├── .gitignore ├── time ├── time.h └── time.c ├── user_space_pages ├── user_space_pages.h └── user_space_pages.c ├── cmdline ├── cmd.h └── cmd.c ├── cpu ├── cpu.h └── cpu.c ├── trace ├── trace.h └── trace.c ├── script ├── build_32.sh └── build.sh ├── shmem ├── shmem.h └── shmem.c ├── lib ├── unaligned.h ├── lzo │ ├── lzo.h │ ├── lzodefs.h │ └── lzo1x_decompress_safe.c ├── be_byteshift.h ├── le_byteshift.h ├── bits.h └── lz4 │ ├── lz4defs.h │ └── lz4.h ├── .github └── workflows │ └── cmake-ubuntu-platform.yml ├── crypto.c ├── zram ├── zram.h ├── zram_drv.c └── zram.c ├── CMakeLists.txt ├── pageowner ├── page_owner.h └── page_owner.c ├── binder ├── binder.h └── binder.c ├── core ├── core_x86_64.c ├── core.h ├── core_arm.c ├── core_x86.c ├── core_arm64.c ├── core32.c ├── core64.c └── core.c ├── README.md └── parser_defs.h /.gitignore: -------------------------------------------------------------------------------- 1 | /output 2 | mybuild.sh 3 | clocline.sh 4 | -------------------------------------------------------------------------------- /time/time.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef TIME_TIME_H_ 4 | #define TIME_TIME_H_ 5 | 6 | #include "parser_defs.h" 7 | #include 8 | 9 | void parser_time_main(void); 10 | void parser_time_usage(void); 11 | 12 | // API 13 | ulong parser_ktime_get(void); 14 | 15 | #endif // TIME_TIME_H_ 16 | -------------------------------------------------------------------------------- /user_space_pages/user_space_pages.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef USER_SPACE_PAGES_H_ 4 | #define USER_SPACE_PAGES_H_ 5 | 6 | #include "parser_defs.h" 7 | #include 8 | 9 | void parser_user_space_pages_main(void); 10 | void parser_user_space_pages_usage(void); 11 | 12 | #endif // USER_SPACE_PAGES_H_ 13 | -------------------------------------------------------------------------------- /cmdline/cmd.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef CMDLINE_CMD_H_ 4 | #define CMDLINE_CMD_H_ 5 | 6 | #include "parser_defs.h" 7 | #include 8 | 9 | void parser_cmdline_main(void); 10 | void parser_cmdline_usage(void); 11 | 12 | void parser_cmdline_form_context(struct task_context* tc); 13 | 14 | #endif // CMDLINE_CMD_H_ 15 | -------------------------------------------------------------------------------- /cpu/cpu.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef CPU_CPU_H_ 4 | #define CPU_CPU_H_ 5 | 6 | #include "parser_defs.h" 7 | #include 8 | 9 | void parser_cpu_main(void); 10 | void parser_cpu_usage(void); 11 | void parser_cpu_set(char* cmm, int idx, int lv); 12 | void parser_cpu_reset(int idx); 13 | void parser_cpu_cache_clean(void); 14 | 15 | #endif // CPU_CPU_H_ 16 | -------------------------------------------------------------------------------- /trace/trace.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef TRACE_TRACE_H_ 4 | #define TRACE_TRACE_H_ 5 | 6 | #include "parser_defs.h" 7 | #include 8 | 9 | #define RB_BUFFER_OFF (1 << 20) 10 | 11 | void parser_trace_main(void); 12 | void parser_trace_usage(void); 13 | void parser_trace_init(void); 14 | 15 | bool parser_tracer_tracing_is_on(ulong tr); 16 | bool parser_ring_buffer_record_is_set_on(ulong buffer); 17 | int parser_tracer_show(ulong tracer); 18 | 19 | #endif // TRACE_TRACE_H_ 20 | -------------------------------------------------------------------------------- /script/build_32.sh: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | export BUILD_TARGET_ABIS="arm x86" 4 | if [ -z $BUILD_TYPE ];then 5 | export BUILD_TYPE="Debug" 6 | fi 7 | 8 | for CURRENT_TARGET_ABI in $BUILD_TARGET_ABIS 9 | do 10 | cmake -DCMAKE_C_COMPILER="/usr/bin/gcc" \ 11 | -DCMAKE_CXX_COMPILER="/usr/bin/g++" \ 12 | -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ 13 | -DCMAKE_BUILD_TARGET_ARCH=$CURRENT_TARGET_ABI \ 14 | CMakeLists.txt \ 15 | -B output/$CURRENT_TARGET_ABI 16 | 17 | make -C output/$CURRENT_TARGET_ABI -j8 18 | done 19 | -------------------------------------------------------------------------------- /script/build.sh: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | export BUILD_TARGET_ABIS="arm64 x86_64" 4 | if [ -z $BUILD_TYPE ];then 5 | export BUILD_TYPE="Debug" 6 | fi 7 | 8 | for CURRENT_TARGET_ABI in $BUILD_TARGET_ABIS 9 | do 10 | cmake -DCMAKE_C_COMPILER="/usr/bin/gcc" \ 11 | -DCMAKE_CXX_COMPILER="/usr/bin/g++" \ 12 | -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ 13 | -DCMAKE_BUILD_TARGET_ARCH=$CURRENT_TARGET_ABI \ 14 | CMakeLists.txt \ 15 | -B output/$CURRENT_TARGET_ABI 16 | 17 | make -C output/$CURRENT_TARGET_ABI -j8 18 | done 19 | -------------------------------------------------------------------------------- /shmem/shmem.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef SHMEM_SHMEM_H_ 4 | #define SHMEM_SHMEM_H_ 5 | 6 | #include "parser_defs.h" 7 | #include 8 | 9 | void parser_shmem_main(void); 10 | void parser_shmem_usage(void); 11 | 12 | int parser_shmem_read_page(ulong vaddr, struct vma_cache_data* cache, 13 | unsigned char* value, ulong error_handle); 14 | 15 | int parser_shmem_get_page_cache(struct vma_cache_data* cache, 16 | struct list_pair **page_list, ulong error_handle); 17 | int parser_shmem_read_page_cache(ulong vaddr, struct vma_cache_data* cache, int count, 18 | struct list_pair *page_list, unsigned char* value, ulong error_handle); 19 | 20 | struct shmem_data_t { 21 | struct task_context *tc; 22 | int pid; 23 | int vma_count; 24 | struct vma_cache_data *vma_cache; 25 | }; 26 | 27 | #endif // SHMEM_SHMEM_H_ 28 | -------------------------------------------------------------------------------- /lib/unaligned.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef LIB_UNALIGNED_H_ 4 | #define LIB_UNALIGNED_H_ 5 | 6 | #include "le_byteshift.h" 7 | #include "be_byteshift.h" 8 | 9 | #if defined(__LITTLE_ENDIAN) 10 | #define get_unaligned_8 get_unaligned_le8 11 | #define put_unaligned_8 put_unaligned_le8 12 | #define get_unaligned_16 get_unaligned_le16 13 | #define put_unaligned_16 put_unaligned_le16 14 | #define get_unaligned_32 get_unaligned_le32 15 | #define put_unaligned_32 put_unaligned_le32 16 | #define get_unaligned_64 get_unaligned_le64 17 | #define put_unaligned_64 put_unaligned_le64 18 | #else 19 | #define get_unaligned_8 get_unaligned_be8 20 | #define put_unaligned_8 put_unaligned_be8 21 | #define get_unaligned_16 get_unaligned_be16 22 | #define put_unaligned_16 put_unaligned_be16 23 | #define get_unaligned_32 get_unaligned_be32 24 | #define put_unaligned_32 put_unaligned_be32 25 | #define get_unaligned_64 get_unaligned_be64 26 | #define put_unaligned_64 put_unaligned_be64 27 | #endif 28 | 29 | #endif // LIB_UNALIGNED_H_ 30 | -------------------------------------------------------------------------------- /.github/workflows/cmake-ubuntu-platform.yml: -------------------------------------------------------------------------------- 1 | # This starter workflow is for a CMake project running on a single platform. There is a different starter workflow if you need cross-platform coverage. 2 | # See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml 3 | name: CMake on ubuntu platforms 4 | 5 | on: 6 | push: 7 | branches: [ "main" ] 8 | pull_request: 9 | branches: [ "main" ] 10 | 11 | env: 12 | BUILD_TYPE: Debug 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-22.04 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Build 22 | run: | 23 | bash ./script/build.sh 24 | sudo apt-get install -y libc6-dev-i386 25 | bash ./script/build_32.sh 26 | tar -czvf linux-parser_1.0.6.tar.gz output/arm64/linux-parser.so \ 27 | output/x86_64/linux-parser.so \ 28 | output/arm/linux-parser.so \ 29 | output/x86/linux-parser.so 30 | 31 | - name: Upload a Build Artifact 32 | uses: actions/upload-artifact@v4 33 | with: 34 | name: linux-parser_1.0.6.tar.gz 35 | path: linux-parser_1.0.6.tar.gz 36 | -------------------------------------------------------------------------------- /crypto.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "parser_defs.h" 4 | #include "lzo/lzo.h" 5 | #include "lz4/lz4.h" 6 | #include 7 | #include 8 | 9 | int crypto_lzo1x_decompress_safe(unsigned char *source, unsigned char *dest, 10 | int compressedSize, int maxDecompressedSize) { 11 | int err; 12 | size_t tmp_len = maxDecompressedSize; 13 | err = lzo1x_decompress_safe(source, compressedSize, dest, &tmp_len); 14 | if (err != 0) { 15 | tmp_len = 0; 16 | if (CRASHDEBUG(1)) 17 | error(WARNING, "lzo1x_decompress_safe error(%d)\n", err); 18 | } 19 | return tmp_len; 20 | } 21 | 22 | int crypto_LZ4_decompress_safe(unsigned char *source, unsigned char *dest, 23 | int compressedSize, int maxDecompressedSize) { 24 | return LZ4_decompress_safe((const char *)source, (char *)dest, compressedSize, maxDecompressedSize); 25 | } 26 | 27 | void *crypto_comp_get_decompress(const char* name) { 28 | if (STREQ(name, "lz4")) { 29 | return &crypto_LZ4_decompress_safe; 30 | } else if (STREQ(name, "lzo") || STREQ(name, "lzo-rle")) { 31 | return &crypto_lzo1x_decompress_safe; 32 | } else { 33 | fprintf(fp, "Not support %s decompress\n", name); 34 | } 35 | return NULL; 36 | } 37 | -------------------------------------------------------------------------------- /time/time.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "time.h" 4 | 5 | static ulong tk_core_cache = 0x0; 6 | static ulong get_tk_core(void) { 7 | if (!tk_core_cache) 8 | tk_core_cache = symbol_value("tk_core"); 9 | return tk_core_cache; 10 | } 11 | 12 | void parser_time_main(void) { 13 | float current_time = parser_ktime_get() * 1.0F / 1000000 / 1000; 14 | fprintf(fp, "Current time: [%.6f]\n", current_time); 15 | } 16 | 17 | ulong parser_ktime_get(void) { 18 | ulong base; 19 | ulong nescs; 20 | uint shift; 21 | ulong timekeeper; 22 | ulong tkr_mono; 23 | 24 | ulong tk_core = get_tk_core(); 25 | timekeeper = tk_core + /*PARSER_OFFSET(tk_core_timekeeper)*/ 8; 26 | tkr_mono = timekeeper + PARSER_OFFSET(timekeeper_tkr_mono); 27 | 28 | readmem(tkr_mono + PARSER_OFFSET(tk_read_base_base), KVADDR, &base, 29 | PARSER_SIZE(tk_read_base_base), "tk_read_base_base", FAULT_ON_ERROR); 30 | readmem(tkr_mono + PARSER_OFFSET(tk_read_base_shift), KVADDR, &shift, 31 | PARSER_SIZE(tk_read_base_shift), "tk_read_base_shift", FAULT_ON_ERROR); 32 | readmem(tkr_mono + PARSER_OFFSET(tk_read_base_xtime_nsec), KVADDR, &nescs, 33 | PARSER_SIZE(tk_read_base_xtime_nsec), "tk_read_base_xtime_nsec", FAULT_ON_ERROR); 34 | 35 | return base + (nescs >> shift); 36 | } 37 | 38 | void parser_time_usage(void) {} 39 | -------------------------------------------------------------------------------- /zram/zram.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef ZRAM_ZRAM_H_ 4 | #define ZRAM_ZRAM_H_ 5 | 6 | #include "parser_defs.h" 7 | #include 8 | 9 | void parser_zram_main(void); 10 | void parser_zram_usage(void); 11 | 12 | void parser_zram_init(void); 13 | void parser_zram_data_init(void); 14 | void parser_zram_data_uninit(void); 15 | int parser_zram_read_buf(ulong vaddr, unsigned char* value, ulong error_handle); 16 | int parser_zram_read_page(int swap_index, ulong zram_offset, unsigned char* value, ulong error_handle); 17 | int parser_get_swap_total(); 18 | 19 | struct swap_space_cache_data_t { 20 | int page_count; 21 | struct list_pair* pages; 22 | }; 23 | 24 | struct pagecache_data_t { 25 | ulong space; 26 | int cache_count; 27 | struct swap_space_cache_data_t* cache; 28 | }; 29 | 30 | struct zram_data_t { 31 | ulong zram; 32 | ulong pages; 33 | ulong comp_count; 34 | ulong comp[4]; 35 | ulong mem_pool; 36 | ulong table; 37 | int (*decompress[4])(unsigned char *source, unsigned char *dest, 38 | int compressedSize, int maxDecompressedSize); 39 | }; 40 | 41 | extern struct zram_data_t* zram_data_cache; 42 | extern struct pagecache_data_t* pagecache_data_cache; 43 | extern ulong PARSER_ZRAM_FLAG_SHIFT; 44 | extern ulong PARSER_ZRAM_FLAG_SAME_BIT; 45 | extern ulong PARSER_ZRAM_FLAG_WB_BIT; 46 | extern ulong PARSER_ZRAM_COMP_PRIORITY_BIT1; 47 | extern ulong PARSER_ZRAM_COMP_PRIORITY_MASK; 48 | 49 | #endif // ZRAM_ZRAM_H_ 50 | -------------------------------------------------------------------------------- /lib/lzo/lzo.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef __LZO_H__ 3 | #define __LZO_H__ 4 | 5 | #include 6 | 7 | /* 8 | * LZO Public Kernel Interface 9 | * A mini subset of the LZO real-time data compression library 10 | * 11 | * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer 12 | * 13 | * The full LZO package can be found at: 14 | * http://www.oberhumer.com/opensource/lzo/ 15 | * 16 | * Changed for Linux kernel use by: 17 | * Nitin Gupta 18 | * Richard Purdie 19 | * 20 | * Changed for Linux core analysis use by: 21 | * Guanyou.Chen 22 | */ 23 | 24 | #define LZO1X_1_MEM_COMPRESS (8192 * sizeof(unsigned short)) 25 | #define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS 26 | 27 | #define lzo1x_worst_compress(x) ((x) + ((x) / 16) + 64 + 3 + 2) 28 | 29 | /* safe decompression with overrun testing */ 30 | int lzo1x_decompress_safe(const unsigned char *src, size_t src_len, 31 | unsigned char *dst, size_t *dst_len); 32 | 33 | /* 34 | * Return values (< 0 = Error) 35 | */ 36 | #define LZO_E_OK 0 37 | #define LZO_E_ERROR (-1) 38 | #define LZO_E_OUT_OF_MEMORY (-2) 39 | #define LZO_E_NOT_COMPRESSIBLE (-3) 40 | #define LZO_E_INPUT_OVERRUN (-4) 41 | #define LZO_E_OUTPUT_OVERRUN (-5) 42 | #define LZO_E_LOOKBEHIND_OVERRUN (-6) 43 | #define LZO_E_EOF_NOT_FOUND (-7) 44 | #define LZO_E_INPUT_NOT_CONSUMED (-8) 45 | #define LZO_E_NOT_YET_IMPLEMENTED (-9) 46 | #define LZO_E_INVALID_ARGUMENT (-10) 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /lib/be_byteshift.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _TOOLS_BE_BYTESHIFT_H 3 | #define _TOOLS_BE_BYTESHIFT_H 4 | 5 | #include 6 | 7 | static inline uint16_t __get_unaligned_be16(const uint8_t *p) 8 | { 9 | return p[0] << 8 | p[1]; 10 | } 11 | 12 | static inline uint32_t __get_unaligned_be32(const uint8_t *p) 13 | { 14 | return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; 15 | } 16 | 17 | static inline uint64_t __get_unaligned_be64(const uint8_t *p) 18 | { 19 | return (uint64_t)__get_unaligned_be32(p) << 32 | 20 | __get_unaligned_be32(p + 4); 21 | } 22 | 23 | static inline void __put_unaligned_be16(uint16_t val, uint8_t *p) 24 | { 25 | *p++ = val >> 8; 26 | *p++ = val; 27 | } 28 | 29 | static inline void __put_unaligned_be32(uint32_t val, uint8_t *p) 30 | { 31 | __put_unaligned_be16(val >> 16, p); 32 | __put_unaligned_be16(val, p + 2); 33 | } 34 | 35 | static inline void __put_unaligned_be64(uint64_t val, uint8_t *p) 36 | { 37 | __put_unaligned_be32(val >> 32, p); 38 | __put_unaligned_be32(val, p + 4); 39 | } 40 | 41 | static inline uint16_t get_unaligned_be16(const void *p) 42 | { 43 | return __get_unaligned_be16((const uint8_t *)p); 44 | } 45 | 46 | static inline uint32_t get_unaligned_be32(const void *p) 47 | { 48 | return __get_unaligned_be32((const uint8_t *)p); 49 | } 50 | 51 | static inline uint64_t get_unaligned_be64(const void *p) 52 | { 53 | return __get_unaligned_be64((const uint8_t *)p); 54 | } 55 | 56 | static inline void put_unaligned_be16(uint16_t val, void *p) 57 | { 58 | __put_unaligned_be16(val, p); 59 | } 60 | 61 | static inline void put_unaligned_be32(uint32_t val, void *p) 62 | { 63 | __put_unaligned_be32(val, p); 64 | } 65 | 66 | static inline void put_unaligned_be64(uint64_t val, void *p) 67 | { 68 | __put_unaligned_be64(val, p); 69 | } 70 | 71 | #endif /* _TOOLS_BE_BYTESHIFT_H */ 72 | -------------------------------------------------------------------------------- /lib/le_byteshift.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef _TOOLS_LE_BYTESHIFT_H 3 | #define _TOOLS_LE_BYTESHIFT_H 4 | 5 | #include 6 | 7 | static inline uint16_t __get_unaligned_le16(const uint8_t *p) 8 | { 9 | return p[0] | p[1] << 8; 10 | } 11 | 12 | static inline uint32_t __get_unaligned_le32(const uint8_t *p) 13 | { 14 | return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; 15 | } 16 | 17 | static inline uint64_t __get_unaligned_le64(const uint8_t *p) 18 | { 19 | return (uint64_t)__get_unaligned_le32(p + 4) << 32 | 20 | __get_unaligned_le32(p); 21 | } 22 | 23 | static inline void __put_unaligned_le16(uint16_t val, uint8_t *p) 24 | { 25 | *p++ = val; 26 | *p++ = val >> 8; 27 | } 28 | 29 | static inline void __put_unaligned_le32(uint32_t val, uint8_t *p) 30 | { 31 | __put_unaligned_le16(val >> 16, p + 2); 32 | __put_unaligned_le16(val, p); 33 | } 34 | 35 | static inline void __put_unaligned_le64(uint64_t val, uint8_t *p) 36 | { 37 | __put_unaligned_le32(val >> 32, p + 4); 38 | __put_unaligned_le32(val, p); 39 | } 40 | 41 | static inline uint16_t get_unaligned_le16(const void *p) 42 | { 43 | return __get_unaligned_le16((const uint8_t *)p); 44 | } 45 | 46 | static inline uint32_t get_unaligned_le32(const void *p) 47 | { 48 | return __get_unaligned_le32((const uint8_t *)p); 49 | } 50 | 51 | static inline uint64_t get_unaligned_le64(const void *p) 52 | { 53 | return __get_unaligned_le64((const uint8_t *)p); 54 | } 55 | 56 | static inline void put_unaligned_le16(uint16_t val, void *p) 57 | { 58 | __put_unaligned_le16(val, p); 59 | } 60 | 61 | static inline void put_unaligned_le32(uint32_t val, void *p) 62 | { 63 | __put_unaligned_le32(val, p); 64 | } 65 | 66 | static inline void put_unaligned_le64(uint64_t val, void *p) 67 | { 68 | __put_unaligned_le64(val, p); 69 | } 70 | 71 | #endif /* _TOOLS_LE_BYTESHIFT_H */ 72 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | cmake_minimum_required(VERSION 3.21.1) 4 | project(OpenLinuxAnalysisKit) 5 | 6 | string(TOUPPER "${CMAKE_BUILD_TARGET_ARCH}" BUILD_TARGET_ARCH) 7 | add_definitions(-D${BUILD_TARGET_ARCH}) 8 | add_definitions(-D__LITTLE_ENDIAN) 9 | 10 | set(LINUX_PARSER_SOURCES 11 | parser.c 12 | core/core.c 13 | zram/zram.c 14 | zram/zram_drv.c 15 | crypto.c 16 | lib/lzo/lzo1x_decompress_safe.c 17 | lib/lz4/lz4_decompress.c 18 | shmem/shmem.c 19 | binder/binder.c 20 | pageowner/page_owner.c 21 | trace/trace.c 22 | cpu/cpu.c 23 | time/time.c 24 | cmdline/cmd.c 25 | user_space_pages/user_space_pages.c) 26 | 27 | if (CMAKE_BUILD_TARGET_ARCH STREQUAL "arm64") 28 | add_definitions(-D__LP64__) 29 | list(APPEND LINUX_PARSER_SOURCES 30 | core/core64.c 31 | core/core32.c 32 | core/core_arm64.c 33 | core/core_arm.c) 34 | elseif(CMAKE_BUILD_TARGET_ARCH STREQUAL "arm") 35 | add_definitions(-D__LP32__) 36 | set(MACHINE_CFLAGS "-m32") 37 | list(APPEND LINUX_PARSER_SOURCES 38 | core/core32.c 39 | core/core_arm.c) 40 | elseif(CMAKE_BUILD_TARGET_ARCH STREQUAL "x86_64") 41 | add_definitions(-D__LP64__) 42 | list(APPEND LINUX_PARSER_SOURCES 43 | core/core64.c 44 | core/core32.c 45 | core/core_x86_64.c 46 | core/core_x86.c) 47 | elseif(CMAKE_BUILD_TARGET_ARCH STREQUAL "x86") 48 | add_definitions(-D__LP32__) 49 | set(MACHINE_CFLAGS "-m32") 50 | list(APPEND LINUX_PARSER_SOURCES 51 | core/core32.c 52 | core/core_x86.c) 53 | endif() 54 | 55 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MACHINE_CFLAGS} -rdynamic -Wall") 56 | 57 | include_directories(.) 58 | include_directories(lib) 59 | 60 | add_library(linux-parser SHARED ${LINUX_PARSER_SOURCES}) 61 | set_target_properties(linux-parser PROPERTIES PREFIX "") 62 | -------------------------------------------------------------------------------- /lib/lzo/lzodefs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * lzodefs.h -- architecture, OS and compiler specific defines 4 | * 5 | * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer 6 | * 7 | * The full LZO package can be found at: 8 | * http://www.oberhumer.com/opensource/lzo/ 9 | * 10 | * Changed for Linux kernel use by: 11 | * Nitin Gupta 12 | * Richard Purdie 13 | * 14 | * Changed for Linux core analysis use by: 15 | * Guanyou.Chen 16 | */ 17 | 18 | /* Version 19 | * 0: original lzo version 20 | * 1: lzo with support for RLE 21 | */ 22 | 23 | #include "unaligned.h" 24 | 25 | #define LZO_VERSION 1 26 | #define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 27 | 28 | #define COPY4(dst, src) \ 29 | put_unaligned_32(get_unaligned_32((const uint32_t *)(src)), (uint32_t *)(dst)) 30 | #if defined(X86_64) || defined(ARM64) 31 | #define COPY8(dst, src) \ 32 | put_unaligned_64(get_unaligned_64((const uint64_t *)(src)), (uint64_t *)(dst)) 33 | #else 34 | #define COPY8(dst, src) \ 35 | COPY4(dst, src); COPY4((dst) + 4, (src) + 4) 36 | #endif 37 | 38 | #if defined(X86_64) || defined(ARM64) 39 | #define LZO_USE_CTZ64 1 40 | #define LZO_USE_CTZ32 1 41 | #define LZO_FAST_64BIT_MEMORY_ACCESS 42 | #elif defined(X86) || defined(PPC) 43 | #define LZO_USE_CTZ32 1 44 | #elif defined(ARM) && (__LINUX_ARM_ARCH__ >= 5) 45 | #define LZO_USE_CTZ32 1 46 | #endif 47 | 48 | #define M1_MAX_OFFSET 0x0400 49 | #define M2_MAX_OFFSET 0x0800 50 | #define M3_MAX_OFFSET 0x4000 51 | #define M4_MAX_OFFSET_V0 0xbfff 52 | #define M4_MAX_OFFSET_V1 0xbffe 53 | 54 | #define M1_MIN_LEN 2 55 | #define M1_MAX_LEN 2 56 | #define M2_MIN_LEN 3 57 | #define M2_MAX_LEN 8 58 | #define M3_MIN_LEN 3 59 | #define M3_MAX_LEN 33 60 | #define M4_MIN_LEN 3 61 | #define M4_MAX_LEN 9 62 | 63 | #define M1_MARKER 0 64 | #define M2_MARKER 64 65 | #define M3_MARKER 32 66 | #define M4_MARKER 16 67 | 68 | #define MIN_ZERO_RUN_LENGTH 4 69 | #define MAX_ZERO_RUN_LENGTH (2047 + MIN_ZERO_RUN_LENGTH) 70 | 71 | #define lzo_dict_t unsigned short 72 | #define D_BITS 13 73 | #define D_SIZE (1u << D_BITS) 74 | #define D_MASK (D_SIZE - 1) 75 | #define D_HIGH ((D_MASK >> 1) + 1) 76 | -------------------------------------------------------------------------------- /pageowner/page_owner.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef PAGEOWNER_PAGE_OWNER_H_ 4 | #define PAGEOWNER_PAGE_OWNER_H_ 5 | 6 | #include "parser_defs.h" 7 | #include 8 | 9 | #define PAGE_EXT_INVALID (0x1) 10 | 11 | void parser_page_owner_main(void); 12 | void parser_page_owner_usage(void); 13 | 14 | struct pageowner_data_t { 15 | int pid; 16 | ulong page; 17 | int dumptop; 18 | ulong *top; 19 | ulong top_size; 20 | 21 | ulong max_pfn; 22 | ulong min_low_pfn; 23 | ulong stack_slabs; 24 | ulong page_owner_ops_offset; 25 | ulong mem_section; 26 | ulong page_ext_size; 27 | int depot_index; 28 | 29 | long PAGE_EXT_OWNER; 30 | long PAGE_EXT_OWNER_ALLOCATED; 31 | 32 | int CONFIG_PAGE_EXTENSION; 33 | int CONFIG_SPARSEMEM_EXTREME; 34 | int CONFIG_SPARSEMEM; 35 | }; 36 | 37 | int parser_page_owner_data_init(struct pageowner_data_t* pageowner_data); 38 | void parser_page_owner_dump(struct pageowner_data_t* pageowner_data); 39 | 40 | ulong parser_page_ext_get(struct pageowner_data_t* pageowner_data, ulong page, ulong pfn); 41 | ulong parser_lookup_page_ext(struct pageowner_data_t* pageowner_data, ulong page, ulong pfn); 42 | 43 | ulong parser_pfn_to_section(struct pageowner_data_t* pageowner_data, ulong pfn); 44 | ulong parser_nr_to_section(struct pageowner_data_t* pageowner_data, ulong nr); 45 | ulong parser_get_page_owner(struct pageowner_data_t* pageowner_data, ulong page_ext); 46 | ulong parser_page_owner_get_entry(struct pageowner_data_t* pageowner_data, ulong base, ulong index); 47 | bool parser_page_ext_invalid(ulong page_ext); 48 | void parser_print_page_owner(struct pageowner_data_t* pageowner_data, ulong pfn, ulong page, ulong page_owner, int handle); 49 | 50 | void parser_stack_depot_print(struct pageowner_data_t* pageowner_data, int stack); 51 | void parser_stack_trace_print(unsigned long entries, unsigned int nr_entries, int spaces); 52 | unsigned int parser_stack_depot_fetch(struct pageowner_data_t* pageowner_data, int handle, unsigned long *entries); 53 | 54 | #define STACK_ALLOC_ALIGN 4 55 | union handle_parts { 56 | unsigned int handle; 57 | struct { 58 | unsigned int slabindex : 21; 59 | unsigned int offset : 10; 60 | unsigned int valid : 1; 61 | } v0; 62 | struct { 63 | unsigned int slabindex : 16; 64 | unsigned int offset : 10; 65 | unsigned int valid : 1; 66 | unsigned int extra : 5; 67 | } v6_1; 68 | }; 69 | 70 | #endif // PAGEOWNER_PAGE_OWNER_H_ 71 | -------------------------------------------------------------------------------- /trace/trace.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "trace.h" 4 | #include 5 | #include 6 | #include 7 | 8 | bool parser_ring_buffer_record_is_set_on(ulong buffer) { 9 | int record_disabled; 10 | 11 | readmem(buffer + PARSER_OFFSET(trace_buffer_record_disabled), KVADDR, &record_disabled, 12 | PARSER_SIZE(trace_buffer_record_disabled), "trace_buffer_record_disabled", FAULT_ON_ERROR); 13 | 14 | return !(record_disabled & RB_BUFFER_OFF); 15 | } 16 | 17 | bool parser_tracer_tracing_is_on(ulong tr) { 18 | ulong array_buffer_buffer = 0; 19 | int buffer_disabled = 1; 20 | 21 | readmem(tr + PARSER_OFFSET(trace_array_array_buffer) + PARSER_OFFSET(array_buffer_buffer), 22 | KVADDR, &array_buffer_buffer, PARSER_SIZE(array_buffer_buffer), "array_buffer_buffer", FAULT_ON_ERROR); 23 | 24 | if (array_buffer_buffer) 25 | return parser_ring_buffer_record_is_set_on(array_buffer_buffer); 26 | 27 | readmem(tr + PARSER_OFFSET(trace_array_buffer_disabled), KVADDR, &buffer_disabled, 28 | PARSER_SIZE(trace_array_buffer_disabled), "trace_array_buffer_disabled", FAULT_ON_ERROR); 29 | return !buffer_disabled; 30 | } 31 | 32 | int parser_tracer_show(ulong tracer) { 33 | char tracer_name[256]; 34 | ulong tracer_name_ptr; 35 | 36 | memset(tracer_name, 0x0, sizeof(tracer_name)); 37 | readmem(tracer + PARSER_OFFSET(tracer_name), KVADDR, &tracer_name_ptr, 38 | PARSER_SIZE(tracer_name), "tracer_name_ptr", FAULT_ON_ERROR); 39 | readmem(tracer_name_ptr, KVADDR, tracer_name, 40 | sizeof(tracer_name), "tracer_name", FAULT_ON_ERROR); 41 | tracer_name[255] = 0; 42 | 43 | fprintf(fp, "# tracer: %s\n", tracer_name); 44 | return 0; 45 | } 46 | 47 | void parser_trace_main(void) { 48 | parser_trace_init(); 49 | 50 | ulong global_trace; 51 | ulong current_trace; 52 | 53 | if (!symbol_exists("global_trace")) { 54 | error(INFO, "no found symbol global_trace.\n"); 55 | return; 56 | } 57 | global_trace = symbol_value("global_trace"); 58 | readmem(global_trace + PARSER_OFFSET(trace_array_current_trace), KVADDR, ¤t_trace, 59 | PARSER_SIZE(trace_array_current_trace), "trace_array_current_trace", FAULT_ON_ERROR); 60 | 61 | parser_tracer_show(current_trace); 62 | } 63 | 64 | void parser_trace_usage(void) { 65 | fprintf(fp, "Usage: lp trace [OPTION] ...\n"); 66 | } 67 | 68 | void parser_trace_init(void) { 69 | // trace.ko 70 | } 71 | -------------------------------------------------------------------------------- /binder/binder.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef BINDER_BINDER_H_ 4 | #define BINDER_BINDER_H_ 5 | 6 | #include "parser_defs.h" 7 | #include 8 | 9 | void parser_binder_main(void); 10 | void parser_binder_usage(void); 11 | 12 | struct binder_data_t { 13 | struct task_context *tc; 14 | int pid; 15 | int dump_all; 16 | }; 17 | 18 | /** 19 | * struct binder_priority - scheduler policy and priority 20 | * @sched_policy scheduler policy 21 | * @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT 22 | * 23 | * The binder driver supports inheriting the following scheduler policies: 24 | * SCHED_NORMAL 25 | * SCHED_BATCH 26 | * SCHED_FIFO 27 | * SCHED_RR 28 | */ 29 | struct binder_priority { 30 | unsigned int sched_policy; 31 | int prio; 32 | }; 33 | 34 | struct binder_buffer { 35 | struct kernel_list_head entry; /* free and allocated entries by address */ 36 | struct rb_node rb_node; /* free entry by size or allocated entry */ 37 | /* by address */ 38 | unsigned free:1; 39 | unsigned clear_on_free:1; 40 | unsigned allow_user_free:1; 41 | unsigned async_transaction:1; 42 | unsigned oneway_spam_suspect:1; 43 | unsigned debug_id:27; 44 | 45 | struct binder_transaction *transaction; 46 | 47 | struct binder_node *target_node; 48 | size_t data_size; 49 | size_t offsets_size; 50 | size_t extra_buffers_size; 51 | void *user_data; 52 | int pid; 53 | }; 54 | 55 | /** 56 | * struct binder_work - work enqueued on a worklist 57 | * @entry: node enqueued on list 58 | * @type: type of work to be performed 59 | * 60 | * There are separate work lists for proc, thread, and node (async). 61 | */ 62 | struct binder_work { 63 | struct kernel_list_head entry; 64 | enum binder_work_type { 65 | BINDER_WORK_TRANSACTION = 1, 66 | BINDER_WORK_TRANSACTION_COMPLETE, 67 | BINDER_WORK_TRANSACTION_PENDING, 68 | BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT, 69 | BINDER_WORK_RETURN_ERROR, 70 | BINDER_WORK_NODE, 71 | BINDER_WORK_DEAD_BINDER, 72 | BINDER_WORK_DEAD_BINDER_AND_CLEAR, 73 | BINDER_WORK_CLEAR_DEATH_NOTIFICATION, 74 | } type; 75 | }; 76 | 77 | struct binder_error { 78 | struct binder_work work; 79 | unsigned int cmd; 80 | }; 81 | 82 | void parser_binder_proc_show(struct binder_data_t* binder_data); 83 | void parser_binder_print_binder_proc(ulong proc); 84 | void parser_binder_print_binder_thread_ilocked(ulong thread); 85 | void parser_binder_print_binder_transaction_ilocked(ulong proc, const char* prefix, ulong transaction); 86 | void parser_binder_print_binder_work_ilocked(ulong proc, const char* prefix, const char* transaction_prefix, ulong work); 87 | 88 | #endif // BINDER_BINDER_H_ 89 | -------------------------------------------------------------------------------- /lib/bits.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef LIB_BITS_H_ 4 | #define LIB_BITS_H_ 5 | 6 | #define BIT(nr) (1UL << (nr)) 7 | #define BIT_ULL(nr) (1ULL << (nr)) 8 | 9 | #define PARSER_BITS_PER_LONG (sizeof(long) * 8) 10 | #define BIT_WORD(nr) ((nr) / PARSER_BITS_PER_LONG) 11 | #define BIT_MASK(nr) (1UL << ((nr) % PARSER_BITS_PER_LONG)) 12 | 13 | #define GENMASK(h, l) (((1ULL<<(h+1))-1)&(~((1ULL<> (nr & (PARSER_BITS_PER_LONG-1))); 17 | } 18 | 19 | static inline int const_test_bit(unsigned long nr, const volatile unsigned long *addr) { 20 | const unsigned long *p = (const unsigned long *)addr + BIT_WORD(nr); 21 | unsigned long mask = BIT_MASK(nr); 22 | unsigned long val = *p; 23 | return !!(val & mask); 24 | } 25 | 26 | #define bitop(op, nr, addr) \ 27 | ((__builtin_constant_p(nr) && \ 28 | __builtin_constant_p((uintptr_t)(addr) != (uintptr_t)NULL) && \ 29 | (uintptr_t)(addr) != (uintptr_t)NULL && \ 30 | __builtin_constant_p(*(const unsigned long *)(addr))) ? \ 31 | const##op(nr, addr) : op(nr, addr)) 32 | 33 | #define test_bit(nr, addr) bitop(_test_bit, nr, addr) 34 | #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) 35 | 36 | static inline unsigned long __ffs(unsigned long word) 37 | { 38 | int num = 0; 39 | 40 | #if defined(X86_64) || defined(ARM64) 41 | if ((word & 0xffffffff) == 0) { 42 | num += 32; 43 | word >>= 32; 44 | } 45 | #endif 46 | if ((word & 0xffff) == 0) { 47 | num += 16; 48 | word >>= 16; 49 | } 50 | if ((word & 0xff) == 0) { 51 | num += 8; 52 | word >>= 8; 53 | } 54 | if ((word & 0xf) == 0) { 55 | num += 4; 56 | word >>= 4; 57 | } 58 | if ((word & 0x3) == 0) { 59 | num += 2; 60 | word >>= 2; 61 | } 62 | if ((word & 0x1) == 0) 63 | num += 1; 64 | return num; 65 | } 66 | 67 | static inline unsigned long __fls(unsigned long word) 68 | { 69 | int num = PARSER_BITS_PER_LONG - 1; 70 | 71 | #if defined(X86_64) || defined(ARM64) 72 | if (!(word & (~0ul << 32))) { 73 | num -= 32; 74 | word <<= 32; 75 | } 76 | #endif 77 | if (!(word & (~0ul << (PARSER_BITS_PER_LONG-16)))) { 78 | num -= 16; 79 | word <<= 16; 80 | } 81 | if (!(word & (~0ul << (PARSER_BITS_PER_LONG-8)))) { 82 | num -= 8; 83 | word <<= 8; 84 | } 85 | if (!(word & (~0ul << (PARSER_BITS_PER_LONG-4)))) { 86 | num -= 4; 87 | word <<= 4; 88 | } 89 | if (!(word & (~0ul << (PARSER_BITS_PER_LONG-2)))) { 90 | num -= 2; 91 | word <<= 2; 92 | } 93 | if (!(word & (~0ul << (PARSER_BITS_PER_LONG-1)))) 94 | num -= 1; 95 | return num; 96 | } 97 | 98 | #endif // LIB_BITS_H_ 99 | -------------------------------------------------------------------------------- /core/core_x86_64.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "core.h" 4 | 5 | struct pt_regs { 6 | uint64_t r15; 7 | uint64_t r14; 8 | uint64_t r13; 9 | uint64_t r12; 10 | uint64_t rbp; 11 | uint64_t rbx; 12 | uint64_t r11; 13 | uint64_t r10; 14 | uint64_t r9; 15 | uint64_t r8; 16 | uint64_t rax; 17 | uint64_t rcx; 18 | uint64_t rdx; 19 | uint64_t rsi; 20 | uint64_t rdi; 21 | uint64_t orig_rax; 22 | uint64_t rip; 23 | uint32_t cs; 24 | uint32_t __cs; 25 | uint64_t flags; 26 | uint64_t rsp; 27 | uint32_t ss; 28 | uint32_t __ss; 29 | uint64_t fs_base; 30 | uint64_t gs_base; 31 | uint32_t ds; 32 | uint32_t __ds; 33 | uint32_t es; 34 | uint32_t __es; 35 | uint32_t fs; 36 | uint32_t __fs; 37 | uint32_t gs; 38 | uint32_t __gs; 39 | }; 40 | 41 | typedef struct elf64_prstatus { 42 | uint32_t pr_si_signo; 43 | uint32_t pr_si_code; 44 | uint32_t pr_si_errno; 45 | uint16_t pr_cursig; 46 | uint64_t pr_sigpend; 47 | uint64_t pr_sighold; 48 | uint32_t pr_pid; 49 | uint32_t pr_ppid; 50 | uint32_t pr_pgrp; 51 | uint32_t pd_sid; 52 | uint64_t pr_utime[2]; 53 | uint64_t pr_stime[2]; 54 | uint64_t pr_cutime[2]; 55 | uint64_t pr_cstime[2]; 56 | struct pt_regs pr_reg; 57 | uint32_t pr_fpvalid; 58 | } Elf64_prstatus; 59 | 60 | void parser_x86_64_core_prstatus(struct core_data_t* core_data) { 61 | core_data->prstatus_sizeof = sizeof(Elf64_prstatus); 62 | if (!core_data->prnum) return; 63 | 64 | int i, cur; 65 | core_data->prstatus_cache = malloc(core_data->prnum * sizeof(Elf64_prstatus)); 66 | memset(core_data->prstatus_cache, 0, core_data->prnum * sizeof(Elf64_prstatus)); 67 | Elf64_prstatus *prstatus = core_data->prstatus_cache; 68 | 69 | int tgid = task_tgid(core_data->tc->task); 70 | struct task_context *tc = FIRST_CONTEXT(); 71 | for (i = cur = 0; i < RUNNING_TASKS(); i++, tc++) { 72 | if (task_tgid(tc->task) == tgid) { 73 | prstatus[cur].pr_pid = tc->pid; 74 | 75 | readmem(machdep->get_stacktop(tc->task) - PARSER_SIZE(pt_regs), KVADDR, 76 | &prstatus[cur].pr_reg, sizeof(struct pt_regs), "gpr_get: user_pt_regs", 77 | core_data->error_handle); 78 | cur++; 79 | } 80 | } 81 | } 82 | 83 | void parser_write_x86_64_core_prstatus(struct core_data_t* core_data) { 84 | if (!core_data->prnum) return; 85 | 86 | Elf64_Nhdr nhdr; 87 | nhdr.n_namesz = NOTE_CORE_NAME_SZ; 88 | nhdr.n_descsz = core_data->prstatus_sizeof; 89 | nhdr.n_type = NT_PRSTATUS; 90 | 91 | char magic[8]; 92 | memset(magic, 0, sizeof(magic)); 93 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC); 94 | 95 | int index = 0; 96 | while (index < core_data->prnum) { 97 | fwrite(&nhdr, sizeof(Elf64_Nhdr), 1, core_data->fp); 98 | fwrite(magic, sizeof(magic), 1, core_data->fp); 99 | fwrite((char *)core_data->prstatus_cache + nhdr.n_descsz * index, nhdr.n_descsz, 1, core_data->fp); 100 | index++; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /user_space_pages/user_space_pages.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "user_space_pages/user_space_pages.h" 4 | #include 5 | #include 6 | #include 7 | 8 | void parser_user_space_pages_main(void) { 9 | int i, cur; 10 | int flags; 11 | 12 | int total_anon_pages = 0; 13 | int total_file_pages = 0; 14 | struct task_context *tc = FIRST_CONTEXT(); 15 | fprintf(fp, " PID COMM ANON FILE\n"); 16 | 17 | for (i = cur = 0; i < RUNNING_TASKS(); i++, tc++) { 18 | if (tc->pid == task_tgid(tc->task)) { 19 | readmem(tc->task + PARSER_OFFSET(task_struct_flags), KVADDR, 20 | &flags, sizeof(flags), "task_struct flags", FAULT_ON_ERROR); 21 | if (flags & PF_KTHREAD) 22 | continue; 23 | 24 | set_context(tc->task, NO_PID, FALSE); 25 | 26 | struct vma_cache_data *vma_cache = NULL; 27 | int vma_count = 0; 28 | physaddr_t paddr; 29 | uint64_t vaddr; 30 | int idx, i; 31 | int anon_pages = 0; 32 | int file_pages = 0; 33 | 34 | char *file_buf = NULL; 35 | ulong dentry, vfsmnt; 36 | int cur_file_pages = 0; 37 | 38 | vma_count = parser_vma_caches(tc, &vma_cache); 39 | for (idx = 0; idx < vma_count; ++idx) { 40 | cur_file_pages = 0; 41 | int count = (vma_cache[idx].vm_end - vma_cache[idx].vm_start) / PAGESIZE(); 42 | for (i = 0; i < count; ++i) { 43 | vaddr = vma_cache[idx].vm_start + i * PAGESIZE(); 44 | paddr = (physaddr_t)0x0; 45 | int page_exist = uvtop(tc, vaddr, &paddr, 0); 46 | if (page_exist) { 47 | if (vma_cache[idx].vm_file) { 48 | file_pages++; 49 | cur_file_pages++; 50 | } 51 | else 52 | anon_pages++; 53 | } 54 | } 55 | 56 | if (vma_cache[idx].vm_file && cur_file_pages) { 57 | file_buf = fill_file_cache(vma_cache[idx].vm_file); 58 | dentry = ULONG(file_buf + OFFSET(file_f_dentry)); 59 | 60 | if (IS_KVADDR(dentry)) { 61 | if (VALID_MEMBER(file_f_vfsmnt)) { 62 | vfsmnt = ULONG(file_buf + OFFSET(file_f_vfsmnt)); 63 | get_pathname(dentry, vma_cache[idx].buf, BUFSIZE, 1, vfsmnt); 64 | } else 65 | get_pathname(dentry, vma_cache[idx].buf, BUFSIZE, 1, 0); 66 | 67 | fprintf(fp, " %8d %s\n", cur_file_pages, vma_cache[idx].buf); 68 | } 69 | } 70 | 71 | } 72 | 73 | if (vma_cache) free(vma_cache); 74 | cur++; 75 | 76 | fprintf(fp, "%7ld %18s %8d %8d\n", tc->pid, tc->comm, anon_pages, file_pages); 77 | total_anon_pages += anon_pages; 78 | total_file_pages += file_pages; 79 | } 80 | } 81 | 82 | fprintf(fp, "total_pages %d, (%d, %d)\n", total_anon_pages + total_file_pages, total_anon_pages, total_file_pages); 83 | } 84 | 85 | void parser_user_space_pages_usage(void) { 86 | fprintf(fp, "Usage: lp user_space_pages [OPTION] ...\n"); 87 | } 88 | -------------------------------------------------------------------------------- /core/core.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef CORE_CORE_H_ 4 | #define CORE_CORE_H_ 5 | 6 | #include "parser_defs.h" 7 | #include 8 | #include 9 | 10 | void parser_core_main(void); 11 | void parser_core_usage(void); 12 | 13 | #define FILTER_SPECIAL_VMA (1 << 0) 14 | #define FILTER_FILE_VMA (1 << 1) 15 | #define FILTER_SHARED_VMA (1 << 2) 16 | #define FILTER_SANITIZER_SHADOW_VMA (1 << 3) 17 | #define FILTER_NON_READ_VMA (1 << 4) 18 | #define FILTER_SIGNAL_CONTEXT (1 << 5) // unused 19 | #define FILTER_MINIDUMP (1 << 6) // unused 20 | 21 | struct core_data_t { 22 | // env 23 | struct task_context *tc; 24 | int pid; 25 | char* file; 26 | int filter_flags; 27 | char parse_zram; 28 | char parse_shmem; 29 | ulong error_handle; 30 | 31 | ulong mm_start_stack; 32 | ulong mm_start_brk; 33 | ulong mm_brk; 34 | 35 | // core 36 | int class; 37 | int machine; 38 | char compat; /* 32-bit address space on 64 bits */ 39 | 40 | FILE* fp; 41 | int phnum; 42 | int prnum; 43 | int auxvnum; 44 | int fileslen; 45 | int vma_count; 46 | struct vma_cache_data *vma_cache; 47 | void* load_cache; 48 | void* prstatus_cache; 49 | int prstatus_sizeof; 50 | void* auxv_cache; 51 | int extra_note_filesz; 52 | unsigned char* zero_buf; 53 | unsigned char* page_buf; 54 | int align_size; 55 | int page_size; 56 | 57 | void (*parser_core_dump)(struct core_data_t* core_data); 58 | void (*parser_core_prstatus)(struct core_data_t* core_data); 59 | void (*parser_write_core_prstatus)(struct core_data_t* core_data); 60 | void (*clean)(struct core_data_t* core_data); 61 | void (*fill_vma_name)(struct core_data_t* core_data); 62 | int (*filter_vma)(struct core_data_t* core_data, int index); 63 | }; 64 | 65 | void parser_core_clean(struct core_data_t* core_data); 66 | void parser_core_fill_vma_name(struct core_data_t* core_data); 67 | int parser_core_filter_vma(struct core_data_t* core_data, int index); 68 | 69 | #if defined(__LP64__) 70 | void parser_core_dump64(struct core_data_t* core_data); 71 | void parser_core_dump32(struct core_data_t* core_data); 72 | #else 73 | void parser_core_dump32(struct core_data_t* core_data); 74 | #endif 75 | 76 | #if defined(ARM64) 77 | void parser_arm64_core_prstatus(struct core_data_t* core_data); 78 | void parser_write_arm64_core_prstatus(struct core_data_t* core_data); 79 | void parser_arm_core_prstatus(struct core_data_t* core_data); 80 | void parser_write_arm_core_prstatus(struct core_data_t* core_data); 81 | #elif defined(ARM) 82 | void parser_arm_core_prstatus(struct core_data_t* core_data); 83 | void parser_write_arm_core_prstatus(struct core_data_t* core_data); 84 | #endif 85 | 86 | #if defined(X86_64) 87 | void parser_x86_64_core_prstatus(struct core_data_t* core_data); 88 | void parser_write_x86_64_core_prstatus(struct core_data_t* core_data); 89 | void parser_x86_core_prstatus(struct core_data_t* core_data); 90 | void parser_write_x86_core_prstatus(struct core_data_t* core_data); 91 | #elif defined(X86) 92 | void parser_x86_core_prstatus(struct core_data_t* core_data); 93 | void parser_write_x86_core_prstatus(struct core_data_t* core_data); 94 | #endif 95 | 96 | typedef struct elf64_auxv { 97 | uint64_t a_type; 98 | uint64_t a_val; 99 | } Elf64_auxv; 100 | 101 | typedef struct elf32_auxv { 102 | uint64_t a_type; 103 | uint64_t a_val; 104 | } Elf32_auxv; 105 | 106 | typedef struct elf64_ntfile{ 107 | uint64_t start; 108 | uint64_t end; 109 | uint64_t fileofs; 110 | } Elf64_ntfile; 111 | 112 | typedef struct elf32_ntfile{ 113 | uint32_t start; 114 | uint32_t end; 115 | uint32_t fileofs; 116 | } Elf32_ntfile; 117 | 118 | #define ELFCOREMAGIC "CORE" 119 | #define NOTE_CORE_NAME_SZ 5 120 | #define ELFLINUXMAGIC "LINUX" 121 | #define NOTE_LINUX_NAME_SZ 6 122 | 123 | #ifndef NT_ARM_PAC_MASK 124 | #define NT_ARM_PAC_MASK 0x406 125 | #endif 126 | #ifndef NT_ARM_TAGGED_ADDR_CTRL 127 | #define NT_ARM_TAGGED_ADDR_CTRL 0x409 128 | #endif 129 | #ifndef NT_ARM_PAC_ENABLED_KEYS 130 | #define NT_ARM_PAC_ENABLED_KEYS 0x40A 131 | #endif 132 | 133 | #endif // CORE_CORE_H_ 134 | -------------------------------------------------------------------------------- /core/core_arm.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "core.h" 4 | 5 | struct parser_arm64_pt_regs { 6 | uint64_t regs[31]; 7 | uint64_t sp; 8 | uint64_t pc; 9 | uint64_t pstate; 10 | }; 11 | 12 | struct pt_regs { 13 | uint32_t regs[13]; 14 | uint32_t sp; 15 | uint32_t lr; 16 | uint32_t pc; 17 | uint32_t cpsr; 18 | }; 19 | 20 | typedef struct elf32_prstatus { 21 | uint32_t pr_si_signo; 22 | uint32_t pr_si_code; 23 | uint32_t pr_si_errno; 24 | uint16_t pr_cursig; 25 | uint16_t __padding1; 26 | uint32_t pr_sigpend; 27 | uint32_t pr_sighold; 28 | uint32_t pr_pid; 29 | uint32_t pr_ppid; 30 | uint32_t pr_pgrp; 31 | uint32_t pd_sid; 32 | uint64_t pr_utime; 33 | uint64_t pr_stime; 34 | uint64_t pr_cutime; 35 | uint64_t pr_cstime; 36 | struct pt_regs pr_reg; 37 | uint32_t pr_fpvalid; 38 | uint32_t __padding2; 39 | } __attribute__((packed, aligned(1))) Elf32_prstatus; 40 | 41 | void parser_arm_core_prstatus(struct core_data_t* core_data) { 42 | core_data->prstatus_sizeof = sizeof(Elf32_prstatus); 43 | if (!core_data->prnum) return; 44 | 45 | int i, cur; 46 | struct parser_arm64_pt_regs regs; 47 | core_data->prstatus_cache = malloc(core_data->prnum * sizeof(Elf32_prstatus)); 48 | memset(core_data->prstatus_cache, 0, core_data->prnum * sizeof(Elf32_prstatus)); 49 | Elf32_prstatus *prstatus = core_data->prstatus_cache; 50 | 51 | int tgid = task_tgid(core_data->tc->task); 52 | struct task_context *tc = FIRST_CONTEXT(); 53 | for (i = cur = 0; i < RUNNING_TASKS(); i++, tc++) { 54 | if (task_tgid(tc->task) == tgid) { 55 | prstatus[cur].pr_pid = tc->pid; 56 | 57 | if (!core_data->compat) { 58 | readmem(machdep->get_stacktop(tc->task) - align_up(PARSER_SIZE(pt_regs), 0x10), KVADDR, 59 | &prstatus[cur].pr_reg, sizeof(struct pt_regs), "gpr_get: user_pt_regs", 60 | core_data->error_handle); 61 | } else { 62 | memset(®s, 0x0, sizeof(struct parser_arm64_pt_regs)); 63 | readmem(machdep->get_stacktop(tc->task) - PARSER_SIZE(pt_regs), KVADDR, 64 | ®s, sizeof(struct parser_arm64_pt_regs), "gpr_get: user_pt_regs", 65 | core_data->error_handle); 66 | 67 | prstatus[cur].pr_reg.regs[0] = regs.regs[0]; 68 | prstatus[cur].pr_reg.regs[1] = regs.regs[1]; 69 | prstatus[cur].pr_reg.regs[2] = regs.regs[2]; 70 | prstatus[cur].pr_reg.regs[3] = regs.regs[3]; 71 | prstatus[cur].pr_reg.regs[4] = regs.regs[4]; 72 | prstatus[cur].pr_reg.regs[5] = regs.regs[5]; 73 | prstatus[cur].pr_reg.regs[6] = regs.regs[6]; 74 | prstatus[cur].pr_reg.regs[7] = regs.regs[7]; 75 | prstatus[cur].pr_reg.regs[8] = regs.regs[8]; 76 | prstatus[cur].pr_reg.regs[9] = regs.regs[9]; 77 | prstatus[cur].pr_reg.regs[10] = regs.regs[10]; 78 | prstatus[cur].pr_reg.regs[11] = regs.regs[11]; 79 | prstatus[cur].pr_reg.regs[12] = regs.regs[12]; 80 | prstatus[cur].pr_reg.sp = regs.regs[13]; 81 | prstatus[cur].pr_reg.lr = regs.regs[14]; 82 | prstatus[cur].pr_reg.pc = regs.pc; 83 | prstatus[cur].pr_reg.cpsr = regs.pstate; 84 | } 85 | cur++; 86 | } 87 | } 88 | } 89 | 90 | void parser_write_arm_core_prstatus(struct core_data_t* core_data) { 91 | if (!core_data->prnum) return; 92 | 93 | Elf32_Nhdr nhdr; 94 | nhdr.n_namesz = NOTE_CORE_NAME_SZ; 95 | nhdr.n_descsz = core_data->prstatus_sizeof; 96 | nhdr.n_type = NT_PRSTATUS; 97 | 98 | char magic[8]; 99 | memset(magic, 0, sizeof(magic)); 100 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC); 101 | 102 | int index = 0; 103 | while (index < core_data->prnum) { 104 | fwrite(&nhdr, sizeof(Elf32_Nhdr), 1, core_data->fp); 105 | fwrite(magic, sizeof(magic), 1, core_data->fp); 106 | fwrite((char *)core_data->prstatus_cache + nhdr.n_descsz * index, nhdr.n_descsz, 1, core_data->fp); 107 | index++; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /core/core_x86.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "core.h" 4 | 5 | struct x86_64_pt_regs { 6 | uint64_t r15; 7 | uint64_t r14; 8 | uint64_t r13; 9 | uint64_t r12; 10 | uint64_t rbp; 11 | uint64_t rbx; 12 | uint64_t r11; 13 | uint64_t r10; 14 | uint64_t r9; 15 | uint64_t r8; 16 | uint64_t rax; 17 | uint64_t rcx; 18 | uint64_t rdx; 19 | uint64_t rsi; 20 | uint64_t rdi; 21 | uint64_t orig_rax; 22 | uint64_t rip; 23 | uint32_t cs; 24 | uint32_t __cs; 25 | uint64_t flags; 26 | uint64_t rsp; 27 | uint32_t ss; 28 | uint32_t __ss; 29 | uint64_t fs_base; 30 | uint64_t gs_base; 31 | uint32_t ds; 32 | uint32_t __ds; 33 | uint32_t es; 34 | uint32_t __es; 35 | uint32_t fs; 36 | uint32_t __fs; 37 | uint32_t gs; 38 | uint32_t __gs; 39 | }; 40 | 41 | struct pt_regs { 42 | uint32_t ebx, ecx, edx, esi, edi, ebp, eax; 43 | uint16_t ds, __ds, es, __es; 44 | uint16_t fs, __fs, gs, __gs; 45 | uint32_t orig_eax, eip; 46 | uint16_t cs, __cs; 47 | uint32_t eflags, esp; 48 | uint16_t ss, __ss; 49 | }; 50 | 51 | typedef struct elf32_prstatus { 52 | uint32_t pr_si_signo; 53 | uint32_t pr_si_code; 54 | uint32_t pr_si_errno; 55 | uint16_t pr_cursig; 56 | uint16_t __padding1; 57 | uint32_t pr_sigpend; 58 | uint32_t pr_sighold; 59 | uint32_t pr_pid; 60 | uint32_t pr_ppid; 61 | uint32_t pr_pgrp; 62 | uint32_t pd_sid; 63 | uint64_t pr_utime; 64 | uint64_t pr_stime; 65 | uint64_t pr_cutime; 66 | uint64_t pr_cstime; 67 | struct pt_regs pr_reg; 68 | uint32_t pr_fpvalid; 69 | } Elf32_prstatus; 70 | 71 | void parser_x86_core_prstatus(struct core_data_t* core_data) { 72 | core_data->prstatus_sizeof = sizeof(Elf32_prstatus); 73 | if (!core_data->prnum) return; 74 | 75 | int i, cur; 76 | struct x86_64_pt_regs regs; 77 | core_data->prstatus_cache = malloc(core_data->prnum * sizeof(Elf32_prstatus)); 78 | memset(core_data->prstatus_cache, 0, core_data->prnum * sizeof(Elf32_prstatus)); 79 | Elf32_prstatus *prstatus = core_data->prstatus_cache; 80 | 81 | int tgid = task_tgid(core_data->tc->task); 82 | struct task_context *tc = FIRST_CONTEXT(); 83 | for (i = cur = 0; i < RUNNING_TASKS(); i++, tc++) { 84 | if (task_tgid(tc->task) == tgid) { 85 | prstatus[cur].pr_pid = tc->pid; 86 | 87 | if (!core_data->compat) { 88 | readmem(machdep->get_stacktop(tc->task) - PARSER_SIZE(pt_regs), KVADDR, 89 | &prstatus[cur].pr_reg, sizeof(struct pt_regs), "gpr_get: user_pt_regs", 90 | core_data->error_handle); 91 | } else { 92 | memset(®s, 0x0, sizeof(struct x86_64_pt_regs)); 93 | readmem(machdep->get_stacktop(tc->task) - PARSER_SIZE(pt_regs), KVADDR, 94 | ®s, sizeof(struct x86_64_pt_regs), "gpr_get: user_pt_regs", 95 | core_data->error_handle); 96 | 97 | prstatus[cur].pr_reg.ebx = regs.rbx; 98 | prstatus[cur].pr_reg.ecx = regs.rcx; 99 | prstatus[cur].pr_reg.edx = regs.rdx; 100 | prstatus[cur].pr_reg.esi = regs.rsi; 101 | prstatus[cur].pr_reg.edi = regs.rdi; 102 | prstatus[cur].pr_reg.ebp = regs.rbp; 103 | prstatus[cur].pr_reg.eax = regs.rax; 104 | prstatus[cur].pr_reg.ds = regs.ds; 105 | prstatus[cur].pr_reg.es = regs.es; 106 | prstatus[cur].pr_reg.fs = regs.fs; 107 | prstatus[cur].pr_reg.gs = regs.gs; 108 | prstatus[cur].pr_reg.orig_eax = regs.orig_rax; 109 | prstatus[cur].pr_reg.eip = regs.rip; 110 | prstatus[cur].pr_reg.cs = regs.cs; 111 | prstatus[cur].pr_reg.eflags = regs.flags; 112 | prstatus[cur].pr_reg.esp = regs.rsp; 113 | prstatus[cur].pr_reg.ss = regs.ss; 114 | } 115 | cur++; 116 | } 117 | } 118 | } 119 | 120 | void parser_write_x86_core_prstatus(struct core_data_t* core_data) { 121 | if (!core_data->prnum) return; 122 | 123 | Elf32_Nhdr nhdr; 124 | nhdr.n_namesz = NOTE_CORE_NAME_SZ; 125 | nhdr.n_descsz = core_data->prstatus_sizeof; 126 | nhdr.n_type = NT_PRSTATUS; 127 | 128 | char magic[8]; 129 | memset(magic, 0, sizeof(magic)); 130 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC); 131 | 132 | int index = 0; 133 | while (index < core_data->prnum) { 134 | fwrite(&nhdr, sizeof(Elf32_Nhdr), 1, core_data->fp); 135 | fwrite(magic, sizeof(magic), 1, core_data->fp); 136 | fwrite((char *)core_data->prstatus_cache + nhdr.n_descsz * index, nhdr.n_descsz, 1, core_data->fp); 137 | index++; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /cmdline/cmd.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "cmdline/cmd.h" 4 | #include "zram/zram.h" 5 | #include 6 | #include 7 | #include 8 | 9 | void parser_cmdline_form_context(struct task_context* tc) { 10 | struct task_mem_usage task_mem_usage, *tm; 11 | ulong arg_start_addr = 0x0; 12 | ulong arg_end_addr = 0x0; 13 | char anon[ANON_BUFSIZE]; 14 | int current_offset = 0; 15 | unsigned char* page_buf; 16 | bool parse_zram = true; 17 | 18 | set_context(tc->task, NO_PID, FALSE); 19 | 20 | tm = &task_mem_usage; 21 | get_task_mem_usage(tc->task, tm); 22 | if (!tm->mm_struct_addr) { 23 | fprintf(fp, "%lx no virtual memory space.\n", tc->task); 24 | return; 25 | } 26 | 27 | readmem(tm->mm_struct_addr + PARSER_OFFSET(mm_struct_arg_start), KVADDR, 28 | &arg_start_addr, PARSER_SIZE(mm_struct_arg_start), "mm_struct_arg_start", FAULT_ON_ERROR); 29 | readmem(tm->mm_struct_addr + PARSER_OFFSET(mm_struct_arg_end), KVADDR, 30 | &arg_end_addr, PARSER_SIZE(mm_struct_arg_end), "mm_struct_arg_end", FAULT_ON_ERROR); 31 | 32 | BZERO(anon, ANON_BUFSIZE); 33 | #if defined(__LP64__) 34 | arg_start_addr &= (USERSPACE_TOP - 1); 35 | arg_end_addr &= (USERSPACE_TOP - 1); 36 | #endif 37 | int count = 2; 38 | uint64_t anon_buf_off = 0; 39 | uint64_t anon_buf_use = ANON_BUFSIZE - 1; 40 | page_buf = (unsigned char *)malloc(PAGESIZE()); 41 | do { 42 | memset(page_buf, 0x0, PAGESIZE()); 43 | physaddr_t paddr = (physaddr_t)0x0; 44 | int page_exist = uvtop(tc, arg_start_addr + anon_buf_off, &paddr, 0); 45 | ulong off = PAGEOFFSET(arg_start_addr + anon_buf_off); 46 | uint64_t read_size = (PAGESIZE() - off > anon_buf_use) ? anon_buf_use : (PAGESIZE() - off); 47 | if (!read_size) 48 | break; 49 | 50 | if (paddr) { 51 | if (page_exist) { 52 | readmem(paddr, PHYSADDR, &anon[anon_buf_off], read_size, "read cmdline name", FAULT_ON_ERROR); 53 | } else if (parse_zram) { 54 | parser_zram_init(); 55 | ulong zram_offset = SWP_OFFSET(paddr); 56 | ulong swap_type = SWP_TYPE(paddr); 57 | parser_zram_read_page(swap_type, zram_offset, page_buf, FAULT_ON_ERROR); 58 | memcpy(&anon[anon_buf_off], page_buf + off, read_size); 59 | } 60 | } 61 | 62 | // next page 63 | if (anon[read_size - 1] != 0x0) { 64 | anon_buf_off += read_size; 65 | anon_buf_use -= read_size; 66 | } else 67 | break; 68 | 69 | count--; 70 | } while(count); 71 | 72 | anon[ANON_BUFSIZE - 1] = '\0'; 73 | free(page_buf); 74 | 75 | fprintf(fp, "PID: %-8ld ", tc->pid); 76 | int length = arg_end_addr - arg_start_addr; 77 | do { 78 | fprintf(fp, "%s ", &anon[current_offset]); 79 | current_offset += strlen(&anon[current_offset]) + 1; 80 | } while (current_offset < length); 81 | fprintf(fp, "\n"); 82 | 83 | } 84 | 85 | void parser_cmdline_main(void) { 86 | struct task_context *tc = NULL; 87 | int pid = CURRENT_PID(); 88 | bool dump_all = false; 89 | ulong parent; 90 | 91 | int opt; 92 | int option_index = 0; 93 | optind = 0; // reset 94 | static struct option long_options[] = { 95 | {"task", required_argument, 0,'t'}, 96 | {"pid", required_argument, 0,'p'}, 97 | {"father", no_argument, 0,'f'}, 98 | {0, 0, 0, 0 }, 99 | }; 100 | 101 | while ((opt = getopt_long(argcnt - 1, &args[1], "t:p:f", 102 | long_options, &option_index)) != -1) { 103 | switch (opt) { 104 | case 'p': 105 | pid = atoi(optarg); 106 | break; 107 | case 't': 108 | tc = task_to_context(htol(optarg, FAULT_ON_ERROR, NULL)); 109 | break; 110 | case 'f': 111 | dump_all = true; 112 | break; 113 | } 114 | } 115 | 116 | if (!tc) { 117 | tc = pid_to_context(pid); 118 | if (!tc) { 119 | fprintf(fp, "No such pid: %d\n", pid); 120 | return; 121 | } 122 | } 123 | 124 | if (!dump_all) 125 | parser_cmdline_form_context(tc); 126 | else { 127 | do { 128 | parser_cmdline_form_context(tc); 129 | readmem(tc->task + OFFSET(task_struct_parent), KVADDR, 130 | &parent, sizeof(void *), "task_struct parent", FAULT_ON_ERROR); 131 | tc = task_to_context(parent); 132 | } while (tc->pid != 0); 133 | } 134 | } 135 | 136 | void parser_cmdline_usage(void) { 137 | fprintf(fp, "Usage: lp cmdline [OPTION] ...\n"); 138 | fprintf(fp, "Option:\n"); 139 | fprintf(fp, " -t, --task print task_struct cmdline\n"); 140 | fprintf(fp, " -p, --pid print pid cmdline\n"); 141 | fprintf(fp, " -f, --father foreach print pid cmdline\n"); 142 | 143 | } 144 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Techincal System 2 | ![core-analysis](https://raw.githubusercontent.com/Penguin38/OpenCoreAnalysisKit/refs/heads/main/doc/OpenCoreAnalyzer.jpg) 3 | 4 | | Project | Path | 5 | |:------------:|---------------------------------------------------| 6 | |core-parser | https://github.com/Penguin38/OpenCoreAnalysisKit | 7 | |linux-parser | https://github.com/Penguin38/OpenLinuxAnalysisKit | 8 | |crash-android | https://github.com/Penguin38/crash-android | 9 | |OpenCoreSDK | https://github.com/Penguin38/OpenCoreSDK | 10 | 11 | # Getting Started 12 | 13 | ``` 14 | $ ./script/build.sh 15 | ``` 16 | 17 | To load the module's commands to a running crash-android 9.0.0 session, enter: 18 | 19 | ``` 20 | crash-android> extend /output/arm64/linux-parser.so 21 | ``` 22 | To show the module's commands, enter: 23 | 24 | ``` 25 | crash-android> extend 26 | SHARED OBJECT COMMANDS 27 | /output/arm64/linux-parser.so lp 28 | ``` 29 | 30 | # Usage 31 | 32 | ``` 33 | crash-android> lp help 34 | core zram shmem binder 35 | meminfo page_owner dmabuf trace 36 | cpu time cmdline user_space_pages 37 | help 38 | 39 | crash-android> lp help core 40 | Usage: lp core [OPTION] 41 | Option: 42 | --zram collect zram page 43 | --shmem collect shared memory on zram page 44 | -f, --filter filter vma flags 45 | -o, --output coredump file path 46 | -p, --pid set collect coredump process pid 47 | Filter Vma: 48 | 0x01: filter-special-vma 49 | 0x02: filter-file-vma 50 | 0x04: filter-shared-vma 51 | 0x08: filter-sanitizer-shadow-vma (default) 52 | 0x10: filter-non-read-vma (default) 53 | Example: 54 | lp core -p 1 --zram --shmem -f 0x18 55 | ``` 56 | 57 | # Example 58 | 59 | ``` 60 | crash-android> mod -s zram zram.ko 61 | crash-android> mod -s zsmalloc zsmalloc.ko 62 | 63 | crash-android> lp core -p 1515 --zram --shmem -f 0x18 64 | Saved [1515.core]. 65 | ``` 66 | 67 | ``` 68 | crash-android> vtop 0x12c00100 69 | VIRTUAL PHYSICAL 70 | 12c00100 (not mapped) 71 | 72 | PAGE DIRECTORY: ffffff8160232000 73 | PGD: ffffff8160232000 => 8000001a0233003 74 | PMD: ffffff81602334b0 => 8000001a0234003 75 | PTE: ffffff8160234000 => 112a1700 76 | 77 | PTE SWAP OFFSET 78 | 112a1700 /first_stage_ramdisk/dev/block/zram0 1124887 79 | 80 | VMA START END FLAGS FILE 81 | ffffff8160c68e80 12c00000 32c00000 100073 82 | 83 | SWAP: /first_stage_ramdisk/dev/block/zram0 OFFSET: 1124887 84 | 85 | crash-android> lp zram -r 0x12c00100 -e 0x12c00200 86 | 12c00100: 0000000000000000 0000000000000000 ................ 87 | 12c00110: 0000000000000000 0000000000000000 ................ 88 | 12c00120: 0000000000000000 00000000705f0f78 ........x._p.... 89 | 12c00130: 0000000000000046 72756f7365722041 F.......A.resour 90 | 12c00140: 656c696166206563 6c6163206f742064 ce.failed.to.cal 91 | 12c00150: 7361656c6572206c 0000000000202e65 l.release....... 92 | 12c00160: 0000000070615c70 0000002312c001f0 p\ap........#... 93 | 12c00170: 00000000705d10a0 0000000000000010 ..]p............ 94 | 12c00180: 0000000000000000 0000000000000000 ................ 95 | 12c00190: 0000000000000000 0000000000000000 ................ 96 | 12c001a0: 00000000705d10a0 0020004100000022 ..]p...."...A... 97 | 12c001b0: 006f007300650072 0065006300720075 r.e.s.o.u.r.c.e. 98 | 12c001c0: 0069006100660020 002000640065006c ..f.a.i.l.e.d... 99 | 12c001d0: 00630020006f0074 0020006c006c0061 t.o...c.a.l.l... 100 | 12c001e0: 0065006c00650072 0000006500730061 r.e.l.e.a.s.e... 101 | 12c001f0: 00000000705d10a0 0020004100000046 ..]p....F...A... 102 | ``` 103 | 104 | ``` 105 | crash-android> vtop 98be9000 106 | VIRTUAL PHYSICAL 107 | 98be9000 (not mapped) 108 | 109 | PAGE DIRECTORY: ffffff8160232000 110 | PGD: ffffff8160232010 => 8000001a1586003 111 | PMD: ffffff8161586628 => 800000154766003 112 | PTE: ffffff8114766f48 => 0 113 | 114 | VMA START END FLAGS FILE 115 | ffffff8161ccbed0 98be9000 9abe9000 2000000dd memfd:jit-zygote-cache 116 | 117 | FILE: memfd:jit-zygote-cache OFFSET: 2000000 118 | 119 | crash-android> lp shmem -r 98be9000 -e 98be9100 120 | 98be9000: 0000000000000000 00000000000003b3 ................ 121 | 98be9010: 0000000000000000 0000000000000000 ................ 122 | 98be9020: 0000000000002bd0 000000741ec00000 .+..........t... 123 | 98be9030: 0000000000000000 000000741ec053e0 .........S..t... 124 | 98be9040: 0000000000200000 ffffffffffffffff ................ 125 | 98be9050: 0000000031dcfbb8 0000000000000000 ...1............ 126 | 98be9060: 0000000000000000 000000741ec00058 ........X...t... 127 | 98be9070: 000000741ec00058 000000741ec00068 X...t...h...t... 128 | 98be9080: 000000741ec00068 000000741ec00078 h...t...x...t... 129 | 98be9090: 000000741ec00078 000000741ec00088 x...t.......t... 130 | 98be90a0: 000000741ec00088 000000741ec00098 ....t.......t... 131 | 98be90b0: 000000741ec00098 000000741ec000a8 ....t.......t... 132 | 98be90c0: 000000741ec000a8 000000741ec000b8 ....t.......t... 133 | 98be90d0: 000000741ec000b8 000000741ec000c8 ....t.......t... 134 | 98be90e0: 000000741ec000c8 000000741ec000d8 ....t.......t... 135 | 98be90f0: 000000741ec000d8 000000741ec000e8 ....t.......t... 136 | ``` 137 | 138 | ``` 139 | crash-android> lp binder -a | grep outgoing 140 | outgoing transaction 363543018: 0xffffff8170b4a000 from 7417:7417 to 1709:1728 code 18 flags 12 pri SCHED_NORMAL:120 r1 141 | outgoing transaction 363543023: 0xffffff806b8a9c00 from 7335:7335 to 1709:2599 code 28 flags 12 pri SCHED_NORMAL:120 r1 142 | outgoing transaction 363542714: 0xffffff8196ae6400 from 7310:7310 to 1709:3784 code 17 flags 12 pri SCHED_NORMAL:120 r1 143 | outgoing transaction 363538861: 0xffffff808380de00 from 7203:7203 to 1709:3251 code 6 flags 12 pri SCHED_NORMAL:120 r1 144 | outgoing transaction 363542702: 0xffffff80f6931c00 from 6948:7200 to 1709:2793 code 6b flags 12 pri SCHED_NORMAL:120 r1 145 | outgoing transaction 363542574: 0xffffff80f6931500 from 6948:7381 to 1709:3250 code d flags 12 pri SCHED_NORMAL:120 r1 146 | outgoing transaction 363542463: 0xffffff81439d9d00 from 6948:7456 to 1709:15269 code 6 flags 12 pri SCHED_NORMAL:120 r1 147 | outgoing transaction 363542516: 0xffffff8092d63900 from 6909:7330 to 1709:2794 code 1e flags 12 pri SCHED_NORMAL:139 r1 148 | ``` 149 | 150 | ``` 151 | crash-android> lp time 152 | Current time: [150957.312500] 153 | ``` 154 | 155 | ``` 156 | crash-android> lp cmdline -p 1 157 | /system/bin/init second_stage 158 | ``` 159 | -------------------------------------------------------------------------------- /shmem/shmem.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "shmem.h" 4 | #include "zram/zram.h" 5 | #include 6 | #include 7 | #include 8 | 9 | void parser_shmem_main(void) { 10 | if (argcnt <= 2) { 11 | parser_shmem_usage(); 12 | return; 13 | } 14 | 15 | int opt; 16 | int option_index = 0; 17 | optind = 0; // reset 18 | static struct option long_options[] = { 19 | {"read", required_argument, 0, 'r'}, 20 | {"end", required_argument, 0, 'e'}, 21 | {0, 0, 0, 0 } 22 | }; 23 | 24 | ulong vaddr = 0x0; 25 | ulong eaddr = 0x0; 26 | while ((opt = getopt_long(argcnt - 1, &args[1], "r:e:", 27 | long_options, &option_index)) != -1) { 28 | switch (opt) { 29 | case 'r': 30 | if (args[optind]) { 31 | vaddr = htol(args[optind], FAULT_ON_ERROR, NULL); 32 | eaddr = vaddr + 0x10; 33 | } break; 34 | case 'e': 35 | if (args[optind]) { 36 | eaddr = htol(args[optind], FAULT_ON_ERROR, NULL); 37 | } break; 38 | } 39 | } 40 | 41 | unsigned char *value = (unsigned char *)malloc(PAGESIZE()); 42 | memset(value, 0x0, PAGESIZE()); 43 | int shmem_parse_ret = 0; 44 | char ascii1[9] = {'.', '.', '.', '.', '.', '.', '.', '.', '\0'}; 45 | char ascii2[9] = {'.', '.', '.', '.', '.', '.', '.', '.', '\0'}; 46 | ulong off = PAGEOFFSET(vaddr) / 0x8; 47 | 48 | struct shmem_data_t shmem_data; 49 | memset(&shmem_data, 0x0, sizeof(shmem_data)); 50 | shmem_data.tc = CURRENT_CONTEXT(); 51 | if (!shmem_data.tc) return; 52 | 53 | shmem_data.pid = shmem_data.tc->pid; 54 | shmem_data.vma_count = parser_vma_caches(shmem_data.tc, &shmem_data.vma_cache); 55 | 56 | for (int index = 0; index < shmem_data.vma_count; ++index) { 57 | if (vaddr >= shmem_data.vma_cache[index].vm_start 58 | && vaddr < shmem_data.vma_cache[index].vm_end) { 59 | parser_zram_init(); 60 | shmem_parse_ret = parser_shmem_read_page(vaddr, &shmem_data.vma_cache[index], value, FAULT_ON_ERROR); 61 | } 62 | } 63 | 64 | if (shmem_data.vma_cache) free(shmem_data.vma_cache); 65 | 66 | if (!shmem_parse_ret) return; 67 | int count = (eaddr - vaddr) / 8; 68 | for (int index = 0; index < count; index += 2) { 69 | parser_convert_ascii(((ulong *)value)[index + off], ascii1); 70 | parser_convert_ascii(((ulong *)value)[index + 1 + off], ascii2); 71 | fprintf(fp, " %lx: %016lx %016lx %s%s\n", vaddr + index * 0x8, 72 | ((ulong *)value)[index + off], ((ulong *)value)[index + 1 + off], ascii1, ascii2); 73 | } 74 | } 75 | 76 | void parser_shmem_usage(void) { 77 | fprintf(fp, "Usage: lp shmem [OPTION] ...\n"); 78 | fprintf(fp, "Option:\n"); 79 | fprintf(fp, " -r, --read read vaddr memory\n"); 80 | fprintf(fp, " -e, --end read endvaddr memory\n"); 81 | } 82 | 83 | int parser_shmem_read_page(ulong vaddr, struct vma_cache_data* vma_cache, 84 | unsigned char* value, ulong error_handle) { 85 | if (!vma_cache->vm_file 86 | || !(vma_cache->vm_flags & (VM_SHARED | VM_MAYSHARE))) 87 | return 0; 88 | 89 | ulong vm_pgoff = vma_cache->vm_pgoff << PAGESHIFT(); 90 | int idx = (vaddr - vma_cache->vm_start + vm_pgoff) >> PAGESHIFT(); 91 | 92 | ulong f_inode; 93 | ulong i_mapping; 94 | 95 | readmem(vma_cache->vm_file + PARSER_OFFSET(file_f_inode), KVADDR, 96 | &f_inode, PARSER_SIZE(file_f_inode), "file f_inode", error_handle); 97 | 98 | readmem(f_inode + PARSER_OFFSET(inode_i_mapping), KVADDR, 99 | &i_mapping, PARSER_SIZE(inode_i_mapping), "inode i_mapping", error_handle); 100 | 101 | ulong i_pages = i_mapping + PARSER_OFFSET(address_space_i_pages); 102 | struct list_pair lp; 103 | lp.index = idx; 104 | 105 | if (!IS_KVADDR(i_pages)) 106 | return 0; 107 | 108 | if (do_xarray(i_pages, XARRAY_SEARCH, &lp)) { 109 | ulong page = (ulong)lp.value; 110 | if (page & 1) { 111 | ulong paddr = (page >> 1) << 8; 112 | ulong zram_offset = SWP_OFFSET(paddr); 113 | ulong swap_type = SWP_TYPE(paddr); 114 | return parser_zram_read_page(swap_type, zram_offset, value, error_handle); 115 | } 116 | } 117 | return 0; 118 | } 119 | 120 | int parser_shmem_get_page_cache(struct vma_cache_data* vma_cache, 121 | struct list_pair **page_list, ulong error_handle) { 122 | if (!vma_cache->vm_file 123 | || !(vma_cache->vm_flags & (VM_SHARED | VM_MAYSHARE))) 124 | return 0; 125 | 126 | ulong f_inode; 127 | ulong i_mapping; 128 | ulong xarray; 129 | ulong root_rnode; 130 | int count; 131 | 132 | readmem(vma_cache->vm_file + PARSER_OFFSET(file_f_inode), KVADDR, 133 | &f_inode, PARSER_SIZE(file_f_inode), "file f_inode", error_handle); 134 | 135 | readmem(f_inode + PARSER_OFFSET(inode_i_mapping), KVADDR, 136 | &i_mapping, PARSER_SIZE(inode_i_mapping), "inode i_mapping", error_handle); 137 | 138 | xarray = root_rnode = count = 0; 139 | if (MEMBER_EXISTS("address_space", "i_pages") && 140 | (STREQ(MEMBER_TYPE_NAME("address_space", "i_pages"), "xarray") || 141 | (STREQ(MEMBER_TYPE_NAME("address_space", "i_pages"), "radix_tree_root") && 142 | MEMBER_EXISTS("radix_tree_root", "xa_head")))) 143 | xarray = i_mapping + PARSER_OFFSET(address_space_i_pages); 144 | else 145 | root_rnode = i_mapping + PARSER_OFFSET(address_space_i_pages); 146 | 147 | if (root_rnode) { 148 | if (IS_KVADDR(root_rnode)) { 149 | count = do_radix_tree(root_rnode, RADIX_TREE_COUNT, NULL); 150 | if (count) { 151 | *page_list = (struct list_pair *)malloc(sizeof(struct list_pair) * count); 152 | do_radix_tree(root_rnode, RADIX_TREE_GATHER, *page_list); 153 | } 154 | } 155 | } else { 156 | if (IS_KVADDR(xarray)) { 157 | count = do_xarray(xarray, XARRAY_COUNT, NULL); 158 | if (count) { 159 | *page_list = (struct list_pair *)malloc(sizeof(struct list_pair) * count); 160 | do_xarray(xarray, XARRAY_GATHER, *page_list); 161 | } 162 | } 163 | } 164 | return count; 165 | } 166 | 167 | int parser_shmem_read_page_cache(ulong vaddr, struct vma_cache_data* vma_cache, int count, 168 | struct list_pair *page_list, unsigned char* value, ulong error_handle) { 169 | ulong vm_pgoff = vma_cache->vm_pgoff << PAGESHIFT(); 170 | int idx = (vaddr - vma_cache->vm_start + vm_pgoff) >> PAGESHIFT(); 171 | ulong page = 0x0; 172 | for (int i = 0; i < count; ++i) { 173 | if (page_list[i].index == idx) { 174 | page = (ulong)page_list[i].value; 175 | break; 176 | } 177 | } 178 | 179 | if (page & 1) { 180 | ulong paddr = (page >> 1) << 8; 181 | ulong zram_offset = SWP_OFFSET(paddr); 182 | ulong swap_type = SWP_TYPE(paddr); 183 | return parser_zram_read_page(swap_type, zram_offset, value, error_handle); 184 | } 185 | return 0; 186 | } 187 | -------------------------------------------------------------------------------- /lib/lz4/lz4defs.h: -------------------------------------------------------------------------------- 1 | #ifndef __LZ4DEFS_H__ 2 | #define __LZ4DEFS_H__ 3 | 4 | /* 5 | * lz4defs.h -- common and architecture specific defines for the kernel usage 6 | 7 | * LZ4 - Fast LZ compression algorithm 8 | * Copyright (C) 2011-2016, Yann Collet. 9 | * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are 12 | * met: 13 | * * Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * * Redistributions in binary form must reproduce the above 16 | * copyright notice, this list of conditions and the following disclaimer 17 | * in the documentation and/or other materials provided with the 18 | * distribution. 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * You can contact the author at : 31 | * - LZ4 homepage : http://www.lz4.org 32 | * - LZ4 source repository : https://github.com/lz4/lz4 33 | * 34 | * Changed for kernel usage by: 35 | * Sven Schmidt <4sschmid@informatik.uni-hamburg.de> 36 | * 37 | * Changed for Linux core analysis use by: 38 | * Guanyou.Chen 39 | */ 40 | 41 | #include "unaligned.h" 42 | #include "bits.h" 43 | #include /* memset, memcpy */ 44 | 45 | #define FORCE_INLINE __always_inline 46 | #define likely(x) __builtin_expect(!!(x), 1) 47 | #define unlikely(x) __builtin_expect(!!(x), 0) 48 | 49 | /*-************************************ 50 | * Basic Types 51 | **************************************/ 52 | #include 53 | #include 54 | 55 | typedef uint8_t BYTE; 56 | typedef uint16_t U16; 57 | typedef uint32_t U32; 58 | typedef int32_t S32; 59 | typedef uint64_t U64; 60 | typedef uintptr_t uptrval; 61 | 62 | /*-************************************ 63 | * Architecture specifics 64 | **************************************/ 65 | #if defined(X86_64) || defined(ARM64) 66 | #define LZ4_ARCH64 1 67 | #elif defined(ARM) || defined(X86) 68 | #define LZ4_ARCH64 0 69 | #endif 70 | 71 | #if defined(__LITTLE_ENDIAN) 72 | #define LZ4_LITTLE_ENDIAN 1 73 | #else 74 | #define LZ4_LITTLE_ENDIAN 0 75 | #endif 76 | 77 | /*-************************************ 78 | * Constants 79 | **************************************/ 80 | #define MINMATCH 4 81 | 82 | #define WILDCOPYLENGTH 8 83 | #define LASTLITERALS 5 84 | #define MFLIMIT (WILDCOPYLENGTH + MINMATCH) 85 | /* 86 | * ensure it's possible to write 2 x wildcopyLength 87 | * without overflowing output buffer 88 | */ 89 | #define MATCH_SAFEGUARD_DISTANCE ((2 * WILDCOPYLENGTH) - MINMATCH) 90 | 91 | /* Increase this value ==> compression run slower on incompressible data */ 92 | #define LZ4_SKIPTRIGGER 6 93 | 94 | #define HASH_UNIT sizeof(size_t) 95 | 96 | #define KB (1 << 10) 97 | #define MB (1 << 20) 98 | #define GB (1U << 30) 99 | 100 | #define MAXD_LOG 16 101 | #define MAX_DISTANCE ((1 << MAXD_LOG) - 1) 102 | #define STEPSIZE sizeof(size_t) 103 | 104 | #define ML_BITS 4 105 | #define ML_MASK ((1U << ML_BITS) - 1) 106 | #define RUN_BITS (8 - ML_BITS) 107 | #define RUN_MASK ((1U << RUN_BITS) - 1) 108 | 109 | /*-************************************ 110 | * Reading and writing into memory 111 | **************************************/ 112 | static FORCE_INLINE U16 LZ4_read16(const void *ptr) 113 | { 114 | return get_unaligned_16((const U16 *)ptr); 115 | } 116 | 117 | static FORCE_INLINE U32 LZ4_read32(const void *ptr) 118 | { 119 | return get_unaligned_32((const U32 *)ptr); 120 | } 121 | 122 | static FORCE_INLINE size_t LZ4_read_ARCH(const void *ptr) 123 | { 124 | #if LZ4_ARCH64 125 | return get_unaligned_64((const size_t *)ptr); 126 | #else 127 | return get_unaligned_32((const size_t *)ptr); 128 | #endif 129 | } 130 | 131 | static FORCE_INLINE void LZ4_write16(void *memPtr, U16 value) 132 | { 133 | put_unaligned_16(value, (U16 *)memPtr); 134 | } 135 | 136 | static FORCE_INLINE void LZ4_write32(void *memPtr, U32 value) 137 | { 138 | put_unaligned_16(value, (U32 *)memPtr); 139 | } 140 | 141 | static FORCE_INLINE U16 LZ4_readLE16(const void *memPtr) 142 | { 143 | return get_unaligned_le16(memPtr); 144 | } 145 | 146 | static FORCE_INLINE void LZ4_writeLE16(void *memPtr, U16 value) 147 | { 148 | return put_unaligned_le16(value, memPtr); 149 | } 150 | 151 | /* 152 | * LZ4 relies on memcpy with a constant size being inlined. In freestanding 153 | * environments, the compiler can't assume the implementation of memcpy() is 154 | * standard compliant, so apply its specialized memcpy() inlining logic. When 155 | * possible, use __builtin_memcpy() to tell the compiler to analyze memcpy() 156 | * as-if it were standard compliant, so it can inline it in freestanding 157 | * environments. This is needed when decompressing the Linux Kernel, for example. 158 | */ 159 | #define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size) 160 | #define LZ4_memmove(dst, src, size) __builtin_memmove(dst, src, size) 161 | 162 | static FORCE_INLINE void LZ4_copy8(void *dst, const void *src) 163 | { 164 | #if LZ4_ARCH64 165 | U64 a = get_unaligned_64((const U64 *)src); 166 | 167 | put_unaligned_64(a, (U64 *)dst); 168 | #else 169 | U32 a = get_unaligned_32((const U32 *)src); 170 | U32 b = get_unaligned_32((const U32 *)src + 1); 171 | 172 | put_unaligned_32(a, (U32 *)dst); 173 | put_unaligned_32(b, (U32 *)dst + 1); 174 | #endif 175 | } 176 | 177 | /* 178 | * customized variant of memcpy, 179 | * which can overwrite up to 7 bytes beyond dstEnd 180 | */ 181 | static FORCE_INLINE void LZ4_wildCopy(void *dstPtr, 182 | const void *srcPtr, void *dstEnd) 183 | { 184 | BYTE *d = (BYTE *)dstPtr; 185 | const BYTE *s = (const BYTE *)srcPtr; 186 | BYTE *const e = (BYTE *)dstEnd; 187 | 188 | do { 189 | LZ4_copy8(d, s); 190 | d += 8; 191 | s += 8; 192 | } while (d < e); 193 | } 194 | 195 | static FORCE_INLINE unsigned int LZ4_NbCommonBytes(register size_t val) 196 | { 197 | #if LZ4_LITTLE_ENDIAN 198 | return __ffs(val) >> 3; 199 | #else 200 | return (PARSER_BITS_PER_LONG - 1 - __fls(val)) >> 3; 201 | #endif 202 | } 203 | 204 | static FORCE_INLINE unsigned int LZ4_count( 205 | const BYTE *pIn, 206 | const BYTE *pMatch, 207 | const BYTE *pInLimit) 208 | { 209 | const BYTE *const pStart = pIn; 210 | 211 | while (likely(pIn < pInLimit - (STEPSIZE - 1))) { 212 | size_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); 213 | 214 | if (!diff) { 215 | pIn += STEPSIZE; 216 | pMatch += STEPSIZE; 217 | continue; 218 | } 219 | 220 | pIn += LZ4_NbCommonBytes(diff); 221 | 222 | return (unsigned int)(pIn - pStart); 223 | } 224 | 225 | #if LZ4_ARCH64 226 | if ((pIn < (pInLimit - 3)) 227 | && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { 228 | pIn += 4; 229 | pMatch += 4; 230 | } 231 | #endif 232 | 233 | if ((pIn < (pInLimit - 1)) 234 | && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { 235 | pIn += 2; 236 | pMatch += 2; 237 | } 238 | 239 | if ((pIn < pInLimit) && (*pMatch == *pIn)) 240 | pIn++; 241 | 242 | return (unsigned int)(pIn - pStart); 243 | } 244 | 245 | typedef enum { noLimit = 0, limitedOutput = 1 } limitedOutput_directive; 246 | typedef enum { byPtr, byU32, byU16 } tableType_t; 247 | 248 | typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive; 249 | typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; 250 | 251 | typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; 252 | typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive; 253 | 254 | #endif 255 | -------------------------------------------------------------------------------- /lib/lzo/lzo1x_decompress_safe.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * LZO1X Decompressor from LZO 4 | * 5 | * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer 6 | * 7 | * The full LZO package can be found at: 8 | * http://www.oberhumer.com/opensource/lzo/ 9 | * 10 | * Changed for Linux kernel use by: 11 | * Nitin Gupta 12 | * Richard Purdie 13 | * 14 | * Changed for Linux core analysis use by: 15 | * Guanyou.Chen 16 | */ 17 | 18 | #include "defs.h" 19 | #include "lzo.h" 20 | #include "lzodefs.h" 21 | #include 22 | 23 | #define likely(x) __builtin_expect(!!(x), 1) 24 | #define unlikely(x) __builtin_expect(!!(x), 0) 25 | 26 | #define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x)) 27 | #define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) 28 | #define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun 29 | #define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun 30 | #define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun 31 | 32 | /* This MAX_255_COUNT is the maximum number of times we can add 255 to a base 33 | * count without overflowing an integer. The multiply will overflow when 34 | * multiplying 255 by more than MAXINT/255. The sum will overflow earlier 35 | * depending on the base count. Since the base count is taken from a u8 36 | * and a few bits, it is safe to assume that it will always be lower than 37 | * or equal to 2*255, thus we can always prevent any overflow by accepting 38 | * two less 255 steps. See Documentation/staging/lzo.rst for more information. 39 | */ 40 | #define MAX_255_COUNT ((((size_t)~0) / 255) - 2) 41 | 42 | int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, 43 | unsigned char *out, size_t *out_len) 44 | { 45 | unsigned char *op; 46 | const unsigned char *ip; 47 | size_t t, next; 48 | size_t state = 0; 49 | const unsigned char *m_pos; 50 | const unsigned char * const ip_end = in + in_len; 51 | unsigned char * const op_end = out + *out_len; 52 | 53 | unsigned char bitstream_version; 54 | 55 | static int efficient_unaligned_access = -1; 56 | 57 | if (efficient_unaligned_access == -1) { 58 | #if defined(ARM) || defined(ARM64) || defined(X86) || defined(X86_64) || defined(PPC) || defined(PPC64) || defined(S390)|| defined(S390X) 59 | efficient_unaligned_access = TRUE; 60 | #else 61 | efficient_unaligned_access = FALSE; 62 | #endif 63 | 64 | if ((kt->ikconfig_flags & IKCONFIG_AVAIL) && 65 | (get_kernel_config("CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS", NULL) == IKCONFIG_Y)) 66 | efficient_unaligned_access = TRUE; 67 | } 68 | 69 | op = out; 70 | ip = in; 71 | 72 | if (unlikely(in_len < 3)) 73 | goto input_overrun; 74 | 75 | if (likely(in_len >= 5) && likely(*ip == 17)) { 76 | bitstream_version = ip[1]; 77 | ip += 2; 78 | } else { 79 | bitstream_version = 0; 80 | } 81 | 82 | if (*ip > 17) { 83 | t = *ip++ - 17; 84 | if (t < 4) { 85 | next = t; 86 | goto match_next; 87 | } 88 | goto copy_literal_run; 89 | } 90 | 91 | for (;;) { 92 | t = *ip++; 93 | if (t < 16) { 94 | if (likely(state == 0)) { 95 | if (unlikely(t == 0)) { 96 | size_t offset; 97 | const unsigned char *ip_last = ip; 98 | 99 | while (unlikely(*ip == 0)) { 100 | ip++; 101 | NEED_IP(1); 102 | } 103 | offset = ip - ip_last; 104 | if (unlikely(offset > MAX_255_COUNT)) 105 | return LZO_E_ERROR; 106 | 107 | offset = (offset << 8) - offset; 108 | t += offset + 15 + *ip++; 109 | } 110 | t += 3; 111 | copy_literal_run: 112 | if (efficient_unaligned_access && 113 | (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15)))) { 114 | const unsigned char *ie = ip + t; 115 | unsigned char *oe = op + t; 116 | do { 117 | COPY8(op, ip); 118 | op += 8; 119 | ip += 8; 120 | COPY8(op, ip); 121 | op += 8; 122 | ip += 8; 123 | } while (ip < ie); 124 | ip = ie; 125 | op = oe; 126 | } else { 127 | NEED_OP(t); 128 | NEED_IP(t + 3); 129 | do { 130 | *op++ = *ip++; 131 | } while (--t > 0); 132 | } 133 | state = 4; 134 | continue; 135 | } else if (state != 4) { 136 | next = t & 3; 137 | m_pos = op - 1; 138 | m_pos -= t >> 2; 139 | m_pos -= *ip++ << 2; 140 | TEST_LB(m_pos); 141 | NEED_OP(2); 142 | op[0] = m_pos[0]; 143 | op[1] = m_pos[1]; 144 | op += 2; 145 | goto match_next; 146 | } else { 147 | next = t & 3; 148 | m_pos = op - (1 + M2_MAX_OFFSET); 149 | m_pos -= t >> 2; 150 | m_pos -= *ip++ << 2; 151 | t = 3; 152 | } 153 | } else if (t >= 64) { 154 | next = t & 3; 155 | m_pos = op - 1; 156 | m_pos -= (t >> 2) & 7; 157 | m_pos -= *ip++ << 3; 158 | t = (t >> 5) - 1 + (3 - 1); 159 | } else if (t >= 32) { 160 | t = (t & 31) + (3 - 1); 161 | if (unlikely(t == 2)) { 162 | size_t offset; 163 | const unsigned char *ip_last = ip; 164 | 165 | while (unlikely(*ip == 0)) { 166 | ip++; 167 | NEED_IP(1); 168 | } 169 | offset = ip - ip_last; 170 | if (unlikely(offset > MAX_255_COUNT)) 171 | return LZO_E_ERROR; 172 | 173 | offset = (offset << 8) - offset; 174 | t += offset + 31 + *ip++; 175 | NEED_IP(2); 176 | } 177 | m_pos = op - 1; 178 | 179 | next = get_unaligned_le16(ip); 180 | ip += 2; 181 | m_pos -= next >> 2; 182 | next &= 3; 183 | } else { 184 | NEED_IP(2); 185 | next = get_unaligned_le16(ip); 186 | if (((next & 0xfffc) == 0xfffc) && 187 | ((t & 0xf8) == 0x18) && 188 | likely(bitstream_version)) { 189 | NEED_IP(3); 190 | t &= 7; 191 | t |= ip[2] << 3; 192 | t += MIN_ZERO_RUN_LENGTH; 193 | NEED_OP(t); 194 | memset(op, 0, t); 195 | op += t; 196 | next &= 3; 197 | ip += 3; 198 | goto match_next; 199 | } else { 200 | m_pos = op; 201 | m_pos -= (t & 8) << 11; 202 | t = (t & 7) + (3 - 1); 203 | if (unlikely(t == 2)) { 204 | size_t offset; 205 | const unsigned char *ip_last = ip; 206 | 207 | while (unlikely(*ip == 0)) { 208 | ip++; 209 | NEED_IP(1); 210 | } 211 | offset = ip - ip_last; 212 | if (unlikely(offset > MAX_255_COUNT)) 213 | return LZO_E_ERROR; 214 | 215 | offset = (offset << 8) - offset; 216 | t += offset + 7 + *ip++; 217 | NEED_IP(2); 218 | next = get_unaligned_le16(ip); 219 | } 220 | ip += 2; 221 | m_pos -= next >> 2; 222 | next &= 3; 223 | if (m_pos == op) 224 | goto eof_found; 225 | m_pos -= 0x4000; 226 | } 227 | } 228 | TEST_LB(m_pos); 229 | 230 | if (efficient_unaligned_access && 231 | (op - m_pos >= 8)) { 232 | unsigned char *oe = op + t; 233 | if (likely(HAVE_OP(t + 15))) { 234 | do { 235 | COPY8(op, m_pos); 236 | op += 8; 237 | m_pos += 8; 238 | COPY8(op, m_pos); 239 | op += 8; 240 | m_pos += 8; 241 | } while (op < oe); 242 | op = oe; 243 | if (HAVE_IP(6)) { 244 | state = next; 245 | COPY4(op, ip); 246 | op += next; 247 | ip += next; 248 | continue; 249 | } 250 | } else { 251 | NEED_OP(t); 252 | do { 253 | *op++ = *m_pos++; 254 | } while (op < oe); 255 | } 256 | } else { 257 | unsigned char *oe = op + t; 258 | NEED_OP(t); 259 | op[0] = m_pos[0]; 260 | op[1] = m_pos[1]; 261 | op += 2; 262 | m_pos += 2; 263 | do { 264 | *op++ = *m_pos++; 265 | } while (op < oe); 266 | } 267 | match_next: 268 | state = next; 269 | t = next; 270 | if (efficient_unaligned_access && 271 | (likely(HAVE_IP(6) && HAVE_OP(4)))) { 272 | COPY4(op, ip); 273 | op += t; 274 | ip += t; 275 | } else { 276 | NEED_IP(t + 3); 277 | NEED_OP(t); 278 | while (t > 0) { 279 | *op++ = *ip++; 280 | t--; 281 | } 282 | } 283 | } 284 | 285 | eof_found: 286 | *out_len = op - out; 287 | return (t != 3 ? LZO_E_ERROR : 288 | ip == ip_end ? LZO_E_OK : 289 | ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN); 290 | 291 | input_overrun: 292 | *out_len = op - out; 293 | return LZO_E_INPUT_OVERRUN; 294 | 295 | output_overrun: 296 | *out_len = op - out; 297 | return LZO_E_OUTPUT_OVERRUN; 298 | 299 | lookbehind_overrun: 300 | *out_len = op - out; 301 | return LZO_E_LOOKBEHIND_OVERRUN; 302 | } 303 | -------------------------------------------------------------------------------- /core/core_arm64.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "core.h" 4 | #include "bits.h" 5 | 6 | #define TIF_TAGGED_ADDR 26 7 | #define PR_TAGGED_ADDR_ENABLE (1UL << 0) 8 | 9 | #define PR_PAC_APIAKEY (1UL << 0) 10 | #define PR_PAC_APIBKEY (1UL << 1) 11 | #define PR_PAC_APDAKEY (1UL << 2) 12 | #define PR_PAC_APDBKEY (1UL << 3) 13 | #define PR_PAC_APGAKEY (1UL << 4) 14 | 15 | #define SCTLR_ELx_ENIA (BIT(31)) 16 | #define SCTLR_ELx_ENIB (BIT(30)) 17 | #define SCTLR_ELx_ENDA (BIT(27)) 18 | #define SCTLR_ELx_ENDB (BIT(13)) 19 | 20 | #define MTE_CTRL_GCR_USER_EXCL_SHIFT 0 21 | #define MTE_CTRL_GCR_USER_EXCL_MASK 0xffff 22 | 23 | #define MTE_CTRL_TCF_SYNC (1UL << 16) 24 | #define MTE_CTRL_TCF_ASYNC (1UL << 17) 25 | 26 | #define PR_MTE_TAG_SHIFT 3 27 | #define PR_MTE_TCF_SYNC (1UL << 1) 28 | #define PR_MTE_TCF_ASYNC (1UL << 2) 29 | 30 | struct pt_regs { 31 | uint64_t regs[31]; 32 | uint64_t sp; 33 | uint64_t pc; 34 | uint64_t pstate; 35 | }; 36 | 37 | typedef struct elf64_prstatus { 38 | uint32_t pr_si_signo; 39 | uint32_t pr_si_code; 40 | uint32_t pr_si_errno; 41 | uint16_t pr_cursig; 42 | uint64_t pr_sigpend; 43 | uint64_t pr_sighold; 44 | uint32_t pr_pid; 45 | uint32_t pr_ppid; 46 | uint32_t pr_pgrp; 47 | uint32_t pd_sid; 48 | uint64_t pr_utime[2]; 49 | uint64_t pr_stime[2]; 50 | uint64_t pr_cutime[2]; 51 | uint64_t pr_cstime[2]; 52 | struct pt_regs pr_reg; 53 | uint32_t pr_fpvalid; 54 | } Elf64_prstatus; 55 | 56 | struct user_pac_mask { 57 | uint64_t data_mask; 58 | uint64_t insn_mask; 59 | }; 60 | 61 | void parser_arm64_core_prstatus(struct core_data_t* core_data) { 62 | core_data->prstatus_sizeof = sizeof(Elf64_prstatus); 63 | if (!core_data->prnum) return; 64 | 65 | int i, cur; 66 | core_data->prstatus_cache = malloc(core_data->prnum * sizeof(Elf64_prstatus)); 67 | memset(core_data->prstatus_cache, 0, core_data->prnum * sizeof(Elf64_prstatus)); 68 | Elf64_prstatus *prstatus = core_data->prstatus_cache; 69 | 70 | int tgid = task_tgid(core_data->tc->task); 71 | struct task_context *tc = FIRST_CONTEXT(); 72 | for (i = cur = 0; i < RUNNING_TASKS(); i++, tc++) { 73 | if (task_tgid(tc->task) == tgid) { 74 | prstatus[cur].pr_pid = tc->pid; 75 | 76 | readmem(machdep->get_stacktop(tc->task) - PARSER_SIZE(pt_regs), KVADDR, 77 | &prstatus[cur].pr_reg, sizeof(struct pt_regs), "gpr_get: user_pt_regs", 78 | core_data->error_handle); 79 | cur++; 80 | } 81 | } 82 | 83 | int CONFIG_ARM64_PTR_AUTH = get_kernel_config("CONFIG_ARM64_PTR_AUTH", NULL); 84 | int CONFIG_ARM64_TAGGED_ADDR_ABI = get_kernel_config("CONFIG_ARM64_TAGGED_ADDR_ABI", NULL); 85 | 86 | if (CONFIG_ARM64_PTR_AUTH) { 87 | core_data->extra_note_filesz += ((sizeof(struct user_pac_mask) + sizeof(Elf64_Nhdr) + 8) // NT_ARM_PAC_MASK 88 | + (sizeof(uint64_t) + sizeof(Elf64_Nhdr) + 8) // NT_ARM_PAC_ENABLED_KEYS 89 | ) * core_data->prnum; 90 | } 91 | 92 | if (CONFIG_ARM64_TAGGED_ADDR_ABI) { 93 | core_data->extra_note_filesz += (sizeof(uint64_t) + sizeof(Elf64_Nhdr) + 8) * core_data->prnum; // NT_ARM_TAGGED_ADDR_CTRL 94 | } 95 | } 96 | 97 | void parser_write_arm64_core_pac(struct core_data_t* core_data, int pid) { 98 | // NT_ARM_PAC_MASK 99 | Elf64_Nhdr nhdr; 100 | nhdr.n_namesz = NOTE_LINUX_NAME_SZ; 101 | nhdr.n_descsz = sizeof(struct user_pac_mask); 102 | nhdr.n_type = NT_ARM_PAC_MASK; 103 | 104 | char magic[8]; 105 | memset(magic, 0, sizeof(magic)); 106 | snprintf(magic, NOTE_LINUX_NAME_SZ, ELFLINUXMAGIC); 107 | 108 | fwrite(&nhdr, sizeof(Elf64_Nhdr), 1, core_data->fp); 109 | fwrite(magic, sizeof(magic), 1, core_data->fp); 110 | 111 | struct user_pac_mask uregs; 112 | ulong vabits_actual = machdep->machspec->VA_BITS_ACTUAL; 113 | uint64_t mask = GENMASK(54, vabits_actual); // default 114 | uregs.data_mask = mask; 115 | uregs.insn_mask = mask; 116 | fwrite(&uregs, sizeof(struct user_pac_mask), 1, core_data->fp); 117 | 118 | // NT_ARM_PAC_ENABLED_KEYS 119 | nhdr.n_descsz = sizeof(uint64_t); 120 | nhdr.n_type = NT_ARM_PAC_ENABLED_KEYS; 121 | 122 | fwrite(&nhdr, sizeof(Elf64_Nhdr), 1, core_data->fp); 123 | fwrite(magic, sizeof(magic), 1, core_data->fp); 124 | 125 | struct task_context *tc = pid_to_context(pid); 126 | ulong sctlr_user; 127 | readmem(tc->task + PARSER_OFFSET(task_struct_thread) + PARSER_OFFSET(thread_struct_sctlr_user), 128 | KVADDR, &sctlr_user, sizeof(ulong), "sctlr_user", core_data->error_handle); 129 | uint64_t pac_enabled_keys = 0x0; 130 | 131 | if (sctlr_user & SCTLR_ELx_ENIA) 132 | pac_enabled_keys |= PR_PAC_APIAKEY; 133 | if (sctlr_user & SCTLR_ELx_ENIB) 134 | pac_enabled_keys |= PR_PAC_APIBKEY; 135 | if (sctlr_user & SCTLR_ELx_ENDA) 136 | pac_enabled_keys |= PR_PAC_APDAKEY; 137 | if (sctlr_user & SCTLR_ELx_ENDB) 138 | pac_enabled_keys |= PR_PAC_APDBKEY; 139 | 140 | fwrite(&pac_enabled_keys, sizeof(uint64_t), 1, core_data->fp); 141 | } 142 | 143 | void parser_write_arm64_core_mte(struct core_data_t* core_data, int pid) { 144 | // NT_ARM_TAGGED_ADDR_CTRL 145 | Elf64_Nhdr nhdr; 146 | nhdr.n_namesz = NOTE_LINUX_NAME_SZ; 147 | nhdr.n_descsz = sizeof(uint64_t); 148 | nhdr.n_type = NT_ARM_TAGGED_ADDR_CTRL; 149 | 150 | char magic[8]; 151 | memset(magic, 0, sizeof(magic)); 152 | snprintf(magic, NOTE_LINUX_NAME_SZ, ELFLINUXMAGIC); 153 | 154 | fwrite(&nhdr, sizeof(Elf64_Nhdr), 1, core_data->fp); 155 | fwrite(magic, sizeof(magic), 1, core_data->fp); 156 | 157 | struct task_context *tc = pid_to_context(pid); 158 | ulong thread_info_flags = 0x0; 159 | readmem(tc->thread_info + PARSER_OFFSET(thread_info_flags), 160 | KVADDR, &thread_info_flags, sizeof(ulong), "thread_info_flags", core_data->error_handle); 161 | uint64_t tagged_addr_ctrl = 0x0; 162 | if (thread_info_flags & (1 << TIF_TAGGED_ADDR)) 163 | tagged_addr_ctrl |= PR_TAGGED_ADDR_ENABLE; 164 | 165 | ulong mte_ctrl = -1; 166 | if (PARSER_VALID_MEMBER(thread_struct_mte_ctrl)) { 167 | readmem(tc->task + PARSER_OFFSET(task_struct_thread) + PARSER_OFFSET(thread_struct_mte_ctrl), 168 | KVADDR, &mte_ctrl, sizeof(ulong), "mte_ctrl", core_data->error_handle); 169 | 170 | ulong incl = (~mte_ctrl >> MTE_CTRL_GCR_USER_EXCL_SHIFT) & MTE_CTRL_GCR_USER_EXCL_MASK; 171 | tagged_addr_ctrl = incl << PR_MTE_TAG_SHIFT; 172 | if (mte_ctrl & MTE_CTRL_TCF_ASYNC) 173 | tagged_addr_ctrl |= PR_MTE_TCF_ASYNC; 174 | if (mte_ctrl & MTE_CTRL_TCF_SYNC) 175 | tagged_addr_ctrl |= PR_MTE_TCF_SYNC; 176 | } 177 | fwrite(&tagged_addr_ctrl, sizeof(uint64_t), 1, core_data->fp); 178 | } 179 | 180 | void parser_write_arm64_core_prstatus(struct core_data_t* core_data) { 181 | if (!core_data->prnum) return; 182 | 183 | int CONFIG_ARM64_PTR_AUTH = get_kernel_config("CONFIG_ARM64_PTR_AUTH", NULL); 184 | int CONFIG_ARM64_TAGGED_ADDR_ABI = get_kernel_config("CONFIG_ARM64_TAGGED_ADDR_ABI", NULL); 185 | 186 | Elf64_Nhdr nhdr; 187 | nhdr.n_namesz = NOTE_CORE_NAME_SZ; 188 | nhdr.n_descsz = core_data->prstatus_sizeof; 189 | nhdr.n_type = NT_PRSTATUS; 190 | 191 | char magic[8]; 192 | memset(magic, 0, sizeof(magic)); 193 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC); 194 | 195 | int index = 0; 196 | Elf64_prstatus *prstatus = core_data->prstatus_cache; 197 | while (index < core_data->prnum) { 198 | fwrite(&nhdr, sizeof(Elf64_Nhdr), 1, core_data->fp); 199 | fwrite(magic, sizeof(magic), 1, core_data->fp); 200 | fwrite((char *)core_data->prstatus_cache + nhdr.n_descsz * index, nhdr.n_descsz, 1, core_data->fp); 201 | if (CONFIG_ARM64_PTR_AUTH) parser_write_arm64_core_pac(core_data, prstatus[index].pr_pid); 202 | if (CONFIG_ARM64_TAGGED_ADDR_ABI) parser_write_arm64_core_mte(core_data, prstatus[index].pr_pid); 203 | index++; 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /cpu/cpu.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "cpu/cpu.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct cpu_bitmap { 12 | int is_set; 13 | void *precpu_cache; 14 | void *panic_cache; 15 | }; 16 | 17 | static struct cpu_bitmap* cpu_cache = NULL; 18 | static void* cpu_panic_task_regs_cache = NULL; 19 | struct cpu_bitmap* get_cpu_cache(void) { 20 | if (!cpu_cache) { 21 | int size = NR_CPUS * sizeof(struct cpu_bitmap); 22 | cpu_cache = (struct cpu_bitmap *)malloc(size); 23 | memset(cpu_cache, 0x0, size); 24 | } 25 | return cpu_cache; 26 | } 27 | 28 | struct vmcore_data { 29 | ulong flags; 30 | int ndfd; 31 | FILE *ofp; 32 | uint header_size; 33 | char *elf_header; 34 | uint num_pt_load_segments; 35 | struct pt_load_segment *pt_load_segments; 36 | Elf32_Ehdr *elf32; 37 | Elf32_Phdr *notes32; 38 | Elf32_Phdr *load32; 39 | Elf64_Ehdr *elf64; 40 | Elf64_Phdr *notes64; 41 | Elf64_Phdr *load64; 42 | Elf64_Shdr *sect0_64; 43 | void *nt_prstatus; 44 | void *nt_prpsinfo; 45 | void *nt_taskstruct; 46 | ulong task_struct; 47 | uint page_size; 48 | ulong switch_stack; 49 | uint num_prstatus_notes; 50 | void *nt_prstatus_percpu[NR_CPUS]; 51 | void *vmcoreinfo; 52 | uint size_vmcoreinfo; 53 | }; 54 | 55 | void parser_cpu_main(void) { 56 | int cpu_idx = -1; 57 | char* cmm = NULL; 58 | bool reset_cpu = false; 59 | int cpu_lv = 1; 60 | 61 | int opt; 62 | int option_index = 0; 63 | optind = 0; // reset 64 | static struct option long_options[] = { 65 | {"cmm", required_argument, 0, 1 }, 66 | {"cpu", required_argument, 0, 'c'}, 67 | {"reset", no_argument, 0, 'r'}, 68 | {"lv", required_argument, 0, 'l'}, 69 | {0, 0, 0, 0 }, 70 | }; 71 | 72 | while ((opt = getopt_long(argcnt - 1, &args[1], "c:rl:", 73 | long_options, &option_index)) != -1) { 74 | switch (opt) { 75 | case 1: 76 | if (args[optind]) { 77 | cmm = optarg; 78 | } break; 79 | case 'c': 80 | if (args[optind]) { 81 | cpu_idx = htol(args[optind], FAULT_ON_ERROR, NULL); 82 | } break; 83 | case 'r': 84 | reset_cpu = true; 85 | break; 86 | case 'l': 87 | if (args[optind]) { 88 | cpu_lv = htol(args[optind], FAULT_ON_ERROR, NULL); 89 | cpu_lv %= 4; 90 | } break; 91 | } 92 | } 93 | 94 | if (cpu_idx < 0) 95 | error(FATAL, "cpu id not set!\n"); 96 | 97 | struct vmcore_data *vmd = get_kdump_vmcore_data(); 98 | if (!vmd || !vmd->num_prstatus_notes) 99 | error(FATAL, "this dump not set prs!\n"); 100 | 101 | if (!machine_type("ARM64")) 102 | error(FATAL, "Only support machine arm64.\n"); 103 | 104 | if (cmm) 105 | parser_cpu_set(cmm, cpu_idx, cpu_lv); 106 | else if (reset_cpu) 107 | parser_cpu_reset(cpu_idx); 108 | } 109 | 110 | struct arm64_reg_map { 111 | char regs[16]; 112 | int position; 113 | }; 114 | 115 | static struct arm64_reg_map arm64_reg_maps[] = { 116 | {"x0", 0}, {"x1", 1}, {"x2", 2}, {"x3", 3}, 117 | {"x4", 4}, {"x5", 5}, {"x6", 6}, {"x7", 7}, 118 | {"x8", 8}, {"x9", 9}, {"x10", 10}, {"x11", 11}, 119 | {"x12", 12}, {"x13", 13}, {"x14", 14}, {"x15", 15}, 120 | {"x16", 16}, {"x17", 17}, {"x18", 18}, {"x19", 19}, 121 | {"x20", 20}, {"x21", 21}, {"x22", 22}, {"x23", 23}, 122 | {"x24", 24}, {"x25", 25}, {"x26", 26}, {"x27", 27}, 123 | {"x28", 28}, {"x29", 29}, {"x30", 30}, {"pc", 32}, 124 | {"sp", 31}, {"pstate", 33}, {"spsr", 33}, 125 | }; 126 | 127 | static struct arm64_reg_map arm64_reg_sp_maps[] = { 128 | {"sp_el0", 31}, {"sp_el1", 31}, {"sp_el2", 31}, {"sp_el3", 31}, 129 | {"spsr_el0", 33}, {"spsr_el1", 33}, {"spsr_el2", 33}, {"spsr_el3", 33}, 130 | }; 131 | 132 | void parser_cpu_reset(int idx) { 133 | struct vmcore_data *vmd = get_kdump_vmcore_data(); 134 | struct cpu_bitmap* cache = get_cpu_cache(); 135 | if (cache[idx].is_set) { 136 | free(vmd->nt_prstatus_percpu[idx]); 137 | vmd->nt_prstatus_percpu[idx] = cache[idx].precpu_cache; 138 | cache[idx].precpu_cache = 0; 139 | cache[idx].is_set = 0; 140 | #ifdef ARM64 141 | if (cache[idx].panic_cache) 142 | BCOPY(cache[idx].panic_cache, &machdep->machspec->panic_task_regs[idx], sizeof(struct arm64_pt_regs)); 143 | else 144 | BZERO(&machdep->machspec->panic_task_regs[idx], sizeof(struct arm64_pt_regs)); 145 | #endif 146 | } 147 | } 148 | 149 | void parser_cpu_set(char* cmm, int idx, int lv) { 150 | struct vmcore_data *vmd = get_kdump_vmcore_data(); 151 | size_t len; 152 | uint64_t addr; 153 | char regs_name[16]; 154 | char type_name[16]; 155 | char line[1024]; 156 | char* user_regs; 157 | char* user_data; 158 | 159 | user_data = (char *)malloc(SIZE(elf_prstatus) + sizeof(Elf64_Nhdr) + 8); 160 | Elf64_Nhdr note64; 161 | note64.n_namesz = 5; 162 | note64.n_descsz = SIZE(elf_prstatus); 163 | note64.n_type = NT_PRSTATUS; 164 | 165 | char magic[8]; 166 | memset(magic, 0, sizeof(magic)); 167 | snprintf(magic, 5, "CPU%d", idx); 168 | 169 | len = sizeof(Elf64_Nhdr); 170 | len = roundup(len + note64.n_namesz, 4); 171 | len = roundup(len + note64.n_descsz, 4); 172 | user_regs = user_data + len - SIZE(elf_prstatus) + OFFSET(elf_prstatus_pr_reg); 173 | 174 | memset(user_data, 0x0, SIZE(elf_prstatus) + sizeof(Elf64_Nhdr) + 8); 175 | memcpy(user_data, ¬e64, sizeof(Elf64_Nhdr)); 176 | memcpy(user_data + sizeof(Elf64_Nhdr), magic, 8); 177 | 178 | int count = sizeof(arm64_reg_maps)/sizeof(arm64_reg_maps[0]); 179 | 180 | FILE *ofp = fopen(cmm, "r"); 181 | if (ofp) { 182 | while (fgets(line, sizeof(line), ofp)) { 183 | sscanf(line, "%s %s %" PRIx64 "", type_name, regs_name, &addr); 184 | regs_name[15] = '\0'; 185 | type_name[15] = '\0'; 186 | 187 | if (!strcmp("r.s", type_name)) { 188 | for (int index = 0; index < count; ++index) { 189 | if (!strcmp(arm64_reg_maps[index].regs, regs_name)) { 190 | memcpy(user_regs + sizeof(ulong) * arm64_reg_maps[index].position, &addr, sizeof(ulong)); 191 | break; 192 | } 193 | 194 | if (!strcmp(arm64_reg_sp_maps[lv].regs, regs_name)) { 195 | memcpy(user_regs + sizeof(ulong) * arm64_reg_sp_maps[lv].position, &addr, sizeof(ulong)); 196 | break; 197 | } 198 | 199 | if (!strcmp(arm64_reg_sp_maps[lv + 4].regs, regs_name)) { 200 | memcpy(user_regs + sizeof(ulong) * arm64_reg_sp_maps[lv + 4].position, &addr, sizeof(ulong)); 201 | break; 202 | } 203 | } 204 | } 205 | } 206 | fclose(ofp); 207 | 208 | struct cpu_bitmap* cache = get_cpu_cache(); 209 | if (!cache[idx].is_set) { 210 | cache[idx].is_set = 1; 211 | cache[idx].precpu_cache = vmd->nt_prstatus_percpu[idx]; 212 | #ifdef ARM64 213 | if (machdep->machspec->panic_task_regs 214 | && cpu_panic_task_regs_cache != machdep->machspec->panic_task_regs) 215 | cache[idx].panic_cache = &machdep->machspec->panic_task_regs[idx]; 216 | #endif 217 | } else { 218 | free(vmd->nt_prstatus_percpu[idx]); 219 | vmd->nt_prstatus_percpu[idx] = 0x0; 220 | } 221 | #ifdef ARM64 222 | if (!machdep->machspec->panic_task_regs) { 223 | machdep->machspec->panic_task_regs = calloc((size_t)kt->cpus, sizeof(struct arm64_pt_regs)); 224 | memset(machdep->machspec->panic_task_regs, 0x0, (size_t)kt->cpus * sizeof(struct arm64_pt_regs)); 225 | cpu_panic_task_regs_cache = machdep->machspec->panic_task_regs; 226 | } 227 | if (machdep->machspec->panic_task_regs) 228 | BCOPY(user_regs, &machdep->machspec->panic_task_regs[idx], sizeof(struct arm64_pt_regs)); 229 | #endif 230 | vmd->nt_prstatus_percpu[idx] = user_data; 231 | } 232 | } 233 | 234 | void parser_cpu_cache_clean(void) { 235 | if (cpu_cache) { 236 | free(cpu_cache); 237 | cpu_cache = NULL; 238 | } 239 | if (cpu_panic_task_regs_cache) { 240 | free(cpu_panic_task_regs_cache); 241 | cpu_panic_task_regs_cache = NULL; 242 | #ifdef ARM64 243 | machdep->machspec->panic_task_regs = NULL; 244 | #endif 245 | } 246 | } 247 | 248 | void parser_cpu_usage(void) { 249 | fprintf(fp, "Usage: lp cpu [OPTION] ...\n"); 250 | fprintf(fp, "Option:\n"); 251 | fprintf(fp, " --cmm set cpu regs with core_regs.cmm\n"); 252 | fprintf(fp, " -c, --cpu set target cpu regs\n"); 253 | fprintf(fp, " -l, --lv set cpu exception level\n"); 254 | fprintf(fp, " -r, --reset clean extend cpu regs\n"); 255 | } 256 | -------------------------------------------------------------------------------- /parser_defs.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #ifndef PARSER_DEFS_H_ 4 | #define PARSER_DEFS_H_ 5 | 6 | #include "defs.h" 7 | 8 | #define PARSER_OFFSET(X) (OFFSET_verify(parser_offset_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X)) 9 | #define PARSER_SIZE(X) (SIZE_verify(parser_size_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X)) 10 | #define PARSER_VALID_MEMBER(X) (parser_offset_table.X >= 0) 11 | #define PARSER_ASSIGN_OFFSET(X) (parser_offset_table.X) 12 | #define PARSER_MEMBER_OFFSET_INIT(X, Y, Z) (PARSER_ASSIGN_OFFSET(X) = MEMBER_OFFSET(Y, Z)) 13 | #define PARSER_ASSIGN_SIZE(X) (parser_size_table.X) 14 | #define PARSER_MEMBER_SIZE_INIT(X, Y, Z) (PARSER_ASSIGN_SIZE(X) = MEMBER_SIZE(Y, Z)) 15 | #define PARSER_STRUCT_SIZE_INIT(X, Y) (PARSER_ASSIGN_SIZE(X) = STRUCT_SIZE(Y)) 16 | 17 | #define VM_READ 0x00000001 18 | #define VM_WRITE 0x00000002 19 | #define VM_EXEC 0x00000004 20 | #define VM_SHARED 0x00000008 21 | 22 | #define VM_MAYREAD 0x00000010 /* limits for mprotect() etc */ 23 | #define VM_MAYWRITE 0x00000020 24 | #define VM_MAYEXEC 0x00000040 25 | #define VM_MAYSHARE 0x00000080 26 | 27 | #define ANON_BUFSIZE (1024) 28 | 29 | struct parser_offset_table { 30 | long mm_struct_saved_auxv; 31 | long mm_struct_task_size; 32 | long mm_struct_mmap; 33 | long mm_struct_mm_mt; 34 | long mm_struct_start_stack; 35 | long mm_struct_start_brk; 36 | long mm_struct_brk; 37 | long mm_struct_arg_start; 38 | long mm_struct_arg_end; 39 | long thread_info_flags; 40 | long vm_area_struct_vm_next; 41 | long vm_area_struct_vm_start; 42 | long vm_area_struct_vm_end; 43 | long vm_area_struct_vm_flags; 44 | long vm_area_struct_vm_file; 45 | long vm_area_struct_vm_pgoff; 46 | long vm_area_struct_anon_name; 47 | long vm_area_struct_anon_vma; 48 | long vm_area_struct_vm_mm; 49 | long vm_area_struct_detached; 50 | long task_struct_flags; 51 | long task_struct_thread; 52 | long thread_struct_sctlr_user; 53 | long thread_struct_mte_ctrl; 54 | long swap_info_struct_bdev; 55 | long swap_info_struct_swap_file; 56 | long swap_info_struct_swap_vfsmnt; 57 | long swap_info_struct_old_block_size; 58 | long swap_info_struct_pages; 59 | long block_device_bd_disk; 60 | long gendisk_private_data; 61 | long page_private; 62 | long page_freelist; 63 | long page_index; 64 | long file_f_inode; 65 | long anon_vma_name_name; 66 | long inode_i_mapping; 67 | long address_space_page_tree; 68 | long address_space_i_pages; 69 | long binder_proc_proc_node; 70 | long binder_proc_pid; 71 | long binder_proc_context; 72 | long binder_proc_threads; 73 | long binder_proc_todo; 74 | long binder_context_name; 75 | long binder_thread_rb_node; 76 | long binder_thread_pid; 77 | long binder_thread_looper; 78 | long binder_thread_looper_need_return; 79 | long binder_thread_tmp_ref; 80 | long binder_thread_transaction_stack; 81 | long binder_thread_proc; 82 | long binder_transaction_from; 83 | long binder_transaction_from_parent; 84 | long binder_transaction_to_thread; 85 | long binder_transaction_to_parent; 86 | long binder_transaction_to_proc; 87 | long binder_transaction_code; 88 | long binder_transaction_flags; 89 | long binder_transaction_priority; 90 | long binder_transaction_debug_id; 91 | long binder_transaction_need_reply; 92 | long binder_transaction_buffer; 93 | long binder_transaction_work; 94 | long binder_transaction_start_time; 95 | long binder_node_debug_id; 96 | long binder_node_work; 97 | long binder_node_ptr; 98 | long binder_node_cookie; 99 | long page_owner_order; 100 | long page_owner_gfp_mask; 101 | long page_owner_handle; 102 | long page_owner_ts_nsec; 103 | long page_owner_free_ts_nsec; 104 | long page_owner_comm; 105 | long page_owner_pid; 106 | long page_owner_tgid; 107 | long mem_section_page_ext; 108 | long page_ext_flags; 109 | long page_ext_operations_offset; 110 | long stack_record_entries; 111 | long stack_record_size; 112 | long tk_core_seq; 113 | long tk_core_timekeeper; 114 | long timekeeper_tkr_mono; 115 | long tk_read_base_base; 116 | long tk_read_base_xtime_nsec; 117 | long tk_read_base_shift; 118 | long trace_array_array_buffer; 119 | long trace_array_buffer_disabled; 120 | long trace_array_current_trace; 121 | long array_buffer_buffer; 122 | long trace_buffer_record_disabled; 123 | long tracer_name; 124 | 125 | // zram 126 | long zram_disksize; 127 | long zram_compressor; 128 | long zram_table; 129 | long zram_mem_pool; 130 | long zram_comp; 131 | long zram_comps; 132 | long zram_table_entry_flags; 133 | long zram_table_entry_handle; 134 | long zram_table_entry_element; 135 | long zcomp_name; 136 | 137 | // zsmalloc 138 | long zspool_size_class; 139 | long size_class_size; 140 | long zspage_huge; 141 | }; 142 | 143 | struct parser_size_table { 144 | long mm_struct_saved_auxv; 145 | long mm_struct_task_size; 146 | long mm_struct_mmap; 147 | long mm_struct_mm_mt; 148 | long mm_struct_start_stack; 149 | long mm_struct_start_brk; 150 | long mm_struct_brk; 151 | long mm_struct_arg_start; 152 | long mm_struct_arg_end; 153 | long thread_info_flags; 154 | long vm_area_struct_vm_next; 155 | long vm_area_struct_vm_start; 156 | long vm_area_struct_vm_end; 157 | long vm_area_struct_vm_flags; 158 | long vm_area_struct_vm_file; 159 | long vm_area_struct_vm_pgoff; 160 | long vm_area_struct_anon_name; 161 | long vm_area_struct_anon_vma; 162 | long vm_area_struct_vm_mm; 163 | long vm_area_struct_detached; 164 | long task_struct_flags; 165 | long task_struct_thread; 166 | long thread_struct_sctlr_user; 167 | long thread_struct_mte_ctrl; 168 | long pt_regs; 169 | long swap_info_struct; 170 | long swap_info_struct_bdev; 171 | long swap_info_struct_swap_file; 172 | long swap_info_struct_swap_vfsmnt; 173 | long swap_info_struct_old_block_size; 174 | long swap_info_struct_pages; 175 | long block_device_bd_disk; 176 | long gendisk_private_data; 177 | long page; 178 | long page_private; 179 | long page_freelist; 180 | long page_index; 181 | long file_f_inode; 182 | long anon_vma_name_name; 183 | long inode_i_mapping; 184 | long address_space; 185 | long address_space_i_pages; 186 | long binder_proc; 187 | long binder_proc_pid; 188 | long binder_proc_context; 189 | long binder_proc_threads; 190 | long binder_proc_todo; 191 | long binder_context_name; 192 | long binder_thread; 193 | long binder_thread_pid; 194 | long binder_thread_looper; 195 | long binder_thread_looper_need_return; 196 | long binder_thread_tmp_ref; 197 | long binder_thread_transaction_stack; 198 | long binder_thread_proc; 199 | long binder_transaction; 200 | long binder_transaction_from; 201 | long binder_transaction_from_parent; 202 | long binder_transaction_to_thread; 203 | long binder_transaction_to_parent; 204 | long binder_transaction_to_proc; 205 | long binder_transaction_code; 206 | long binder_transaction_flags; 207 | long binder_transaction_priority; 208 | long binder_transaction_debug_id; 209 | long binder_transaction_need_reply; 210 | long binder_transaction_buffer; 211 | long binder_transaction_work; 212 | long binder_transaction_start_time; 213 | long binder_node_debug_id; 214 | long binder_node_work; 215 | long binder_node_ptr; 216 | long binder_node_cookie; 217 | long page_owner; 218 | long page_owner_order; 219 | long page_owner_gfp_mask; 220 | long page_owner_handle; 221 | long page_owner_ts_nsec; 222 | long page_owner_free_ts_nsec; 223 | long page_owner_comm; 224 | long page_owner_pid; 225 | long page_owner_tgid; 226 | long mem_section; 227 | long mem_section_page_ext; 228 | long page_ext; 229 | long page_ext_flags; 230 | long page_ext_operations_offset; 231 | long stack_record_entries; 232 | long stack_record_size; 233 | long tk_core; 234 | long tk_core_seq; 235 | long tk_core_timekeeper; 236 | long timekeeper_tkr_mono; 237 | long tk_read_base_base; 238 | long tk_read_base_xtime_nsec; 239 | long tk_read_base_shift; 240 | long trace_array_array_buffer; 241 | long trace_array_buffer_disabled; 242 | long trace_array_current_trace; 243 | long array_buffer_buffer; 244 | long trace_buffer_record_disabled; 245 | long tracer_name; 246 | 247 | // zram 248 | long zram; 249 | long zram_disksize; 250 | long zram_compressor; 251 | long zram_table; 252 | long zram_mem_pool; 253 | long zram_comp; 254 | long zram_comps; 255 | long zram_table_entry; 256 | long zram_table_entry_flags; 257 | long zram_table_entry_handle; 258 | long zram_table_entry_element; 259 | long zcomp_name; 260 | 261 | // zsmalloc 262 | long zspool_size_class; 263 | long size_class_size; 264 | long zspage_huge; 265 | }; 266 | 267 | extern struct parser_offset_table parser_offset_table; 268 | extern struct parser_size_table parser_size_table; 269 | 270 | typedef void (*parser_main)(); 271 | typedef void (*parser_usage)(); 272 | 273 | struct parser_commands { 274 | char* cmd; 275 | parser_main main; 276 | parser_usage usage; 277 | }; 278 | 279 | struct vma_cache_data { 280 | ulong vm_start; 281 | ulong vm_end; 282 | ulong vm_flags; 283 | ulong vm_pgoff; 284 | ulong vm_file; 285 | ulong anon_name; 286 | ulong anon_vma; 287 | ulong vm_mm; 288 | char buf[BUFSIZE]; 289 | }; 290 | 291 | uint64_t align_down(uint64_t x, uint64_t n); 292 | uint64_t align_up(uint64_t x, uint64_t n); 293 | void parser_convert_ascii(ulong value, char *ascii); 294 | int parser_vma_caches(struct task_context *tc, struct vma_cache_data **vma_cache); 295 | 296 | // crypto 297 | void *crypto_comp_get_decompress(const char* name); 298 | 299 | // sched 300 | const char* convert_sched(int i); 301 | 302 | #endif // PARSER_DEFS_H_ 303 | -------------------------------------------------------------------------------- /zram/zram_drv.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "zram.h" 4 | 5 | void parser_zram_obj_to_location(ulong obj, ulong *page, unsigned int* obj_idx) { 6 | ulong THE_OBJ_INDEX_BITS = OBJ_INDEX_BITS; 7 | ulong THE_OBJ_INDEX_MASK = OBJ_INDEX_MASK; 8 | if (THIS_KERNEL_VERSION >= LINUX(6,12,0)) { 9 | THE_OBJ_INDEX_BITS = (BITS_PER_LONG - (52 - PAGESHIFT())); 10 | THE_OBJ_INDEX_MASK = ((1 << THE_OBJ_INDEX_BITS) - 1); 11 | } else { 12 | obj >>= OBJ_TAG_BITS; 13 | } 14 | *page = 0x0; 15 | phys_to_page(PTOB(obj >> THE_OBJ_INDEX_BITS), page); 16 | *obj_idx = (obj & THE_OBJ_INDEX_MASK); 17 | } 18 | 19 | unsigned char *parser_zram_zs_map_object(ulong pool, ulong handle, unsigned char *zram_buf, ulong error_handle) { 20 | ulong obj, off, class, page, zspage; 21 | struct zspage zspage_s; 22 | physaddr_t paddr = 0; 23 | unsigned int obj_idx, class_idx, size; 24 | ulong pages[2] = {0, 0}; 25 | ulong sizes[2] = {0, 0}; 26 | ulong zs_magic = 0; 27 | obj = off = class = page = zspage = 0; 28 | 29 | readmem(handle, KVADDR, &obj, sizeof(void *), "zram entry", error_handle); 30 | parser_zram_obj_to_location(obj, &page, &obj_idx); 31 | if (!page) return NULL; 32 | 33 | readmem(page + PARSER_OFFSET(page_private), KVADDR, &zspage, 34 | PARSER_SIZE(page_private), "page_private", error_handle); 35 | 36 | readmem(zspage, KVADDR, &zspage_s, sizeof(struct zspage), "zspage", error_handle); 37 | if (PARSER_VALID_MEMBER(zspage_huge)) { 38 | if (THIS_KERNEL_VERSION >= LINUX(6,12,0)) { 39 | class_idx = zspage_s.v6_12.class; 40 | zs_magic = zspage_s.v6_12.magic; 41 | } else if (THIS_KERNEL_VERSION >= LINUX(6,6,0)) { 42 | class_idx = zspage_s.v6_6.class; 43 | zs_magic = zspage_s.v6_6.magic; 44 | } else { 45 | class_idx = zspage_s.v5_17.class; 46 | zs_magic = zspage_s.v5_17.magic; 47 | } 48 | } else { 49 | class_idx = zspage_s.v0.class; 50 | zs_magic = zspage_s.v0.magic; 51 | } 52 | 53 | if (zs_magic != ZSPAGE_MAGIC) { 54 | if (error_handle == FAULT_ON_ERROR) 55 | error(INFO, "0x%lx zspage magic incorrect: %x\n", zspage, zs_magic); 56 | return NULL; 57 | } 58 | 59 | class = pool + PARSER_OFFSET(zspool_size_class); 60 | class += (class_idx * sizeof(void *)); 61 | readmem(class, KVADDR, &class, sizeof(void *), "size_class", error_handle); 62 | readmem(class + PARSER_OFFSET(size_class_size), KVADDR, 63 | &size, sizeof(unsigned int), "size of class_size", error_handle); 64 | off = (size * obj_idx) & (~machdep->pagemask); 65 | if (off + size <= PAGESIZE()) { 66 | if (!is_page_ptr(page, &paddr)) { 67 | if (error_handle == FAULT_ON_ERROR) 68 | error(INFO, "zspage: %lx: not a page pointer\n", page); 69 | return NULL; 70 | } 71 | readmem(paddr + off, PHYSADDR, zram_buf, size, "zram buffer", error_handle); 72 | goto out; 73 | } 74 | 75 | pages[0] = page; 76 | if (PARSER_VALID_MEMBER(page_freelist)) { 77 | readmem(page + PARSER_OFFSET(page_freelist), KVADDR, &pages[1], 78 | sizeof(void *), "page_freelist", error_handle); 79 | } else { 80 | readmem(page + PARSER_OFFSET(page_index), KVADDR, &pages[1], 81 | sizeof(void *), "page_index", error_handle); 82 | } 83 | 84 | sizes[0] = PAGESIZE() - off; 85 | sizes[1] = size - sizes[0]; 86 | if (!is_page_ptr(pages[0], &paddr)) { 87 | if (error_handle == FAULT_ON_ERROR) 88 | error(INFO, "pages[0]: %lx: not a page pointer\n", pages[0]); 89 | return NULL; 90 | } 91 | 92 | readmem(paddr + off, PHYSADDR, zram_buf, sizes[0], "zram buffer[0]", error_handle); 93 | if (!is_page_ptr(pages[1], &paddr)) { 94 | if (error_handle == FAULT_ON_ERROR) 95 | error(INFO, "pages[1]: %lx: not a page pointer\n", pages[1]); 96 | return NULL; 97 | } 98 | 99 | readmem(paddr, PHYSADDR, zram_buf + sizes[0], sizes[1], "zram buffer[1]", error_handle); 100 | 101 | out: 102 | if (!PARSER_VALID_MEMBER(zspage_huge)) { 103 | readmem(page, KVADDR, &obj, sizeof(void *), "page flags", error_handle); 104 | if (!(obj & (1 << 10))) { //PG_OwnerPriv1 flag 105 | return (zram_buf + ZS_HANDLE_SIZE); 106 | } 107 | } else { 108 | if (!zspage_s.v5_17.huge) { 109 | return (zram_buf + ZS_HANDLE_SIZE); 110 | } 111 | } 112 | return zram_buf; 113 | } 114 | 115 | int parser_zram_read_swap_page_cache(ulong swap_type, ulong zram_offset, unsigned char* value, ulong error_handle) { 116 | ulong swp_space; 117 | physaddr_t paddr; 118 | ulong xarray; 119 | ulong root_rnode; 120 | 121 | if (swap_type >= parser_get_swap_total()) 122 | return 0; 123 | 124 | if (!pagecache_data_cache[swap_type].space) 125 | return 0; 126 | 127 | int idx = zram_offset >> SWAP_ADDRESS_SPACE_SHIFT; 128 | if (idx >= pagecache_data_cache[swap_type].cache_count) 129 | return 0; 130 | 131 | ulong page_value = 0; 132 | if (!pagecache_data_cache[swap_type].cache[idx].page_count) { 133 | swp_space = pagecache_data_cache[swap_type].space + idx * PARSER_SIZE(address_space); 134 | 135 | xarray = root_rnode = 0; 136 | if (MEMBER_EXISTS("address_space", "i_pages") && 137 | (STREQ(MEMBER_TYPE_NAME("address_space", "i_pages"), "xarray") || 138 | (STREQ(MEMBER_TYPE_NAME("address_space", "i_pages"), "radix_tree_root") && 139 | MEMBER_EXISTS("radix_tree_root", "xa_head")))) 140 | xarray = swp_space + PARSER_OFFSET(address_space_i_pages); 141 | else 142 | root_rnode = swp_space + PARSER_OFFSET(address_space_i_pages); 143 | 144 | if (IS_KVADDR(root_rnode)) 145 | pagecache_data_cache[swap_type].cache[idx].page_count = do_radix_tree(root_rnode, RADIX_TREE_COUNT, NULL); 146 | else if (IS_KVADDR(xarray)) 147 | pagecache_data_cache[swap_type].cache[idx].page_count = do_xarray(xarray, XARRAY_COUNT, NULL); 148 | else 149 | return 0; 150 | 151 | if (pagecache_data_cache[swap_type].cache[idx].page_count) { 152 | pagecache_data_cache[swap_type].cache[idx].pages = (struct list_pair *)malloc(sizeof(struct list_pair) * pagecache_data_cache[swap_type].cache[idx].page_count); 153 | BZERO(pagecache_data_cache[swap_type].cache[idx].pages, sizeof(struct list_pair) * pagecache_data_cache[swap_type].cache[idx].page_count); 154 | 155 | if (IS_KVADDR(root_rnode)) 156 | do_radix_tree(root_rnode, RADIX_TREE_GATHER, pagecache_data_cache[swap_type].cache[idx].pages); 157 | else if (IS_KVADDR(xarray)) 158 | do_xarray(xarray, XARRAY_GATHER, pagecache_data_cache[swap_type].cache[idx].pages); 159 | else 160 | return 0; 161 | } 162 | } 163 | 164 | for (int index = 0; index < pagecache_data_cache[swap_type].cache[idx].page_count; ++index) { 165 | if (pagecache_data_cache[swap_type].cache[idx].pages[index].index == zram_offset) { 166 | page_value = (ulong)pagecache_data_cache[swap_type].cache[idx].pages[index].value; 167 | break; 168 | } 169 | } 170 | 171 | if (page_value) { 172 | if (page_value & 1) { 173 | return 0; 174 | } 175 | if (!is_page_ptr(page_value, &paddr)) { 176 | return 0; 177 | } 178 | readmem(paddr, PHYSADDR, value, PAGESIZE(), "zram buffer", error_handle); 179 | return 1; 180 | } 181 | return 0; 182 | } 183 | 184 | int parser_zram_read_page(int swap_index, ulong zram_offset, unsigned char* value, ulong error_handle) { 185 | unsigned char *src = NULL; 186 | unsigned char *zram_buf = NULL; 187 | unsigned char *entry_buf = NULL; 188 | 189 | if (swap_index >= parser_get_swap_total()) 190 | return 0; 191 | 192 | if (zram_offset > zram_data_cache[swap_index].pages) 193 | return 0; 194 | 195 | ulong outsize = 0; 196 | ulong sector = 0; 197 | ulong index = 0; 198 | ulong entry = 0; 199 | ulong flags = 0; 200 | ulong objsize = 0; 201 | ulong handle = 0; 202 | ulong element = 0; 203 | ulong prio = 0; 204 | 205 | sector = zram_offset << (PAGESHIFT() - 9); 206 | index = sector >> SECTORS_PER_PAGE_SHIFT; 207 | outsize = PAGESIZE(); 208 | 209 | // zram_table_entry parse 210 | entry = zram_data_cache[swap_index].table + index * PARSER_SIZE(zram_table_entry); 211 | entry_buf = (unsigned char *)malloc(PARSER_SIZE(zram_table_entry)); 212 | BZERO(entry_buf, PARSER_SIZE(zram_table_entry)); 213 | readmem(entry, KVADDR, entry_buf, PARSER_SIZE(zram_table_entry), "zram_table_entry", error_handle); 214 | flags = ULONG(entry_buf + PARSER_OFFSET(zram_table_entry_flags)); 215 | handle = ULONG(entry_buf + PARSER_OFFSET(zram_table_entry_handle)); // handle or entry 216 | element = ULONG(entry_buf + PARSER_OFFSET(zram_table_entry_element)); 217 | free(entry_buf); 218 | 219 | objsize = flags & (PARSER_ZRAM_FLAG_SHIFT - 1); 220 | 221 | // avoid having some idiot make changes that mess up the flags formatting. 222 | if (objsize > PAGESIZE()) 223 | objsize &= (PAGESIZE() - 1); 224 | 225 | if (zram_data_cache[swap_index].comp_count > 1) 226 | prio = (flags >> PARSER_ZRAM_COMP_PRIORITY_BIT1) & PARSER_ZRAM_COMP_PRIORITY_MASK; 227 | 228 | // ZRAM_WB 229 | if ((flags & PARSER_ZRAM_FLAG_WB_BIT) || !handle) { 230 | // try look swapcache 231 | if (parser_zram_read_swap_page_cache(swap_index, zram_offset, value, error_handle)) { 232 | return 1; 233 | } else { 234 | if (error_handle == FAULT_ON_ERROR) 235 | error(INFO, "Not support read zram offset %ld. (flags = %lx, handle = %lx)\n" 236 | , zram_offset, flags, handle); 237 | return 0; 238 | } 239 | } 240 | 241 | // ZRAM_SAME 242 | if (flags & PARSER_ZRAM_FLAG_SAME_BIT) { 243 | unsigned long *same_buf = NULL; 244 | unsigned long buf = handle ? element : 0; 245 | same_buf = (unsigned long *)malloc(PAGESIZE()); 246 | for (int count = 0; count < PAGESIZE() / sizeof(unsigned long); count++) { 247 | same_buf[count] = buf; 248 | } 249 | memcpy(value, same_buf, outsize); 250 | free(same_buf); 251 | return 1; 252 | } 253 | 254 | zram_buf = (unsigned char *)malloc(PAGESIZE()); 255 | BZERO(zram_buf, PAGESIZE()); 256 | src = parser_zram_zs_map_object(zram_data_cache[swap_index].mem_pool, handle, zram_buf, error_handle); 257 | if (!src) { 258 | free(zram_buf); 259 | return 0; 260 | } 261 | 262 | if (objsize == PAGESIZE()) { 263 | memcpy(value, src, outsize); 264 | } else { 265 | if (zram_data_cache[swap_index].decompress[prio]) 266 | zram_data_cache[swap_index].decompress[prio](src, value, objsize, outsize); 267 | } 268 | free(zram_buf); 269 | return 1; 270 | } 271 | -------------------------------------------------------------------------------- /core/core32.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "core.h" 4 | #include "zram/zram.h" 5 | #include "shmem/shmem.h" 6 | #include "parser_defs.h" 7 | #include 8 | 9 | void parser_core_header32(struct core_data_t* core_data, Elf32_Ehdr *ehdr) { 10 | snprintf((char *)ehdr->e_ident, 5, ELFMAG); 11 | ehdr->e_ident[EI_CLASS] = ELFCLASS32; 12 | ehdr->e_ident[EI_DATA] = ELFDATA2LSB; 13 | ehdr->e_ident[EI_VERSION] = EV_CURRENT; 14 | 15 | ehdr->e_type = ET_CORE; 16 | ehdr->e_machine = core_data->machine; 17 | ehdr->e_version = EV_CURRENT; 18 | ehdr->e_entry = 0x0; 19 | ehdr->e_phoff = sizeof(Elf32_Ehdr); 20 | ehdr->e_shoff = 0x0; 21 | ehdr->e_flags = 0x0; 22 | ehdr->e_ehsize = sizeof(Elf32_Ehdr); 23 | ehdr->e_phentsize = sizeof(Elf32_Phdr); 24 | ehdr->e_phnum = core_data->phnum; 25 | ehdr->e_shentsize = 0x0; 26 | ehdr->e_shnum = 0x0; 27 | ehdr->e_shstrndx = 0x0; 28 | } 29 | 30 | void parser_write_core_header32(struct core_data_t* core_data, Elf32_Ehdr *ehdr) { 31 | fwrite(ehdr, sizeof(Elf32_Ehdr), 1, core_data->fp); 32 | } 33 | 34 | void parser_core_note32(struct core_data_t* core_data, Elf32_Phdr *note) { 35 | note->p_type = PT_NOTE; 36 | note->p_offset = sizeof(Elf32_Ehdr) + core_data->phnum * sizeof(Elf32_Phdr); 37 | } 38 | 39 | void parser_write_core_note32(struct core_data_t* core_data, Elf32_Phdr *note) { 40 | note->p_filesz += (core_data->prstatus_sizeof + sizeof(Elf32_Nhdr) + 8) * core_data->prnum; 41 | note->p_filesz += sizeof(Elf32_auxv) * core_data->auxvnum + sizeof(Elf32_Nhdr) + 8; 42 | note->p_filesz += core_data->extra_note_filesz; 43 | note->p_filesz += sizeof(Elf32_ntfile) * core_data->vma_count + sizeof(Elf32_Nhdr) + 8 + 2 * 4 + align_up(core_data->fileslen, 4); 44 | fwrite(note, sizeof(Elf32_Phdr), 1, core_data->fp); 45 | } 46 | 47 | void parser_core_prstatus32(struct core_data_t* core_data) { 48 | int tgid = task_tgid(core_data->tc->task); 49 | struct task_context *tc = FIRST_CONTEXT(); 50 | for (int i = core_data->prnum = 0; i < RUNNING_TASKS(); i++, tc++) { 51 | if (task_tgid(tc->task) == tgid) { 52 | core_data->prnum++; 53 | } 54 | } 55 | core_data->parser_core_prstatus(core_data); 56 | } 57 | 58 | void parser_core_auxv32(struct core_data_t* core_data) { 59 | core_data->auxvnum = PARSER_SIZE(mm_struct_saved_auxv) / sizeof(Elf32_auxv); 60 | 61 | core_data->auxv_cache = malloc(core_data->auxvnum * sizeof(Elf32_auxv)); 62 | struct task_mem_usage task_mem_usage, *tm; 63 | tm = &task_mem_usage; 64 | get_task_mem_usage(core_data->tc->task, tm); 65 | readmem(tm->mm_struct_addr + PARSER_OFFSET(mm_struct_saved_auxv), KVADDR, 66 | core_data->auxv_cache, core_data->auxvnum * sizeof(Elf32_auxv), "mm_struct saved_auxv", core_data->error_handle); 67 | } 68 | 69 | void parser_core_load_vma32(struct core_data_t* core_data, int index) { 70 | Elf32_Phdr* phdr = &((Elf32_Phdr* )core_data->load_cache)[index]; 71 | memset(phdr, 0x0, sizeof(Elf32_Phdr)); 72 | 73 | phdr->p_type = PT_LOAD; 74 | phdr->p_vaddr = (Elf32_Addr)core_data->vma_cache[index].vm_start; 75 | phdr->p_paddr = 0x0; 76 | phdr->p_memsz = (Elf32_Addr)core_data->vma_cache[index].vm_end 77 | - (Elf32_Addr)core_data->vma_cache[index].vm_start; 78 | 79 | phdr->p_flags = 0x0; 80 | if (core_data->vma_cache[index].vm_flags & VM_READ) 81 | phdr->p_flags |= PF_R; 82 | 83 | if (core_data->vma_cache[index].vm_flags & VM_WRITE) 84 | phdr->p_flags |= PF_W; 85 | 86 | if (core_data->vma_cache[index].vm_flags & VM_EXEC) 87 | phdr->p_flags |= PF_X; 88 | 89 | phdr->p_align = core_data->align_size; 90 | 91 | if (!core_data->filter_vma(core_data, index)) 92 | phdr->p_filesz = phdr->p_memsz; 93 | } 94 | 95 | void parser_write_core_program_headers32(struct core_data_t* core_data, Elf32_Phdr *note) { 96 | if (!core_data->vma_count) return; 97 | 98 | Elf32_Phdr* prev; 99 | parser_core_load_vma32(core_data, 0); 100 | Elf32_Phdr* phdr = &((Elf32_Phdr*)core_data->load_cache)[0]; 101 | phdr->p_offset = align_up(note->p_offset + note->p_filesz, core_data->align_size); 102 | fwrite(phdr, sizeof(Elf32_Phdr), 1, core_data->fp); 103 | 104 | for (int index = 1; index < core_data->vma_count; ++index) { 105 | prev = &((Elf32_Phdr*)core_data->load_cache)[index - 1]; 106 | phdr = &((Elf32_Phdr*)core_data->load_cache)[index]; 107 | parser_core_load_vma32(core_data, index); 108 | phdr->p_offset = prev->p_offset + prev->p_filesz; 109 | fwrite(phdr, sizeof(Elf32_Phdr), 1, core_data->fp); 110 | } 111 | } 112 | 113 | void parser_write_core_auxv32(struct core_data_t* core_data) { 114 | Elf32_Nhdr nhdr; 115 | nhdr.n_namesz = NOTE_CORE_NAME_SZ; 116 | nhdr.n_descsz = sizeof(Elf32_auxv) * core_data->auxvnum; 117 | nhdr.n_type = NT_AUXV; 118 | 119 | char magic[8]; 120 | memset(magic, 0, sizeof(magic)); 121 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC); 122 | 123 | fwrite(&nhdr, sizeof(Elf32_Nhdr), 1, core_data->fp); 124 | fwrite(magic, sizeof(magic), 1, core_data->fp); 125 | 126 | int index = 0; 127 | while (index < core_data->auxvnum) { 128 | fwrite((char *)core_data->auxv_cache + index * sizeof(Elf32_auxv), sizeof(Elf32_auxv), 1, core_data->fp); 129 | index++; 130 | } 131 | } 132 | 133 | void parser_write_core_file32(struct core_data_t* core_data, Elf32_Phdr *note) { 134 | Elf32_Nhdr nhdr; 135 | nhdr.n_namesz = NOTE_CORE_NAME_SZ; 136 | nhdr.n_descsz = sizeof(Elf32_ntfile) * core_data->vma_count + 2 * 4 + align_up(core_data->fileslen, 4); 137 | nhdr.n_type = NT_FILE; 138 | 139 | char magic[8]; 140 | memset(magic, 0, sizeof(magic)); 141 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC); 142 | 143 | fwrite(&nhdr, sizeof(Elf32_Nhdr), 1, core_data->fp); 144 | fwrite(magic, sizeof(magic), 1, core_data->fp); 145 | 146 | uint32_t number = core_data->vma_count; 147 | fwrite(&number, 4, 1, core_data->fp); 148 | uint32_t page_size = core_data->page_size; 149 | fwrite(&page_size, 4, 1, core_data->fp); 150 | 151 | int index = 0; 152 | while(index < core_data->vma_count) { 153 | Elf32_ntfile ntfile; 154 | ntfile.start = core_data->vma_cache[index].vm_start; 155 | ntfile.end = core_data->vma_cache[index].vm_end; 156 | ntfile.fileofs = 0x0; 157 | if (core_data->vma_cache[index].vm_file) 158 | ntfile.fileofs = core_data->vma_cache[index].vm_pgoff; 159 | fwrite(&ntfile, sizeof(Elf32_ntfile), 1, core_data->fp); 160 | index++; 161 | } 162 | 163 | index = 0; 164 | while(index < core_data->vma_count) { 165 | fwrite(core_data->vma_cache[index].buf, 166 | strlen(core_data->vma_cache[index].buf) + 1, 167 | 1, core_data->fp); 168 | index++; 169 | } 170 | } 171 | 172 | void parser_core_note_align32(struct core_data_t* core_data, Elf32_Phdr *note) { 173 | memset(core_data->zero_buf, 0x0, core_data->align_size); 174 | uint32_t align_filesz = note->p_filesz - align_up(core_data->fileslen, 4) + core_data->fileslen; 175 | uint32_t offset = align_up(note->p_offset + align_filesz, core_data->align_size); 176 | uint32_t size = offset - (note->p_offset + align_filesz); 177 | fwrite(core_data->zero_buf, size, 1, core_data->fp); 178 | } 179 | 180 | void parser_write_core_load32(struct core_data_t* core_data) { 181 | physaddr_t paddr; 182 | uint32_t vaddr; 183 | int idx, i; 184 | struct list_pair *shmem_page_list; 185 | int shmem_page_count; 186 | 187 | for (idx = 0; idx < core_data->vma_count; ++idx) { 188 | Elf32_Phdr* phdr = &((Elf32_Phdr*)core_data->load_cache)[idx]; 189 | if (!phdr->p_filesz) continue; 190 | 191 | // shmem cache init 192 | shmem_page_count = 0; 193 | shmem_page_list = NULL; 194 | 195 | int count = phdr->p_memsz / core_data->page_size; 196 | for (i = 0; i < count; ++i) { 197 | memset(core_data->page_buf, 0x0, core_data->page_size); 198 | vaddr = phdr->p_vaddr + i * core_data->page_size; 199 | paddr = (physaddr_t)0x0; 200 | int page_exist = uvtop(core_data->tc, vaddr, &paddr, 0); 201 | 202 | if (paddr) { 203 | if (page_exist) { 204 | readmem(paddr, PHYSADDR, core_data->page_buf, core_data->page_size, "write load32", QUIET); 205 | } else if (core_data->parse_zram) { 206 | ulong zram_offset = SWP_OFFSET(paddr); 207 | ulong swap_type = SWP_TYPE(paddr); 208 | parser_zram_read_page(swap_type, zram_offset, core_data->page_buf, QUIET); 209 | } 210 | } else { 211 | if (core_data->parse_shmem) { 212 | if (!shmem_page_list) { 213 | shmem_page_count = parser_shmem_get_page_cache(&core_data->vma_cache[idx], &shmem_page_list, QUIET); 214 | } 215 | 216 | if (shmem_page_count) { 217 | parser_shmem_read_page_cache(vaddr, &core_data->vma_cache[idx], shmem_page_count, 218 | shmem_page_list, core_data->page_buf, QUIET); 219 | } 220 | } 221 | } 222 | fwrite(core_data->page_buf, core_data->page_size, 1, core_data->fp); 223 | } 224 | if (shmem_page_list) free(shmem_page_list); 225 | } 226 | } 227 | 228 | void parser_core_dump32(struct core_data_t* core_data) { 229 | Elf32_Ehdr ehdr; 230 | Elf32_Phdr note; 231 | memset(&ehdr, 0, sizeof(Elf32_Ehdr)); 232 | memset(¬e, 0, sizeof(Elf32_Phdr)); 233 | 234 | char* corefile = NULL; 235 | char filename[32]; 236 | if (core_data->file) { 237 | corefile = core_data->file; 238 | } else { 239 | snprintf(filename, sizeof(filename), "%d.core", core_data->pid); 240 | corefile = filename; 241 | } 242 | 243 | core_data->fp = fopen(corefile, "wb"); 244 | if (!core_data->fp) { 245 | error(INFO, "Can't open %s\n", corefile); 246 | return; 247 | } 248 | 249 | core_data->vma_count = parser_vma_caches(core_data->tc, &core_data->vma_cache); 250 | core_data->load_cache = malloc(core_data->vma_count * sizeof(Elf32_Phdr)); 251 | core_data->phnum = core_data->vma_count + 1; 252 | core_data->fill_vma_name(core_data); 253 | parser_core_header32(core_data, &ehdr); 254 | parser_core_note32(core_data, ¬e); 255 | parser_core_prstatus32(core_data); 256 | parser_core_auxv32(core_data); 257 | 258 | parser_write_core_header32(core_data, &ehdr); 259 | parser_write_core_note32(core_data, ¬e); 260 | parser_write_core_program_headers32(core_data, ¬e); 261 | core_data->parser_write_core_prstatus(core_data); 262 | parser_write_core_auxv32(core_data); 263 | parser_write_core_file32(core_data, ¬e); 264 | parser_core_note_align32(core_data, ¬e); 265 | parser_write_core_load32(core_data); 266 | 267 | fprintf(fp, "Saved [%s].\n", corefile); 268 | core_data->clean(core_data); 269 | } 270 | -------------------------------------------------------------------------------- /core/core64.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "core.h" 4 | #include "zram/zram.h" 5 | #include "shmem/shmem.h" 6 | #include "parser_defs.h" 7 | #include 8 | 9 | void parser_core_header64(struct core_data_t* core_data, Elf64_Ehdr *ehdr) { 10 | snprintf((char *)ehdr->e_ident, 5, ELFMAG); 11 | ehdr->e_ident[EI_CLASS] = ELFCLASS64; 12 | ehdr->e_ident[EI_DATA] = ELFDATA2LSB; 13 | ehdr->e_ident[EI_VERSION] = EV_CURRENT; 14 | 15 | ehdr->e_type = ET_CORE; 16 | ehdr->e_machine = core_data->machine; 17 | ehdr->e_version = EV_CURRENT; 18 | ehdr->e_entry = 0x0; 19 | ehdr->e_phoff = sizeof(Elf64_Ehdr); 20 | ehdr->e_shoff = 0x0; 21 | ehdr->e_flags = 0x0; 22 | ehdr->e_ehsize = sizeof(Elf64_Ehdr); 23 | ehdr->e_phentsize = sizeof(Elf64_Phdr); 24 | ehdr->e_phnum = core_data->phnum; 25 | ehdr->e_shentsize = 0x0; 26 | ehdr->e_shnum = 0x0; 27 | ehdr->e_shstrndx = 0x0; 28 | } 29 | 30 | void parser_write_core_header64(struct core_data_t* core_data, Elf64_Ehdr *ehdr) { 31 | fwrite(ehdr, sizeof(Elf64_Ehdr), 1, core_data->fp); 32 | } 33 | 34 | void parser_core_note64(struct core_data_t* core_data, Elf64_Phdr *note) { 35 | note->p_type = PT_NOTE; 36 | note->p_offset = sizeof(Elf64_Ehdr) + core_data->phnum * sizeof(Elf64_Phdr); 37 | } 38 | 39 | void parser_write_core_note64(struct core_data_t* core_data, Elf64_Phdr *note) { 40 | note->p_filesz += (core_data->prstatus_sizeof + sizeof(Elf64_Nhdr) + 8) * core_data->prnum; 41 | note->p_filesz += sizeof(Elf64_auxv) * core_data->auxvnum + sizeof(Elf64_Nhdr) + 8; 42 | note->p_filesz += core_data->extra_note_filesz; 43 | note->p_filesz += sizeof(Elf64_ntfile) * core_data->vma_count + sizeof(Elf64_Nhdr) + 8 + 2 * 8 + align_up(core_data->fileslen, 4); 44 | fwrite(note, sizeof(Elf64_Phdr), 1, core_data->fp); 45 | } 46 | 47 | void parser_core_prstatus64(struct core_data_t* core_data) { 48 | int tgid = task_tgid(core_data->tc->task); 49 | struct task_context *tc = FIRST_CONTEXT(); 50 | for (int i = core_data->prnum = 0; i < RUNNING_TASKS(); i++, tc++) { 51 | if (task_tgid(tc->task) == tgid) { 52 | core_data->prnum++; 53 | } 54 | } 55 | core_data->parser_core_prstatus(core_data); 56 | } 57 | 58 | void parser_core_auxv64(struct core_data_t* core_data) { 59 | core_data->auxvnum = PARSER_SIZE(mm_struct_saved_auxv) / sizeof(Elf64_auxv); 60 | 61 | core_data->auxv_cache = malloc(core_data->auxvnum * sizeof(Elf64_auxv)); 62 | struct task_mem_usage task_mem_usage, *tm; 63 | tm = &task_mem_usage; 64 | get_task_mem_usage(core_data->tc->task, tm); 65 | readmem(tm->mm_struct_addr + PARSER_OFFSET(mm_struct_saved_auxv), KVADDR, 66 | core_data->auxv_cache, core_data->auxvnum * sizeof(Elf64_auxv), "mm_struct saved_auxv", core_data->error_handle); 67 | } 68 | 69 | void parser_core_load_vma64(struct core_data_t* core_data, int index) { 70 | Elf64_Phdr* phdr = &((Elf64_Phdr* )core_data->load_cache)[index]; 71 | memset(phdr, 0x0, sizeof(Elf64_Phdr)); 72 | 73 | phdr->p_type = PT_LOAD; 74 | phdr->p_vaddr = (Elf64_Addr)core_data->vma_cache[index].vm_start; 75 | phdr->p_paddr = 0x0; 76 | phdr->p_memsz = (Elf64_Addr)core_data->vma_cache[index].vm_end 77 | - (Elf64_Addr)core_data->vma_cache[index].vm_start; 78 | 79 | phdr->p_flags = 0x0; 80 | if (core_data->vma_cache[index].vm_flags & VM_READ) 81 | phdr->p_flags |= PF_R; 82 | 83 | if (core_data->vma_cache[index].vm_flags & VM_WRITE) 84 | phdr->p_flags |= PF_W; 85 | 86 | if (core_data->vma_cache[index].vm_flags & VM_EXEC) 87 | phdr->p_flags |= PF_X; 88 | 89 | phdr->p_align = core_data->align_size; 90 | 91 | if (!core_data->filter_vma(core_data, index)) 92 | phdr->p_filesz = phdr->p_memsz; 93 | } 94 | 95 | void parser_write_core_program_headers64(struct core_data_t* core_data, Elf64_Phdr *note) { 96 | if (!core_data->vma_count) return; 97 | 98 | Elf64_Phdr* prev; 99 | parser_core_load_vma64(core_data, 0); 100 | Elf64_Phdr* phdr = &((Elf64_Phdr*)core_data->load_cache)[0]; 101 | phdr->p_offset = align_up(note->p_offset + note->p_filesz, core_data->align_size); 102 | fwrite(phdr, sizeof(Elf64_Phdr), 1, core_data->fp); 103 | 104 | for (int index = 1; index < core_data->vma_count; ++index) { 105 | prev = &((Elf64_Phdr*)core_data->load_cache)[index - 1]; 106 | phdr = &((Elf64_Phdr*)core_data->load_cache)[index]; 107 | parser_core_load_vma64(core_data, index); 108 | phdr->p_offset = prev->p_offset + prev->p_filesz; 109 | fwrite(phdr, sizeof(Elf64_Phdr), 1, core_data->fp); 110 | } 111 | } 112 | 113 | void parser_write_core_auxv64(struct core_data_t* core_data) { 114 | Elf64_Nhdr nhdr; 115 | nhdr.n_namesz = NOTE_CORE_NAME_SZ; 116 | nhdr.n_descsz = sizeof(Elf64_auxv) * core_data->auxvnum; 117 | nhdr.n_type = NT_AUXV; 118 | 119 | char magic[8]; 120 | memset(magic, 0, sizeof(magic)); 121 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC); 122 | 123 | fwrite(&nhdr, sizeof(Elf64_Nhdr), 1, core_data->fp); 124 | fwrite(magic, sizeof(magic), 1, core_data->fp); 125 | 126 | int index = 0; 127 | while (index < core_data->auxvnum) { 128 | fwrite((char *)core_data->auxv_cache + index * sizeof(Elf64_auxv), sizeof(Elf64_auxv), 1, core_data->fp); 129 | index++; 130 | } 131 | } 132 | 133 | void parser_write_core_file64(struct core_data_t* core_data, Elf64_Phdr *note) { 134 | Elf64_Nhdr nhdr; 135 | nhdr.n_namesz = NOTE_CORE_NAME_SZ; 136 | nhdr.n_descsz = sizeof(Elf64_ntfile) * core_data->vma_count + 2 * 8 + align_up(core_data->fileslen, 4); 137 | nhdr.n_type = NT_FILE; 138 | 139 | char magic[8]; 140 | memset(magic, 0, sizeof(magic)); 141 | snprintf(magic, NOTE_CORE_NAME_SZ, ELFCOREMAGIC); 142 | 143 | fwrite(&nhdr, sizeof(Elf64_Nhdr), 1, core_data->fp); 144 | fwrite(magic, sizeof(magic), 1, core_data->fp); 145 | 146 | uint64_t number = core_data->vma_count; 147 | fwrite(&number, 8, 1, core_data->fp); 148 | uint64_t page_size = core_data->page_size; 149 | fwrite(&page_size, 8, 1, core_data->fp); 150 | 151 | int index = 0; 152 | while(index < core_data->vma_count) { 153 | Elf64_ntfile ntfile; 154 | ntfile.start = core_data->vma_cache[index].vm_start; 155 | ntfile.end = core_data->vma_cache[index].vm_end; 156 | ntfile.fileofs = 0x0; 157 | if (core_data->vma_cache[index].vm_file) 158 | ntfile.fileofs = core_data->vma_cache[index].vm_pgoff; 159 | fwrite(&ntfile, sizeof(Elf64_ntfile), 1, core_data->fp); 160 | index++; 161 | } 162 | 163 | index = 0; 164 | while(index < core_data->vma_count) { 165 | fwrite(core_data->vma_cache[index].buf, 166 | strlen(core_data->vma_cache[index].buf) + 1, 167 | 1, core_data->fp); 168 | index++; 169 | } 170 | } 171 | 172 | void parser_core_note_align64(struct core_data_t* core_data, Elf64_Phdr *note) { 173 | memset(core_data->zero_buf, 0x0, core_data->align_size); 174 | uint64_t align_filesz = note->p_filesz - align_up(core_data->fileslen, 4) + core_data->fileslen; 175 | uint64_t offset = align_up(note->p_offset + align_filesz, core_data->align_size); 176 | uint64_t size = offset - (note->p_offset + align_filesz); 177 | fwrite(core_data->zero_buf, size, 1, core_data->fp); 178 | } 179 | 180 | void parser_write_core_load64(struct core_data_t* core_data) { 181 | physaddr_t paddr; 182 | uint64_t vaddr; 183 | int idx, i; 184 | struct list_pair *shmem_page_list; 185 | int shmem_page_count; 186 | 187 | for (idx = 0; idx < core_data->vma_count; ++idx) { 188 | Elf64_Phdr* phdr = &((Elf64_Phdr*)core_data->load_cache)[idx]; 189 | if (!phdr->p_filesz) continue; 190 | 191 | // shmem cache init 192 | shmem_page_count = 0; 193 | shmem_page_list = NULL; 194 | 195 | int count = phdr->p_memsz / core_data->page_size; 196 | for (i = 0; i < count; ++i) { 197 | memset(core_data->page_buf, 0x0, core_data->page_size); 198 | vaddr = phdr->p_vaddr + i * core_data->page_size; 199 | paddr = (physaddr_t)0x0; 200 | int page_exist = uvtop(core_data->tc, vaddr, &paddr, 0); 201 | 202 | if (paddr) { 203 | if (page_exist) { 204 | readmem(paddr, PHYSADDR, core_data->page_buf, core_data->page_size, "write load64", QUIET); 205 | } else if (core_data->parse_zram) { 206 | ulong zram_offset = SWP_OFFSET(paddr); 207 | ulong swap_type = SWP_TYPE(paddr); 208 | parser_zram_read_page(swap_type, zram_offset, core_data->page_buf, QUIET); 209 | } 210 | } else { 211 | if (core_data->parse_shmem) { 212 | if (!shmem_page_list) { 213 | shmem_page_count = parser_shmem_get_page_cache(&core_data->vma_cache[idx], &shmem_page_list, QUIET); 214 | } 215 | 216 | if (shmem_page_count) { 217 | parser_shmem_read_page_cache(vaddr, &core_data->vma_cache[idx], shmem_page_count, 218 | shmem_page_list, core_data->page_buf, QUIET); 219 | } 220 | } 221 | } 222 | fwrite(core_data->page_buf, core_data->page_size, 1, core_data->fp); 223 | } 224 | if (shmem_page_list) free(shmem_page_list); 225 | } 226 | } 227 | 228 | void parser_core_dump64(struct core_data_t* core_data) { 229 | Elf64_Ehdr ehdr; 230 | Elf64_Phdr note; 231 | memset(&ehdr, 0, sizeof(Elf64_Ehdr)); 232 | memset(¬e, 0, sizeof(Elf64_Phdr)); 233 | 234 | char* corefile = NULL; 235 | char filename[32]; 236 | if (core_data->file) { 237 | corefile = core_data->file; 238 | } else { 239 | snprintf(filename, sizeof(filename), "%d.core", core_data->pid); 240 | corefile = filename; 241 | } 242 | 243 | core_data->fp = fopen(corefile, "wb"); 244 | if (!core_data->fp) { 245 | error(INFO, "Can't open %s\n", corefile); 246 | return; 247 | } 248 | 249 | core_data->vma_count = parser_vma_caches(core_data->tc, &core_data->vma_cache); 250 | core_data->load_cache = malloc(core_data->vma_count * sizeof(Elf64_Phdr)); 251 | core_data->phnum = core_data->vma_count + 1; 252 | core_data->fill_vma_name(core_data); 253 | parser_core_header64(core_data, &ehdr); 254 | parser_core_note64(core_data, ¬e); 255 | parser_core_prstatus64(core_data); 256 | parser_core_auxv64(core_data); 257 | 258 | parser_write_core_header64(core_data, &ehdr); 259 | parser_write_core_note64(core_data, ¬e); 260 | parser_write_core_program_headers64(core_data, ¬e); 261 | core_data->parser_write_core_prstatus(core_data); 262 | parser_write_core_auxv64(core_data); 263 | parser_write_core_file64(core_data, ¬e); 264 | parser_core_note_align64(core_data, ¬e); 265 | parser_write_core_load64(core_data); 266 | 267 | fprintf(fp, "Saved [%s].\n", corefile); 268 | core_data->clean(core_data); 269 | } 270 | -------------------------------------------------------------------------------- /pageowner/page_owner.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "page_owner.h" 4 | #include "bits.h" 5 | #include 6 | #include 7 | #include 8 | 9 | int parser_page_owner_data_init(struct pageowner_data_t* pageowner_data) { 10 | pageowner_data->CONFIG_PAGE_EXTENSION = get_kernel_config("CONFIG_PAGE_EXTENSION", NULL); 11 | if (pageowner_data->CONFIG_PAGE_EXTENSION == IKCONFIG_N) 12 | return -1; 13 | 14 | pageowner_data->CONFIG_SPARSEMEM_EXTREME = get_kernel_config("CONFIG_SPARSEMEM_EXTREME", NULL); 15 | pageowner_data->CONFIG_SPARSEMEM = get_kernel_config("CONFIG_SPARSEMEM", NULL); 16 | 17 | if (pageowner_data->CONFIG_SPARSEMEM_EXTREME == IKCONFIG_N) 18 | return -1; 19 | 20 | readmem(symbol_value("mem_section"), KVADDR, &pageowner_data->mem_section, sizeof(ulong), "mem_section", FAULT_ON_ERROR); 21 | 22 | readmem(symbol_value("max_pfn"), KVADDR, &pageowner_data->max_pfn, sizeof(ulong), "max_pfn", FAULT_ON_ERROR); 23 | readmem(symbol_value("min_low_pfn"), KVADDR, &pageowner_data->min_low_pfn, sizeof(ulong), "min_low_pfn", FAULT_ON_ERROR); 24 | 25 | readmem(symbol_value("page_ext_size"), KVADDR, &pageowner_data->page_ext_size, sizeof(ulong), "page_ext_size", FAULT_ON_ERROR); 26 | readmem(symbol_value("page_owner_ops") + PARSER_OFFSET(page_ext_operations_offset), KVADDR, 27 | &pageowner_data->page_owner_ops_offset, PARSER_SIZE(page_ext_operations_offset), "page_ext_operations_offset", FAULT_ON_ERROR); 28 | 29 | if (symbol_exists("depot_index")) 30 | readmem(symbol_value("depot_index"), KVADDR, &pageowner_data->depot_index, sizeof(int), "depot_index", FAULT_ON_ERROR); 31 | if (symbol_exists("stack_slabs")) 32 | pageowner_data->stack_slabs = symbol_value("stack_slabs"); 33 | 34 | if (symbol_exists("pool_index")) 35 | readmem(symbol_value("pool_index"), KVADDR, &pageowner_data->depot_index, sizeof(int), "pool_index", FAULT_ON_ERROR); 36 | if (symbol_exists("stack_pools")) 37 | pageowner_data->stack_slabs = symbol_value("stack_pools"); 38 | 39 | enumerator_value("PAGE_EXT_OWNER", &pageowner_data->PAGE_EXT_OWNER); 40 | enumerator_value("PAGE_EXT_OWNER_ALLOCATED", &pageowner_data->PAGE_EXT_OWNER_ALLOCATED); 41 | return 0; 42 | } 43 | 44 | void parser_page_owner_dump(struct pageowner_data_t* pageowner_data) { 45 | ulong page; 46 | ulong page_ext; 47 | ulong page_owner; 48 | ulong flags; 49 | ulong order; 50 | int handle; 51 | ulong pfn = pageowner_data->min_low_pfn; 52 | ulong max_pfn = pageowner_data->max_pfn; 53 | 54 | for(; pfn < max_pfn; pfn++) { 55 | page = 0x0; 56 | phys_to_page(PTOB(pfn), &page); 57 | if (!page) continue; 58 | 59 | if (pageowner_data->page && pageowner_data->page != page) 60 | continue; 61 | 62 | page_ext = parser_page_ext_get(pageowner_data, page, pfn); 63 | if (!page_ext) continue; 64 | 65 | readmem(page_ext + PARSER_OFFSET(page_ext_flags), KVADDR, 66 | &flags, PARSER_SIZE(page_ext_flags), "page_ext_flags", FAULT_ON_ERROR); 67 | 68 | if (!test_bit(pageowner_data->PAGE_EXT_OWNER, &flags)) continue; 69 | if (!test_bit(pageowner_data->PAGE_EXT_OWNER_ALLOCATED, &flags)) continue; 70 | 71 | page_owner = parser_get_page_owner(pageowner_data, page_ext); 72 | readmem(page_owner + PARSER_OFFSET(page_owner_order), KVADDR, 73 | &order, PARSER_SIZE(page_owner_order), "page_owner_order", FAULT_ON_ERROR); 74 | 75 | if (!IS_ALIGNED(pfn, 1 << order)) continue; 76 | 77 | readmem(page_owner + PARSER_OFFSET(page_owner_handle), KVADDR, 78 | &handle, PARSER_SIZE(page_owner_handle), "page_owner_handle", FAULT_ON_ERROR); 79 | if (!handle) continue; 80 | 81 | parser_print_page_owner(pageowner_data, pfn, page, page_owner, handle); 82 | } 83 | } 84 | 85 | void parser_page_owner_top_print(ulong pages, int pid) { 86 | struct task_context *tc = NULL; 87 | if (pages) { 88 | tc = pid_to_context(pid); 89 | if (!tc) { 90 | fprintf(fp, "PID:%-5d alloc %lu pages\n", pid, pages); 91 | } else { 92 | fprintf(fp, "PID:%-5d %-16s alloc %lu pages\n", pid, tc->comm, pages); 93 | } 94 | } 95 | } 96 | 97 | void parser_page_owner_main(void) { 98 | struct pageowner_data_t page_owner_data; 99 | BZERO(&page_owner_data, sizeof(page_owner_data)); 100 | 101 | int opt; 102 | int option_index = 0; 103 | optind = 0; // reset 104 | static struct option long_options[] = { 105 | {"page", required_argument, 0, 1}, 106 | {"pid", required_argument, 0, 2}, 107 | {"top", required_argument, 0,'t'}, 108 | {0, 0, 0, 0} 109 | }; 110 | 111 | while ((opt = getopt_long(argcnt - 1, &args[1], "t:", 112 | long_options, &option_index)) != -1) { 113 | switch (opt) { 114 | case 1: 115 | if (args[optind]) { 116 | page_owner_data.page = htol(args[optind], FAULT_ON_ERROR, NULL); 117 | } break; 118 | case 2: 119 | if (args[optind]) page_owner_data.pid = atoi(args[optind]); 120 | break; 121 | case 't': { 122 | if (args[optind]) { 123 | page_owner_data.dumptop = atoi(args[optind]); 124 | } else { 125 | page_owner_data.dumptop = 1; 126 | } 127 | } break; 128 | } 129 | } 130 | 131 | if (!parser_page_owner_data_init(&page_owner_data)) { 132 | if (page_owner_data.dumptop) { 133 | if (page_owner_data.pid) { 134 | page_owner_data.dumptop = 1; 135 | page_owner_data.top = (ulong *)malloc(1 * sizeof(ulong)); 136 | BZERO(page_owner_data.top, 1 * sizeof(ulong)); 137 | page_owner_data.top_size = 1; 138 | } else { 139 | page_owner_data.top = (ulong *)malloc(32768 * sizeof(ulong)); 140 | BZERO(page_owner_data.top, 32768 * sizeof(ulong)); 141 | page_owner_data.top_size = 32768; 142 | } 143 | } 144 | 145 | parser_page_owner_dump(&page_owner_data); 146 | 147 | if (page_owner_data.dumptop) { 148 | if (page_owner_data.pid) { 149 | parser_page_owner_top_print(page_owner_data.top[0], page_owner_data.pid); 150 | } else { 151 | ulong last_pages = ~0UL; 152 | for (int s = 0; s < page_owner_data.dumptop; ++s) { 153 | ulong max_pages = 0; 154 | int max_pid = 0; 155 | for (int p = 0; p < page_owner_data.top_size; ++p) { 156 | if (page_owner_data.top[p] > max_pages 157 | && page_owner_data.top[p] < last_pages) { 158 | max_pid = p; 159 | max_pages = page_owner_data.top[p]; 160 | } 161 | } 162 | last_pages = max_pages; 163 | parser_page_owner_top_print(max_pages, max_pid); 164 | } 165 | } 166 | if (page_owner_data.top) free(page_owner_data.top); 167 | } 168 | } 169 | } 170 | 171 | void parser_page_owner_usage(void) { 172 | fprintf(fp, "Usage: lp page_owner [OPTION] ...\n"); 173 | fprintf(fp, "Option:\n"); 174 | fprintf(fp, " --page dump page alloc stack.\n"); 175 | fprintf(fp, " --pid cloc pid pages.\n"); 176 | fprintf(fp, " -t, --top cloc top pages.\n"); 177 | } 178 | 179 | ulong parser_page_ext_get(struct pageowner_data_t* pageowner_data, ulong page, ulong pfn) { 180 | ulong page_ext; 181 | page_ext = parser_lookup_page_ext(pageowner_data, page, pfn); 182 | return page_ext; 183 | } 184 | 185 | ulong parser_lookup_page_ext(struct pageowner_data_t* pageowner_data, ulong page, ulong pfn) { 186 | if (pageowner_data->CONFIG_SPARSEMEM == IKCONFIG_N) 187 | return 0x0; 188 | 189 | ulong section = parser_pfn_to_section(pageowner_data, pfn); 190 | if (!section) return 0x0; 191 | 192 | ulong page_ext; 193 | readmem(section + PARSER_OFFSET(mem_section_page_ext), KVADDR, 194 | &page_ext, PARSER_SIZE(mem_section_page_ext), "mem_section_page_ext", FAULT_ON_ERROR); 195 | 196 | if (parser_page_ext_invalid(page_ext)) return 0x0; 197 | return parser_page_owner_get_entry(pageowner_data, page_ext, pfn); 198 | } 199 | 200 | ulong parser_pfn_to_section(struct pageowner_data_t* pageowner_data, ulong pfn) { 201 | return parser_nr_to_section(pageowner_data, pfn_to_section_nr(pfn)); 202 | } 203 | 204 | ulong parser_nr_to_section(struct pageowner_data_t* pageowner_data, ulong nr) { 205 | ulong root = SECTION_NR_TO_ROOT(nr); 206 | ulong root_value = 0x0; 207 | if (root >= NR_SECTION_ROOTS()) { 208 | return 0x0; 209 | } 210 | 211 | if (pageowner_data->CONFIG_SPARSEMEM_EXTREME == IKCONFIG_N) 212 | return 0x0; 213 | 214 | readmem(pageowner_data->mem_section + root * sizeof(void *), KVADDR, &root_value, sizeof(ulong), "root", FAULT_ON_ERROR); 215 | if (!root_value) 216 | return 0x0; 217 | 218 | ulong section_nr = nr & SECTION_ROOT_MASK(); 219 | return root_value + PARSER_SIZE(mem_section) * section_nr; 220 | } 221 | 222 | bool parser_page_ext_invalid(ulong page_ext) { 223 | return !page_ext || ((page_ext & PAGE_EXT_INVALID) == PAGE_EXT_INVALID); 224 | } 225 | 226 | ulong parser_get_page_owner(struct pageowner_data_t* pageowner_data, ulong page_ext) { 227 | return page_ext + pageowner_data->page_owner_ops_offset; 228 | } 229 | 230 | ulong parser_page_owner_get_entry(struct pageowner_data_t* pageowner_data, ulong base, ulong index) { 231 | return base + pageowner_data->page_ext_size * index; 232 | } 233 | 234 | void parser_print_page_owner(struct pageowner_data_t* pageowner_data, ulong pfn, ulong page, ulong page_owner, int handle) { 235 | struct task_context *tc = NULL; 236 | char page_owner_buf[64]; 237 | BZERO(page_owner_buf, sizeof(page_owner_buf)); 238 | readmem(page_owner, KVADDR, page_owner_buf, PARSER_SIZE(page_owner), "page_owner", FAULT_ON_ERROR); 239 | 240 | short order = SHORT(page_owner_buf + PARSER_OFFSET(page_owner_order)); 241 | int gfp_mask = INT(page_owner_buf + PARSER_OFFSET(page_owner_gfp_mask)); 242 | int pid = INT(page_owner_buf + PARSER_OFFSET(page_owner_pid)); 243 | int tgid = INT(page_owner_buf + PARSER_OFFSET(page_owner_tgid)); 244 | char *comm = page_owner_buf + PARSER_OFFSET(page_owner_comm); 245 | ulong ts_nsec = ULONG(page_owner_buf + PARSER_OFFSET(page_owner_ts_nsec)); 246 | 247 | if (!PARSER_VALID_MEMBER(page_owner_tgid)) { 248 | tc = pid_to_context(pid); 249 | if (tc) { 250 | tgid = task_tgid(tc->task); 251 | comm = tc->comm; 252 | } 253 | } 254 | 255 | if (pageowner_data->pid && pageowner_data->pid != tgid) return; 256 | if (pageowner_data->dumptop) { 257 | if (pageowner_data->pid) { 258 | pageowner_data->top[0] += 1; 259 | } else { 260 | pageowner_data->top[tgid] += 1; 261 | } 262 | return; 263 | } 264 | 265 | char header[256]; 266 | snprintf(header, sizeof(header), "PFN:0x%lx PAGE:0x%lx ORDER:%d PID:%d TGID:%d COMM:%s SEC:%lu GFP:0x%x\n", 267 | pfn, page, order, pid, tgid, comm, ts_nsec, gfp_mask); 268 | fprintf(fp, "%s", header); 269 | parser_stack_depot_print(pageowner_data, handle); 270 | } 271 | 272 | void parser_stack_depot_print(struct pageowner_data_t* pageowner_data, int stack) { 273 | unsigned long entries; 274 | unsigned int nr_entries; 275 | nr_entries = parser_stack_depot_fetch(pageowner_data, stack, &entries); 276 | if (nr_entries) parser_stack_trace_print(entries, nr_entries, 0); 277 | } 278 | 279 | void parser_stack_trace_print(unsigned long entries, unsigned int nr_entries, int spaces) { 280 | unsigned int i; 281 | if (!entries) return; 282 | 283 | for (i = 0; i < nr_entries; i++) { 284 | ulong symbols; 285 | struct syment *sp; 286 | ulong offset; 287 | readmem(entries + i * sizeof(void *), KVADDR, &symbols, sizeof(ulong), "symbols", FAULT_ON_ERROR); 288 | sp = value_search(symbols, &offset); 289 | if (sp) { 290 | fprintf(fp, " [<%lx>] %s+0x%lx\n", symbols, sp->name, offset); 291 | } else { 292 | fprintf(fp, " [<%lx>] %p\n", symbols, sp); 293 | } 294 | } 295 | fprintf(fp, "\n"); 296 | } 297 | 298 | unsigned int parser_stack_depot_fetch(struct pageowner_data_t* pageowner_data, int handle, unsigned long *entries) { 299 | int depot_index = pageowner_data->depot_index; 300 | ulong stack_slabs = pageowner_data->stack_slabs; 301 | ulong sr_size; 302 | ulong slab; 303 | ulong offset; 304 | ulong slabindex; 305 | 306 | union handle_parts parts = { .handle = handle }; 307 | if (THIS_KERNEL_VERSION >= LINUX(6,1,0)) { 308 | offset = parts.v6_1.offset << STACK_ALLOC_ALIGN; 309 | slabindex = parts.v6_1.slabindex; 310 | } else { 311 | offset = parts.v0.offset << STACK_ALLOC_ALIGN; 312 | slabindex = parts.v0.slabindex; 313 | } 314 | 315 | *entries = 0x0; 316 | if (!handle) return 0; 317 | if (slabindex > depot_index) return 0; 318 | 319 | readmem(stack_slabs + slabindex * sizeof(void *), KVADDR, &slab, sizeof(ulong), "slab", FAULT_ON_ERROR); 320 | if (!slab) return 0; 321 | 322 | ulong stack = slab + offset; 323 | *entries = stack + PARSER_OFFSET(stack_record_entries); 324 | readmem(stack + PARSER_OFFSET(stack_record_size), KVADDR, 325 | &sr_size, PARSER_SIZE(stack_record_size), "stack_record_size", FAULT_ON_ERROR); 326 | 327 | return sr_size; 328 | } 329 | -------------------------------------------------------------------------------- /core/core.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "core.h" 4 | #include "zram/zram.h" 5 | #include 6 | #include 7 | #include 8 | 9 | void parser_core_main(void) { 10 | #if defined(__LP64__) 11 | ulong thread_info_flags = 0x0; 12 | #endif 13 | unsigned int flags = 0x0; 14 | 15 | struct core_data_t core_data; 16 | memset(&core_data, 0x0, sizeof(core_data)); 17 | 18 | int opt; 19 | int option_index = 0; 20 | optind = 0; // reset 21 | static struct option long_options[] = { 22 | {"pid", required_argument, 0, 'p'}, 23 | {"output", required_argument, 0, 'o'}, 24 | {"zram", no_argument, 0, 1 }, 25 | {"shmem", no_argument, 0, 2 }, 26 | {"filter", required_argument, 0, 'f'}, 27 | {0, 0, 0, 0 } 28 | }; 29 | 30 | core_data.error_handle = QUIET; 31 | core_data.pid = CURRENT_PID(); 32 | core_data.filter_flags = FILTER_SANITIZER_SHADOW_VMA | FILTER_NON_READ_VMA; 33 | while ((opt = getopt_long(argcnt - 1, &args[1], "p:o:f:012", 34 | long_options, &option_index)) != -1) { 35 | switch (opt) { 36 | case 'p': 37 | if (args[optind]) core_data.pid = atoi(args[optind]); 38 | break; 39 | case 'o': 40 | if (args[optind]) core_data.file = args[optind]; 41 | break; 42 | case 'f': 43 | if (args[optind]) core_data.filter_flags = htol(args[optind], FAULT_ON_ERROR, NULL); 44 | break; 45 | case 1: 46 | core_data.parse_zram = 1; 47 | parser_zram_init(); 48 | break; 49 | case 2: 50 | core_data.parse_shmem = 1; 51 | parser_zram_init(); 52 | break; 53 | } 54 | } 55 | 56 | core_data.tc = pid_to_context(core_data.pid); 57 | if (!core_data.tc) { 58 | fprintf(fp, "No such pid: %d\n", core_data.pid); 59 | return; 60 | } 61 | set_context(core_data.tc->task, NO_PID, FALSE); 62 | 63 | readmem(core_data.tc->task + PARSER_OFFSET(task_struct_flags), KVADDR, 64 | &flags, sizeof(flags), "task_struct flags", FAULT_ON_ERROR); 65 | if (flags & PF_KTHREAD) { 66 | fprintf(fp, "%d kernel thread not support coredump.\n", core_data.pid); 67 | return; 68 | } 69 | 70 | struct task_mem_usage task_mem_usage, *tm; 71 | tm = &task_mem_usage; 72 | get_task_mem_usage(core_data.tc->task, tm); 73 | if (!tm->mm_struct_addr) { 74 | fprintf(fp, "%d no virtual memory space.\n", core_data.pid); 75 | return; 76 | } 77 | 78 | readmem(tm->mm_struct_addr + PARSER_OFFSET(mm_struct_start_stack), KVADDR, 79 | &core_data.mm_start_stack, PARSER_SIZE(mm_struct_start_stack), "mm_struct_start_stack", FAULT_ON_ERROR); 80 | readmem(tm->mm_struct_addr + PARSER_OFFSET(mm_struct_start_brk), KVADDR, 81 | &core_data.mm_start_brk, PARSER_SIZE(mm_struct_start_brk), "mm_struct_start_brk", FAULT_ON_ERROR); 82 | readmem(tm->mm_struct_addr + PARSER_OFFSET(mm_struct_brk), KVADDR, 83 | &core_data.mm_brk, PARSER_SIZE(mm_struct_brk), "mm_struct_brk", FAULT_ON_ERROR); 84 | 85 | fill_thread_info(core_data.tc->thread_info); 86 | #if defined(__LP64__) 87 | thread_info_flags = UINT(tt->thread_info + PARSER_OFFSET(thread_info_flags)); 88 | #endif 89 | 90 | if (BITS64()) { 91 | #if defined(ARM64) 92 | if (machine_type("ARM64")) { 93 | if (thread_info_flags & (1 << 22)) { // TIF_32BIT 94 | core_data.class = ELFCLASS32; 95 | core_data.machine = EM_ARM; 96 | core_data.compat = 1; 97 | core_data.parser_core_dump = parser_core_dump32; 98 | core_data.parser_core_prstatus = parser_arm_core_prstatus; 99 | core_data.parser_write_core_prstatus = parser_write_arm_core_prstatus; 100 | } else { 101 | core_data.class = ELFCLASS64; 102 | core_data.machine = EM_AARCH64; 103 | core_data.parser_core_dump = parser_core_dump64; 104 | core_data.parser_core_prstatus = parser_arm64_core_prstatus; 105 | core_data.parser_write_core_prstatus = parser_write_arm64_core_prstatus; 106 | } 107 | } 108 | #endif 109 | #if defined(X86_64) 110 | if (machine_type("X86_64")) { 111 | if (thread_info_flags & (1 << 29)) { // TIF_ADDR32 112 | core_data.class = ELFCLASS32; 113 | core_data.machine = EM_386; 114 | core_data.compat = 1; 115 | core_data.parser_core_dump = parser_core_dump32; 116 | core_data.parser_core_prstatus = parser_x86_core_prstatus; 117 | core_data.parser_write_core_prstatus = parser_write_x86_core_prstatus; 118 | } else { 119 | core_data.class = ELFCLASS64; 120 | core_data.machine = EM_X86_64; 121 | core_data.parser_core_dump = parser_core_dump64; 122 | core_data.parser_core_prstatus = parser_x86_64_core_prstatus; 123 | core_data.parser_write_core_prstatus = parser_write_x86_64_core_prstatus; 124 | } 125 | } 126 | #endif 127 | } else { 128 | #if defined(ARM) 129 | if (machine_type("ARM")) { 130 | core_data.class = ELFCLASS32; 131 | core_data.machine = EM_ARM; 132 | core_data.parser_core_dump = parser_core_dump32; 133 | core_data.parser_core_prstatus = parser_arm_core_prstatus; 134 | core_data.parser_write_core_prstatus = parser_write_arm_core_prstatus; 135 | } 136 | #endif 137 | #if defined(X86) 138 | if (machine_type("X86")) { 139 | core_data.class = ELFCLASS32; 140 | core_data.machine = EM_386; 141 | core_data.parser_core_dump = parser_core_dump32; 142 | core_data.parser_core_prstatus = parser_x86_core_prstatus; 143 | core_data.parser_write_core_prstatus = parser_write_x86_core_prstatus; 144 | } 145 | #endif 146 | } 147 | core_data.page_size = PAGESIZE(); 148 | core_data.align_size = 4096; 149 | core_data.page_buf = (unsigned char *)malloc(core_data.page_size); 150 | core_data.zero_buf = (unsigned char *)malloc(core_data.align_size); 151 | core_data.clean = parser_core_clean; 152 | core_data.fill_vma_name = parser_core_fill_vma_name; 153 | core_data.filter_vma = parser_core_filter_vma; 154 | core_data.parser_core_dump(&core_data); 155 | } 156 | 157 | void parser_core_clean(struct core_data_t* core_data) { 158 | if (core_data->fp) fclose(core_data->fp); 159 | if (core_data->vma_cache) free(core_data->vma_cache); 160 | if (core_data->prstatus_cache) free(core_data->prstatus_cache); 161 | if (core_data->auxv_cache) free(core_data->auxv_cache); 162 | if (core_data->load_cache) free(core_data->load_cache); 163 | if (core_data->zero_buf) free(core_data->zero_buf); 164 | if (core_data->page_buf) free(core_data->page_buf); 165 | } 166 | 167 | void parser_core_fill_vma_name(struct core_data_t* core_data) { 168 | char *file_buf; 169 | char anon[ANON_BUFSIZE]; 170 | ulong dentry, vfsmnt; 171 | physaddr_t paddr; 172 | 173 | for (int index = 0; index < core_data->vma_count; ++index) { 174 | file_buf = NULL; 175 | BZERO(anon, ANON_BUFSIZE); 176 | dentry = vfsmnt = 0; 177 | 178 | if (IS_KVADDR(core_data->vma_cache[index].vm_file)) { 179 | file_buf = fill_file_cache(core_data->vma_cache[index].vm_file); 180 | dentry = ULONG(file_buf + OFFSET(file_f_dentry)); 181 | 182 | if (IS_KVADDR(dentry)) { 183 | if (VALID_MEMBER(file_f_vfsmnt)) { 184 | vfsmnt = ULONG(file_buf + OFFSET(file_f_vfsmnt)); 185 | get_pathname(dentry, core_data->vma_cache[index].buf, BUFSIZE, 1, vfsmnt); 186 | } else 187 | get_pathname(dentry, core_data->vma_cache[index].buf, BUFSIZE, 1, 0); 188 | } 189 | 190 | } else if (core_data->vma_cache[index].anon_name) { 191 | if (PARSER_VALID_MEMBER(anon_vma_name_name)) { 192 | if (IS_KVADDR(core_data->vma_cache[index].anon_name)) 193 | readmem(core_data->vma_cache[index].anon_name + PARSER_OFFSET(anon_vma_name_name), KVADDR, 194 | anon, ANON_BUFSIZE, "anon_name", core_data->error_handle); 195 | } else if (IS_KVADDR(core_data->vma_cache[index].anon_name)) { 196 | readmem(core_data->vma_cache[index].anon_name, KVADDR, 197 | anon, ANON_BUFSIZE, "anon_name", core_data->error_handle); 198 | } else { 199 | #if defined(__LP64__) 200 | core_data->vma_cache[index].anon_name &= (USERSPACE_TOP - 1); 201 | #endif 202 | int count = 2; 203 | uint64_t anon_buf_off = 0; 204 | uint64_t anon_buf_use = ANON_BUFSIZE - 1; 205 | do { 206 | memset(core_data->page_buf, 0x0, core_data->page_size); 207 | paddr = (physaddr_t)0x0; 208 | int page_exist = uvtop(core_data->tc, core_data->vma_cache[index].anon_name + anon_buf_off, &paddr, 0); 209 | ulong off = PAGEOFFSET(core_data->vma_cache[index].anon_name + anon_buf_off); 210 | uint64_t read_size = (core_data->page_size - off > anon_buf_use) ? anon_buf_use : (core_data->page_size - off); 211 | if (!read_size) 212 | break; 213 | 214 | if (paddr) { 215 | if (page_exist) { 216 | readmem(paddr, PHYSADDR, &anon[anon_buf_off], read_size, "read anon_name", core_data->error_handle); 217 | } else if (core_data->parse_zram) { 218 | ulong zram_offset = SWP_OFFSET(paddr); 219 | ulong swap_type = SWP_TYPE(paddr); 220 | parser_zram_read_page(swap_type, zram_offset, core_data->page_buf, core_data->error_handle); 221 | memcpy(&anon[anon_buf_off], core_data->page_buf + off, read_size); 222 | } 223 | } 224 | 225 | // next page 226 | if (anon[read_size - 1] != 0x0) { 227 | anon_buf_off += read_size; 228 | anon_buf_use -= read_size; 229 | } else 230 | break; 231 | 232 | count--; 233 | } while(count); 234 | anon[ANON_BUFSIZE - 1] = '\0'; 235 | } 236 | snprintf(core_data->vma_cache[index].buf, BUFSIZE, "[anon:%s]", anon); 237 | } else { 238 | if (core_data->vma_cache[index].vm_start < core_data->mm_brk 239 | && core_data->vma_cache[index].vm_end > core_data->mm_start_brk) { 240 | snprintf(core_data->vma_cache[index].buf, BUFSIZE, "[heap]"); 241 | } 242 | 243 | if (core_data->vma_cache[index].vm_start <= core_data->mm_start_stack 244 | && core_data->vma_cache[index].vm_end >= core_data->mm_start_stack) { 245 | snprintf(core_data->vma_cache[index].buf, BUFSIZE, "[stack]"); 246 | } 247 | } 248 | 249 | core_data->fileslen += strlen(core_data->vma_cache[index].buf) + 1; 250 | } 251 | } 252 | 253 | int parser_core_filter_vma(struct core_data_t* core_data, int index) { 254 | if (core_data->filter_flags & FILTER_SPECIAL_VMA) { 255 | if (!strcmp(core_data->vma_cache[index].buf, "/dev/binderfs/hwbinder") 256 | || !strcmp(core_data->vma_cache[index].buf, "/dev/binderfs/binder") 257 | || !strcmp(core_data->vma_cache[index].buf, "/dev/mali0")) 258 | return 1; 259 | } 260 | 261 | if (core_data->filter_flags & FILTER_FILE_VMA) { 262 | if (!core_data->vma_cache[index].anon_vma 263 | && core_data->vma_cache[index].vm_file) 264 | return 1; 265 | } 266 | 267 | if (core_data->filter_flags & FILTER_SHARED_VMA) { 268 | if (core_data->vma_cache[index].vm_flags & (VM_SHARED | VM_MAYSHARE)) 269 | return 1; 270 | } 271 | 272 | if (core_data->filter_flags & FILTER_SANITIZER_SHADOW_VMA) { 273 | if (!strcmp(core_data->vma_cache[index].buf, "[anon:low shadow]") 274 | || !strcmp(core_data->vma_cache[index].buf, "[anon:high shadow]") 275 | || !strncmp(core_data->vma_cache[index].buf, "[anon:hwasan", 12)) 276 | return 1; 277 | } 278 | 279 | if (core_data->filter_flags & FILTER_NON_READ_VMA) { 280 | if (!(core_data->vma_cache[index].vm_flags & VM_READ) 281 | && !(core_data->vma_cache[index].vm_flags & VM_WRITE) 282 | && !(core_data->vma_cache[index].vm_flags & VM_EXEC)) 283 | return 1; 284 | } 285 | 286 | return 0; 287 | } 288 | 289 | void parser_core_usage(void) { 290 | fprintf(fp, "Usage: lp core [OPTION]\n"); 291 | fprintf(fp, "Option:\n"); 292 | fprintf(fp, " --zram collect zram page\n"); 293 | fprintf(fp, " --shmem collect shared memory on zram page\n"); 294 | fprintf(fp, " -f, --filter filter vma flags\n"); 295 | fprintf(fp, " -o, --output coredump file path\n"); 296 | fprintf(fp, " -p, --pid set collect coredump process pid\n"); 297 | fprintf(fp, "Filter Vma:\n"); 298 | fprintf(fp, " 0x01: filter-special-vma\n"); 299 | fprintf(fp, " 0x02: filter-file-vma\n"); 300 | fprintf(fp, " 0x04: filter-shared-vma\n"); 301 | fprintf(fp, " 0x08: filter-sanitizer-shadow-vma (default)\n"); 302 | fprintf(fp, " 0x10: filter-non-read-vma (default)\n"); 303 | fprintf(fp, "Example:\n"); 304 | fprintf(fp, " lp core -p 1 --zram --shmem -f 0x18\n"); 305 | } 306 | -------------------------------------------------------------------------------- /binder/binder.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024-present, Guanyou.Chen. All rights reserved. 2 | 3 | #include "binder.h" 4 | #include 5 | #include 6 | #include 7 | 8 | void parser_binder_main(void) { 9 | int opt; 10 | int option_index = 0; 11 | optind = 0; // reset 12 | static struct option long_options[] = { 13 | {"pid", required_argument, 0, 'p'}, 14 | {"all", no_argument, 0, 'a'}, 15 | {0, 0, 0, 0 } 16 | }; 17 | 18 | struct binder_data_t binder_data; 19 | memset(&binder_data, 0x0, sizeof(binder_data)); 20 | 21 | while ((opt = getopt_long(argcnt - 1, &args[1], "p:a", 22 | long_options, &option_index)) != -1) { 23 | switch (opt) { 24 | case 'p': 25 | if (args[optind]) binder_data.pid = atoi(args[optind]); 26 | break; 27 | case 'a': 28 | binder_data.dump_all = 1; 29 | break; 30 | } 31 | } 32 | 33 | if (!binder_data.dump_all && binder_data.pid) { 34 | binder_data.tc = pid_to_context(binder_data.pid); 35 | if (!binder_data.tc) { 36 | fprintf(fp, "No such pid: %d\n", binder_data.pid); 37 | return; 38 | } 39 | } 40 | 41 | parser_binder_proc_show(&binder_data); 42 | } 43 | 44 | void parser_binder_usage(void) { 45 | fprintf(fp, "Usage: lp binder [OPTION] ...\n"); 46 | fprintf(fp, "Option:\n"); 47 | fprintf(fp, " -p, --pid read target binder info\n"); 48 | fprintf(fp, " -a, --all read all binder info\n"); 49 | } 50 | 51 | void parser_binder_proc_show(struct binder_data_t* binder_data) { 52 | int i, pid, tgid, cnt; 53 | struct list_data ld; 54 | 55 | if (!symbol_exists("binder_procs")) 56 | error(FATAL, "binder_procs doesn't exist in this kernel!\n"); 57 | 58 | ulong binder_procs = symbol_value("binder_procs"); 59 | if (!binder_procs) return; 60 | ulong first; 61 | readmem(binder_procs, KVADDR, &first, sizeof(void *), "binder_procs_first", FAULT_ON_ERROR); 62 | 63 | memset(&ld, 0x0, sizeof(ld)); 64 | ld.flags |= LIST_ALLOCATE; 65 | ld.start = first; 66 | ld.member_offset = PARSER_OFFSET(binder_proc_proc_node); 67 | if (empty_list(ld.start)) return; 68 | cnt = do_list(&ld); 69 | 70 | if (binder_data->tc && binder_data->tc->task) 71 | tgid = task_tgid(binder_data->tc->task); 72 | else 73 | tgid = -1; 74 | 75 | for (i = 0; i < cnt; ++i) { 76 | if (!ld.list_ptr[i]) continue; 77 | readmem(ld.list_ptr[i] + PARSER_OFFSET(binder_proc_pid), KVADDR, 78 | &pid, PARSER_SIZE(binder_proc_pid), "binder_proc_pid", FAULT_ON_ERROR); 79 | if (binder_data->dump_all || (binder_data->pid == pid || tgid == pid)) { 80 | fprintf(fp, "binder proc state:\n"); 81 | parser_binder_print_binder_proc(ld.list_ptr[i]); 82 | } 83 | } 84 | FREEBUF(ld.list_ptr); 85 | } 86 | 87 | void parser_binder_print_binder_proc(ulong proc) { 88 | unsigned char *binder_proc_buf = NULL; 89 | binder_proc_buf = (unsigned char *)malloc(PARSER_SIZE(binder_proc)); 90 | readmem(proc, KVADDR, binder_proc_buf, PARSER_SIZE(binder_proc), "binder_proc", FAULT_ON_ERROR); 91 | ulong context = ULONG(binder_proc_buf + PARSER_OFFSET(binder_proc_context)); 92 | ulong threads = ULONG(binder_proc_buf + PARSER_OFFSET(binder_proc_threads)); 93 | ulong todo = ULONG(binder_proc_buf + PARSER_OFFSET(binder_proc_todo)); 94 | ulong nameptr; 95 | char name[16]; 96 | readmem(context + PARSER_OFFSET(binder_context_name), KVADDR, 97 | &nameptr, PARSER_SIZE(binder_context_name), "binder_context_name", FAULT_ON_ERROR); 98 | readmem(nameptr, KVADDR, name, sizeof(name), "name", FAULT_ON_ERROR); 99 | fprintf(fp, "[%lx] proc %d\n", proc, UINT(binder_proc_buf + PARSER_OFFSET(binder_proc_pid))); 100 | fprintf(fp, "context %s\n", name); 101 | 102 | struct tree_data td; 103 | ulong *list_ptr = NULL; 104 | int i, cnt; 105 | memset(&td, 0x0, sizeof(td)); 106 | // td.flags |= VERBOSE | TREE_POSITION_DISPLAY | TREE_LINEAR_ORDER; 107 | td.flags |= TREE_NODE_POINTER; 108 | td.start = threads; 109 | td.node_member_offset = PARSER_OFFSET(binder_thread_rb_node); 110 | hq_open(); 111 | cnt = do_rbtree(&td); 112 | if (cnt) { 113 | list_ptr = (ulong *)malloc(cnt * sizeof(void *)); 114 | BZERO(list_ptr, cnt * sizeof(void *)); 115 | retrieve_list(list_ptr, cnt); 116 | 117 | for (i = 0; i < cnt; ++i) { 118 | if (!list_ptr[i]) continue; 119 | parser_binder_print_binder_thread_ilocked(list_ptr[i] - td.node_member_offset); 120 | } 121 | free(list_ptr); 122 | } 123 | hq_close(); 124 | 125 | struct list_data ld; 126 | memset(&ld, 0x0, sizeof(ld)); 127 | ld.flags |= LIST_ALLOCATE | LIST_HEAD_POINTER; 128 | ld.start = todo; 129 | if (empty_list(ld.start)) { 130 | free(binder_proc_buf); 131 | fprintf(fp, "\n"); 132 | return; 133 | } 134 | cnt = do_list(&ld); 135 | for (i = 0; i < cnt; ++i) { 136 | if (!ld.list_ptr[i]) continue; 137 | parser_binder_print_binder_work_ilocked(proc, " ", " pending transaction", ld.list_ptr[i]); 138 | } 139 | FREEBUF(ld.list_ptr); 140 | free(binder_proc_buf); 141 | fprintf(fp, "\n"); 142 | } 143 | 144 | void parser_binder_print_binder_thread_ilocked(ulong thread) { 145 | unsigned char *binder_thread_buf = NULL; 146 | binder_thread_buf = (unsigned char *)malloc(PARSER_SIZE(binder_thread)); 147 | readmem(thread, KVADDR, binder_thread_buf, PARSER_SIZE(binder_thread), "binder_thread", FAULT_ON_ERROR); 148 | 149 | int pid = UINT(binder_thread_buf + PARSER_OFFSET(binder_thread_pid)); 150 | int looper = UINT(binder_thread_buf + PARSER_OFFSET(binder_thread_looper)); 151 | char looper_need_return = BOOL(binder_thread_buf + PARSER_OFFSET(binder_thread_looper_need_return)); 152 | int tmp_ref = UINT(binder_thread_buf + PARSER_OFFSET(binder_thread_tmp_ref)); 153 | fprintf(fp, " [%lx] thread %d: l %02x need_return %d tr %d\n", 154 | thread, pid, looper, looper_need_return, tmp_ref); 155 | 156 | ulong proc = ULONG(binder_thread_buf + PARSER_OFFSET(binder_thread_proc)); 157 | ulong transaction_stack = ULONG(binder_thread_buf + PARSER_OFFSET(binder_thread_transaction_stack)); 158 | ulong t = transaction_stack; 159 | while (t) { 160 | ulong from; 161 | ulong to_thread; 162 | readmem(t + PARSER_OFFSET(binder_transaction_from), KVADDR, 163 | &from, PARSER_SIZE(binder_transaction_from), "binder_transaction_from", FAULT_ON_ERROR); 164 | readmem(t + PARSER_OFFSET(binder_transaction_to_thread), KVADDR, 165 | &to_thread, PARSER_SIZE(binder_transaction_to_thread), "binder_transaction_to_thread", FAULT_ON_ERROR); 166 | if (from == thread) { 167 | parser_binder_print_binder_transaction_ilocked(proc, " outgoing transaction", t); 168 | ulong from_parent; 169 | readmem(t + PARSER_OFFSET(binder_transaction_from_parent), KVADDR, 170 | &from_parent, PARSER_SIZE(binder_transaction_from_parent), "binder_transaction_from_parent", FAULT_ON_ERROR); 171 | t = from_parent; 172 | } else if (to_thread == thread) { 173 | parser_binder_print_binder_transaction_ilocked(proc, " incoming transaction", t); 174 | ulong to_parent; 175 | readmem(t + PARSER_OFFSET(binder_transaction_to_parent), KVADDR, 176 | &to_parent, PARSER_SIZE(binder_transaction_to_parent), "binder_transaction_to_parent", FAULT_ON_ERROR); 177 | t = to_parent; 178 | } else { 179 | parser_binder_print_binder_transaction_ilocked(proc, " bad transaction", t); 180 | t = 0x0; 181 | } 182 | } 183 | free(binder_thread_buf); 184 | } 185 | 186 | void parser_binder_print_binder_transaction_ilocked(ulong proc, const char* prefix, ulong transaction) { 187 | unsigned char *binder_transaction_buf = NULL; 188 | binder_transaction_buf = (unsigned char *)malloc(PARSER_SIZE(binder_transaction)); 189 | readmem(transaction, KVADDR, binder_transaction_buf, PARSER_SIZE(binder_transaction), "binder_transaction", FAULT_ON_ERROR); 190 | 191 | int debug_id = INT(binder_transaction_buf + PARSER_OFFSET(binder_transaction_debug_id)); 192 | ulong from = ULONG(binder_transaction_buf + PARSER_OFFSET(binder_transaction_from)); 193 | ulong to_proc = ULONG(binder_transaction_buf + PARSER_OFFSET(binder_transaction_to_proc)); 194 | ulong to_thread = ULONG(binder_transaction_buf + PARSER_OFFSET(binder_transaction_to_thread)); 195 | uint code = UINT(binder_transaction_buf + PARSER_OFFSET(binder_transaction_code)); 196 | uint flags = UINT(binder_transaction_buf + PARSER_OFFSET(binder_transaction_flags)); 197 | char need_reply = BOOL(binder_transaction_buf + PARSER_OFFSET(binder_transaction_need_reply)); 198 | 199 | struct binder_priority priority; 200 | memcpy(&priority, binder_transaction_buf + PARSER_OFFSET(binder_transaction_priority), sizeof(priority)); 201 | 202 | ulong from_proc; 203 | int from_proc_pid; 204 | int from_pid; 205 | if (from) { 206 | readmem(from + PARSER_OFFSET(binder_thread_proc), KVADDR, 207 | &from_proc, PARSER_SIZE(binder_thread_proc), "binder_thread_proc", FAULT_ON_ERROR); 208 | readmem(from_proc + PARSER_OFFSET(binder_proc_pid), KVADDR, 209 | &from_proc_pid, PARSER_SIZE(binder_proc_pid), "binder_proc_pid", FAULT_ON_ERROR); 210 | readmem(from + PARSER_OFFSET(binder_thread_pid), KVADDR, 211 | &from_pid, PARSER_SIZE(binder_thread_pid), "binder_thread_pid", FAULT_ON_ERROR); 212 | } 213 | 214 | int to_proc_pid; 215 | if (to_proc) { 216 | readmem(to_proc + PARSER_OFFSET(binder_proc_pid), KVADDR, 217 | &to_proc_pid, PARSER_SIZE(binder_proc_pid), "binder_proc_pid", FAULT_ON_ERROR); 218 | } 219 | 220 | int to_thread_pid; 221 | if (to_thread) { 222 | readmem(to_thread + PARSER_OFFSET(binder_thread_pid), KVADDR, 223 | &to_thread_pid, PARSER_SIZE(binder_thread_pid), "binder_thread_pid", FAULT_ON_ERROR); 224 | } 225 | 226 | if (!PARSER_VALID_MEMBER(binder_transaction_start_time)) 227 | fprintf(fp, "%s %d: 0x%lx from %d:%d to %d:%d code %x flags %x pri %s:%d r%d", 228 | prefix, debug_id, transaction, 229 | from ? from_proc_pid : 0, 230 | from ? from_pid : 0, 231 | to_proc ? to_proc_pid : 0, 232 | to_thread ? to_thread_pid : 0, 233 | code, flags, convert_sched(priority.sched_policy), 234 | priority.prio, need_reply); 235 | else { 236 | ulong start_time = ULONG(binder_transaction_buf + PARSER_OFFSET(binder_transaction_start_time)); 237 | float start_time_cloc = start_time * 1.0F /1000000 / 1000; 238 | fprintf(fp, "%s %d: 0x%lx from %d:%d to %d:%d code %x flags %x pri %s:%d r%d st:[%.6f]", 239 | prefix, debug_id, transaction, 240 | from ? from_proc_pid : 0, 241 | from ? from_pid : 0, 242 | to_proc ? to_proc_pid : 0, 243 | to_thread ? to_thread_pid : 0, 244 | code, flags, convert_sched(priority.sched_policy), 245 | priority.prio, need_reply, start_time_cloc); 246 | } 247 | 248 | if (proc != to_proc) { 249 | fprintf(fp, "\n"); 250 | free(binder_transaction_buf); 251 | return; 252 | } 253 | 254 | ulong buffer = ULONG(binder_transaction_buf + PARSER_OFFSET(binder_transaction_buffer)); 255 | if (!buffer) { 256 | fprintf(fp, " buffer free\n"); 257 | free(binder_transaction_buf); 258 | return; 259 | } 260 | 261 | struct binder_buffer b_buf; 262 | readmem(buffer, KVADDR, &b_buf, sizeof(struct binder_buffer), "binder_buffer", FAULT_ON_ERROR); 263 | 264 | if (b_buf.target_node) { 265 | int node_debug_id; 266 | readmem((ulong)b_buf.target_node + PARSER_OFFSET(binder_node_debug_id), KVADDR, 267 | &node_debug_id, PARSER_SIZE(binder_node_debug_id), "binder_node_debug_id", FAULT_ON_ERROR); 268 | fprintf(fp, " node %d", node_debug_id); 269 | } 270 | 271 | fprintf(fp, " size %zd:%zd data %p\n", 272 | b_buf.data_size, b_buf.offsets_size, b_buf.user_data); 273 | 274 | free(binder_transaction_buf); 275 | } 276 | 277 | void parser_binder_print_binder_work_ilocked(ulong proc, const char* prefix, const char* transaction_prefix, ulong work) { 278 | ulong transaction; 279 | struct binder_work w; 280 | readmem(work, KVADDR, &w, sizeof(struct binder_work), "binder_work", FAULT_ON_ERROR); 281 | 282 | switch(w.type) { 283 | case BINDER_WORK_TRANSACTION: 284 | transaction = work - PARSER_OFFSET(binder_transaction_work); 285 | parser_binder_print_binder_transaction_ilocked(proc, transaction_prefix, transaction); 286 | break; 287 | case BINDER_WORK_RETURN_ERROR: { 288 | ulong error = work - offsetof(struct binder_error, work); 289 | struct binder_error e; 290 | readmem(error, KVADDR, &e, sizeof(struct binder_error), "binder_error", FAULT_ON_ERROR); 291 | fprintf(fp, "%stransaction error: %u\n", prefix, e.cmd); 292 | } break; 293 | case BINDER_WORK_TRANSACTION_COMPLETE: 294 | fprintf(fp, "%stransaction complete\n", prefix); 295 | break; 296 | case BINDER_WORK_NODE: { 297 | ulong node = work - PARSER_OFFSET(binder_node_work); 298 | int debug_id; 299 | ulong ptr; 300 | ulong cookie; 301 | readmem(node + PARSER_OFFSET(binder_node_debug_id), KVADDR, 302 | &debug_id, PARSER_SIZE(binder_node_debug_id), "binder_node_debug_id", FAULT_ON_ERROR); 303 | readmem(node + PARSER_OFFSET(binder_node_ptr), KVADDR, 304 | &ptr, PARSER_SIZE(binder_node_ptr), "binder_node_ptr", FAULT_ON_ERROR); 305 | readmem(node + PARSER_OFFSET(binder_node_cookie), KVADDR, 306 | &cookie, PARSER_SIZE(binder_node_cookie), "binder_node_cookie", FAULT_ON_ERROR); 307 | fprintf(fp, "%snode work %d: u%016lx c%016lx\n", prefix, debug_id, ptr, cookie); 308 | } break; 309 | case BINDER_WORK_DEAD_BINDER: 310 | fprintf(fp, "%shas dead binder\n", prefix); 311 | break; 312 | case BINDER_WORK_DEAD_BINDER_AND_CLEAR: 313 | fprintf(fp, "%shas cleared dead binder\n", prefix); 314 | break; 315 | case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: 316 | fprintf(fp, "%shas cleared death notification\n", prefix); 317 | break; 318 | default: 319 | fprintf(fp, "%sunknown work: type %d\n", prefix, w.type); 320 | break; 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /lib/lz4/lz4.h: -------------------------------------------------------------------------------- 1 | /* LZ4 Kernel Interface 2 | * 3 | * Copyright (C) 2013, LG Electronics, Kyungsik Lee 4 | * Copyright (C) 2016, Sven Schmidt <4sschmid@informatik.uni-hamburg.de> 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 version 2 as 8 | * published by the Free Software Foundation. 9 | * 10 | * This file is based on the original header file 11 | * for LZ4 - Fast LZ compression algorithm. 12 | * 13 | * LZ4 - Fast LZ compression algorithm 14 | * Copyright (C) 2011-2016, Yann Collet. 15 | * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions are 18 | * met: 19 | * * Redistributions of source code must retain the above copyright 20 | * notice, this list of conditions and the following disclaimer. 21 | * * Redistributions in binary form must reproduce the above 22 | * copyright notice, this list of conditions and the following disclaimer 23 | * in the documentation and/or other materials provided with the 24 | * distribution. 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | * You can contact the author at : 37 | * - LZ4 homepage : http://www.lz4.org 38 | * - LZ4 source repository : https://github.com/lz4/lz4 39 | * 40 | * Changed for Linux core analysis use by: 41 | * Guanyou.Chen 42 | */ 43 | 44 | #ifndef __LZ4_H__ 45 | #define __LZ4_H__ 46 | 47 | #include 48 | #include 49 | #include /* memset, memcpy */ 50 | 51 | /*-************************************************************************ 52 | * CONSTANTS 53 | **************************************************************************/ 54 | /* 55 | * LZ4_MEMORY_USAGE : 56 | * Memory usage formula : N->2^N Bytes 57 | * (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) 58 | * Increasing memory usage improves compression ratio 59 | * Reduced memory usage can improve speed, due to cache effect 60 | * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache 61 | */ 62 | #define LZ4_MEMORY_USAGE 14 63 | 64 | #define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ 65 | #define LZ4_COMPRESSBOUND(isize) (\ 66 | (unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE \ 67 | ? 0 \ 68 | : (isize) + ((isize)/255) + 16) 69 | 70 | #define LZ4_ACCELERATION_DEFAULT 1 71 | #define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) 72 | #define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) 73 | #define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) 74 | 75 | #define LZ4HC_MIN_CLEVEL 3 76 | #define LZ4HC_DEFAULT_CLEVEL 9 77 | #define LZ4HC_MAX_CLEVEL 16 78 | 79 | #define LZ4HC_DICTIONARY_LOGSIZE 16 80 | #define LZ4HC_MAXD (1< 5 | #include 6 | #include 7 | 8 | struct zram_data_t* zram_data_cache = NULL; 9 | struct pagecache_data_t* pagecache_data_cache = NULL; 10 | ulong PARSER_ZRAM_FLAG_SHIFT = 0; 11 | ulong PARSER_ZRAM_FLAG_SAME_BIT = 0; 12 | ulong PARSER_ZRAM_FLAG_WB_BIT = 0; 13 | ulong PARSER_ZRAM_COMP_PRIORITY_BIT1 = 0; 14 | ulong PARSER_ZRAM_COMP_PRIORITY_MASK = 0; 15 | static int zram_total = 0; 16 | static int zram_ready = 0; 17 | static int zsmalloc_ready = 0; 18 | 19 | int parser_get_swap_total() { return zram_total; } 20 | void parser_zram_main(void) { 21 | parser_zram_init(); 22 | 23 | if (argcnt <= 2) { 24 | parser_zram_usage(); 25 | return; 26 | } 27 | 28 | int opt; 29 | int option_index = 0; 30 | optind = 0; // reset 31 | static struct option long_options[] = { 32 | {"read", required_argument, 0, 'r'}, 33 | {"end", required_argument, 0, 'e'}, 34 | {"offset", required_argument, 0, 'o'}, 35 | {"type", required_argument, 0, 't'}, 36 | {"file", required_argument, 0, 'f'}, 37 | {"data", no_argument, 0, 'd'}, 38 | {0, 0, 0, 0 } 39 | }; 40 | 41 | ulong vaddr = 0x0; 42 | ulong eaddr = 0x0; 43 | ulong zram_off = 0x0; 44 | int dump_zram_off = 0; 45 | int swap_type = 0; 46 | char *filename = NULL; 47 | int debug_data = 0; 48 | while ((opt = getopt_long(argcnt - 1, &args[1], "r:e:o:t:f:d", 49 | long_options, &option_index)) != -1) { 50 | switch (opt) { 51 | case 'r': 52 | if (args[optind]) { 53 | vaddr = htol(args[optind], FAULT_ON_ERROR, NULL); 54 | eaddr = vaddr + 0x10; 55 | } break; 56 | case 'e': 57 | if (args[optind]) { 58 | eaddr = htol(args[optind], FAULT_ON_ERROR, NULL); 59 | } break; 60 | case 'o': 61 | if (args[optind]) { 62 | zram_off = htol(args[optind], FAULT_ON_ERROR, NULL); 63 | dump_zram_off = 1; 64 | vaddr = 0x0; 65 | eaddr = 0x1000; 66 | } break; 67 | case 't': 68 | if (args[optind]) { 69 | swap_type = htol(args[optind], FAULT_ON_ERROR, NULL); 70 | } break; 71 | case 'f': 72 | if (args[optind]) { 73 | filename = args[optind]; 74 | } break; 75 | case 'd': 76 | debug_data = 1; 77 | break; 78 | } 79 | } 80 | 81 | if (debug_data) { 82 | for (int i = 0; i < zram_total; ++i) { 83 | fprintf(fp, "zram_data_cache[%d].zram: 0x%lx\n", i, zram_data_cache[i].zram); 84 | fprintf(fp, "zram_data_cache[%d].comp_count: %ld\n", i, zram_data_cache[i].comp_count); 85 | for (int k = 0; k < zram_data_cache[i].comp_count; k++) { 86 | fprintf(fp, "zram_data_cache[%d].comp[%d]: 0x%lx\n", i, k, zram_data_cache[i].comp[k]); 87 | } 88 | fprintf(fp, "zram_data_cache[%d].pages: 0x%lx\n", i, zram_data_cache[i].pages); 89 | fprintf(fp, "pagecache_data_cache[%d].space: 0x%lx\n", i, pagecache_data_cache[i].space); 90 | fprintf(fp, "pagecache_data_cache[%d].cache_count: %d\n", i, pagecache_data_cache[i].cache_count); 91 | fprintf(fp, "pagecache_data_cache[%d].cache: %p\n", i, pagecache_data_cache[i].cache); 92 | for (int j = 0; j < pagecache_data_cache[i].cache_count; ++j) { 93 | fprintf(fp, "pagecache_data_cache[%d].cache[%d].page_count: %d\n", i, j, pagecache_data_cache[i].cache[j].page_count); 94 | fprintf(fp, "pagecache_data_cache[%d].cache[%d].pages: %p\n", i, j, pagecache_data_cache[i].cache[j].pages); 95 | } 96 | } 97 | fprintf(fp, "PARSER_ZRAM_FLAG_SHIFT: 0x%lx\n", PARSER_ZRAM_FLAG_SHIFT); 98 | fprintf(fp, "PARSER_ZRAM_FLAG_SAME_BIT: 0x%lx\n", PARSER_ZRAM_FLAG_SAME_BIT); 99 | fprintf(fp, "PARSER_ZRAM_FLAG_WB_BIT: 0x%lx\n", PARSER_ZRAM_FLAG_WB_BIT); 100 | fprintf(fp, "PARSER_ZRAM_COMP_PRIORITY_BIT1: 0x%lx\n", PARSER_ZRAM_COMP_PRIORITY_BIT1); 101 | fprintf(fp, "PARSER_ZRAM_COMP_PRIORITY_MASK: 0x%lx\n", PARSER_ZRAM_COMP_PRIORITY_MASK); 102 | return; 103 | } 104 | 105 | unsigned char *value = (unsigned char *)malloc(PAGESIZE()); 106 | memset(value, 0x0, PAGESIZE()); 107 | int zram_parse_ret = 0; 108 | char ascii1[9] = {'.', '.', '.', '.', '.', '.', '.', '.', '\0'}; 109 | char ascii2[9] = {'.', '.', '.', '.', '.', '.', '.', '.', '\0'}; 110 | ulong off = PAGEOFFSET(vaddr) / 0x8; 111 | 112 | if (dump_zram_off) { 113 | zram_parse_ret = parser_zram_read_page(swap_type, zram_off, value, FAULT_ON_ERROR); 114 | } else { 115 | zram_parse_ret = parser_zram_read_buf(vaddr, value, FAULT_ON_ERROR); 116 | } 117 | 118 | if (!filename) { 119 | if (!zram_parse_ret) return; 120 | int count = (eaddr - vaddr) / 8; 121 | for (int index = 0; index < count; index += 2) { 122 | parser_convert_ascii(((ulong *)value)[index + off], ascii1); 123 | parser_convert_ascii(((ulong *)value)[index + 1 + off], ascii2); 124 | fprintf(fp, " %lx: %016lx %016lx %s%s\n", vaddr + index * 0x8, 125 | ((ulong *)value)[index + off], ((ulong *)value)[index + 1 + off], ascii1, ascii2); 126 | } 127 | } else { 128 | FILE *output = fopen(filename, "wb"); 129 | if (output) { 130 | if (zram_data_cache[swap_type].zram) { 131 | for(int i = 0; i < zram_data_cache[swap_type].pages + 1; i++) { 132 | memset(value, 0x0, PAGESIZE()); 133 | parser_zram_read_page(swap_type, i, value, QUIET); 134 | fwrite(value, PAGESIZE(), 1, output); 135 | } 136 | fprintf(fp, "Saved [%s].\n", filename); 137 | } 138 | fclose(output); 139 | } 140 | } 141 | } 142 | 143 | void parser_zram_usage(void) { 144 | fprintf(fp, "Usage: lp zram [OPTION] ...\n"); 145 | fprintf(fp, "Option:\n"); 146 | fprintf(fp, " -r, --read read vaddr memory\n"); 147 | fprintf(fp, " -e, --end read endvaddr memory\n"); 148 | fprintf(fp, " -o, --offset read zram page\n"); 149 | fprintf(fp, " -t, --type zram, def: 0\n"); 150 | fprintf(fp, " -f, --file save zram.bin to file\n"); 151 | fprintf(fp, " -d, --data show zram cache data\n"); 152 | } 153 | 154 | static long parse_zram_pageflags(char* flags, int index, long zram_flag_shift) { 155 | long pageflags; 156 | if (enumerator_value(flags, &pageflags)) 157 | ; // do nothing 158 | else 159 | pageflags = zram_flag_shift + index; 160 | return pageflags; 161 | } 162 | 163 | void parser_zram_init(void) { 164 | // zram.ko 165 | unsigned char *fill_zram_buf = NULL; 166 | ulong nameptr; 167 | char name[128]; 168 | 169 | if (!zram_ready) { 170 | PARSER_MEMBER_OFFSET_INIT(zram_disksize, "zram", "disksize"); 171 | // PARSER_MEMBER_OFFSET_INIT(zram_compressor, "zram", "compressor"); 172 | PARSER_MEMBER_OFFSET_INIT(zram_table, "zram", "table"); 173 | PARSER_MEMBER_OFFSET_INIT(zram_mem_pool, "zram", "mem_pool"); 174 | PARSER_MEMBER_OFFSET_INIT(zram_comp, "zram", "comp"); 175 | PARSER_MEMBER_OFFSET_INIT(zram_comps, "zram", "comps"); 176 | PARSER_MEMBER_OFFSET_INIT(zram_table_entry_flags, "zram_table_entry", "flags"); 177 | PARSER_MEMBER_OFFSET_INIT(zram_table_entry_handle, "zram_table_entry", "handle"); 178 | PARSER_MEMBER_OFFSET_INIT(zram_table_entry_element, "zram_table_entry", "element"); 179 | PARSER_MEMBER_OFFSET_INIT(zcomp_name, "zcomp", "name"); 180 | 181 | PARSER_MEMBER_SIZE_INIT(zram_disksize, "zram", "disksize"); 182 | // PARSER_MEMBER_SIZE_INIT(zram_compressor, "zram", "compressor"); 183 | PARSER_MEMBER_SIZE_INIT(zram_table, "zram", "table"); 184 | PARSER_MEMBER_SIZE_INIT(zram_mem_pool, "zram", "mem_pool"); 185 | PARSER_MEMBER_SIZE_INIT(zram_comp, "zram", "comp"); 186 | PARSER_MEMBER_SIZE_INIT(zram_comps, "zram", "comps"); 187 | PARSER_MEMBER_SIZE_INIT(zram_table_entry_flags, "zram_table_entry", "flags"); 188 | PARSER_MEMBER_SIZE_INIT(zram_table_entry_handle, "zram_table_entry", "handle"); 189 | PARSER_MEMBER_SIZE_INIT(zram_table_entry_element, "zram_table_entry", "element"); 190 | PARSER_MEMBER_SIZE_INIT(zcomp_name, "zcomp", "name"); 191 | 192 | PARSER_STRUCT_SIZE_INIT(zram, "zram"); 193 | PARSER_STRUCT_SIZE_INIT(zram_table_entry, "zram_table_entry"); 194 | 195 | // check zram.ko ready 196 | if (!PARSER_VALID_MEMBER(zram_disksize)) { 197 | error(FATAL, "Please run mod -s zram.\n"); 198 | } 199 | 200 | long zram_flag_shift; 201 | if (enumerator_value("ZRAM_LOCK", &zram_flag_shift)) { 202 | ; // do nothing 203 | } else if (THIS_KERNEL_VERSION >= LINUX(6,1,0)) { 204 | zram_flag_shift = PAGESHIFT() + 1; 205 | } else { 206 | zram_flag_shift = 24; 207 | } 208 | PARSER_ZRAM_FLAG_SHIFT = 1 << zram_flag_shift; 209 | PARSER_ZRAM_FLAG_SAME_BIT = 1 << (parse_zram_pageflags("ZRAM_SAME", 1, zram_flag_shift)); 210 | PARSER_ZRAM_FLAG_WB_BIT = 1 << (parse_zram_pageflags("ZRAM_WB", 2, zram_flag_shift)); 211 | PARSER_ZRAM_COMP_PRIORITY_BIT1 = parse_zram_pageflags("ZRAM_COMP_PRIORITY_BIT1", 7, zram_flag_shift); 212 | PARSER_ZRAM_COMP_PRIORITY_MASK = 0x3; 213 | 214 | for (int i = 0; i < zram_total; ++i) { 215 | if (!zram_data_cache[i].zram) continue; 216 | fill_zram_buf = (unsigned char *)malloc(PARSER_SIZE(zram)); 217 | BZERO(fill_zram_buf, PARSER_SIZE(zram)); 218 | readmem(zram_data_cache[i].zram, KVADDR, fill_zram_buf, PARSER_SIZE(zram), "fill_zram_buf", FAULT_ON_ERROR); 219 | if (!PARSER_VALID_MEMBER(zram_comps)) { 220 | zram_data_cache[i].comp_count = 1; 221 | zram_data_cache[i].comp[0] = ULONG(fill_zram_buf + PARSER_OFFSET(zram_comp)); 222 | } else { 223 | zram_data_cache[i].comp_count = PARSER_SIZE(zram_comps) / sizeof(void *); 224 | for (int k = 0; k < zram_data_cache[i].comp_count; k++) { 225 | zram_data_cache[i].comp[k] = ULONG(fill_zram_buf + PARSER_OFFSET(zram_comps) + 8 * k); 226 | } 227 | } 228 | zram_data_cache[i].table = ULONG(fill_zram_buf + PARSER_OFFSET(zram_table)); 229 | zram_data_cache[i].mem_pool = ULONG(fill_zram_buf + PARSER_OFFSET(zram_mem_pool)); 230 | free(fill_zram_buf); 231 | 232 | // crypto decompress 233 | for (int k = 0; k < zram_data_cache[i].comp_count; k++) { 234 | memset(name, 0x0, sizeof(name)); 235 | if (zram_data_cache[i].comp[k]) { 236 | readmem(zram_data_cache[i].comp[k] + PARSER_OFFSET(zcomp_name), KVADDR, 237 | &nameptr, PARSER_SIZE(zcomp_name), "zcomp_name", FAULT_ON_ERROR); 238 | readmem(nameptr, KVADDR, name, sizeof(name), "compress name", FAULT_ON_ERROR); 239 | } 240 | zram_data_cache[i].decompress[k] = crypto_comp_get_decompress(name); 241 | } 242 | } 243 | zram_ready = 1; 244 | } 245 | 246 | // zsmalloc.ko 247 | if (!zsmalloc_ready) { 248 | PARSER_MEMBER_OFFSET_INIT(zspool_size_class, "zs_pool", "size_class"); 249 | PARSER_MEMBER_OFFSET_INIT(size_class_size, "size_class", "size"); 250 | PARSER_MEMBER_OFFSET_INIT(zspage_huge, "zspage", "huge"); 251 | 252 | // check zsmalloc.ko ready 253 | if (!PARSER_VALID_MEMBER(zspool_size_class)) { 254 | error(FATAL, "Please run mod -s zsmalloc.\n"); 255 | } 256 | zsmalloc_ready = 1; 257 | } 258 | } 259 | 260 | void parser_zram_data_init(void) { 261 | if (zram_data_cache) return; 262 | 263 | unsigned char *swap_info_buf = NULL; 264 | ulong swap_info_ptr; 265 | ulong swap_info; 266 | ulong swap_file; 267 | ulong bdev; 268 | ulong bd_disk; 269 | ulong swp_space_ptr = 0x0; 270 | ulong swp_space; 271 | int nr_swapfiles; 272 | char buf[BUFSIZE]; 273 | char *file_buf = NULL; 274 | ulong dentry, vfsmnt; 275 | 276 | if (!symbol_exists("nr_swapfiles")) 277 | error(FATAL, "nr_swapfiles doesn't exist in this kernel!\n"); 278 | 279 | if (!symbol_exists("swap_info")) 280 | error(FATAL, "swap_info doesn't exist in this kernel!\n"); 281 | 282 | if (symbol_exists("swapper_spaces")) 283 | swp_space_ptr = symbol_value("swapper_spaces"); 284 | 285 | swap_info_init(); 286 | swap_info_ptr = symbol_value("swap_info"); 287 | readmem(symbol_value("nr_swapfiles"), KVADDR, &nr_swapfiles, sizeof(int), "nr_swapfiles", FAULT_ON_ERROR); 288 | 289 | zram_data_cache = (struct zram_data_t*)malloc(nr_swapfiles * sizeof(struct zram_data_t)); 290 | BZERO(zram_data_cache, nr_swapfiles * sizeof(struct zram_data_t)); 291 | pagecache_data_cache = (struct pagecache_data_t*)malloc(nr_swapfiles * sizeof(struct pagecache_data_t)); 292 | BZERO(pagecache_data_cache, nr_swapfiles * sizeof(struct pagecache_data_t)); 293 | zram_total = nr_swapfiles; 294 | swap_info_buf = (unsigned char *)malloc(PARSER_SIZE(swap_info_struct)); 295 | for (int i = 0; i < nr_swapfiles; i++) { 296 | file_buf = NULL; 297 | dentry = vfsmnt = 0; 298 | memset(swap_info_buf, 0x0, PARSER_SIZE(swap_info_struct)); 299 | readmem(swap_info_ptr + i * sizeof(void *), KVADDR, 300 | &swap_info, sizeof(void *), "swap_info_struct", FAULT_ON_ERROR); 301 | 302 | readmem(swap_info, KVADDR, swap_info_buf, PARSER_SIZE(swap_info_struct), "swap_info_buf", FAULT_ON_ERROR); 303 | swap_file = ULONG(swap_info_buf + PARSER_OFFSET(swap_info_struct_swap_file)); 304 | zram_data_cache[i].pages = UINT(swap_info_buf + PARSER_OFFSET(swap_info_struct_pages)); 305 | 306 | if (swp_space_ptr) { 307 | swp_space = swp_space_ptr + i * sizeof(void *); 308 | readmem(swp_space, KVADDR, &pagecache_data_cache[i].space, sizeof(void *), "swp_spaces", FAULT_ON_ERROR); 309 | if (pagecache_data_cache[i].space) { 310 | pagecache_data_cache[i].cache_count = (zram_data_cache[i].pages + 1)/(1<