Crash 插件开发指南 简介 基本构成 常用 API 集

简介

crash-utility 开源项目是用于解析具体版本 Linux 内核 Core 的工具,基于 GDB 之上的程序,支持原始 GDB 指令以及特定的 Linux 模块解析,支持格式化内核数据结构、反汇编源代码、内核堆栈回溯等。对于开发者感兴趣解析的模块,可自定义增加插件模块解析。

基本构成

插件开发构成 描述
defs.h 文件 开发必备头文件,提供 crash-utility 环境下的 API 函数声明。
void attribute((constructor)) demo_init(void) demo 插件模块初始化入口,其它插件开发则替换 demo 字符串即可。
void attribute((destructor)) demo_fini(void) 在 crash-utility 环境下移除 demo 插件时自动调用。
static struct command_table_entry command_table[] = { “demo”, cmd_demo, help_demo, 0 },{ NULL }register_extension(command_table); 用于初始化入口注册插件函数。(关键)command_table_entry 结构体由 { 指令名称,指令主函数,指令帮助信息,…… } 组成。
void cmd_demo(void) 命令行传入参数已被 crash-utility 自身处理过,如果需使用 getopt,getopt_long 函数解析参数,使用全局变量 ( argcnt 、args ) 。
char *help_demo[] = {“demo”, // 指令名称”demo info”, // 指令具体描述”demo [-p] “, // 指令概要”version 1.0”, // 具体描述信息NULL}; 该字符串用于在 crash-utility 中输入 help demo 时返回。
{ ARM64,X86_64,…… } 编译宏定义 必须在编译脚本中确定目标架构,会影响 defs.h 部分函数及宏。
-rdynamic 编译 cflags 定义 添加到动态符号表

自定义插件,以下全局变量,以及宏需重新定义,扩展新的结构体成员。

结构体偏移、大小解析相关
extern struct offset_table offset_table;extern struct size_table size_table; 全局结构体成员偏移表全局结构体以及成员大小表
#define OFFSET(X) (… …) 与 offset_table 绑定,获取指定结构体成员偏移量
#define SIZE(X) (… …) 与 size_table 绑定,获取指定结构体或成员大小
#define VALID_MEMBER(X) (… …) 与 offset_table 绑定,校验成员是否有定义
#define ASSIGN_OFFSET(X) (… …) 与 offset_table 绑定,获取指定结构体成员偏移量,不校验
#define MEMBER_OFFSET_INIT(X, Y, Z) (… …) 初始化 offset_table 表成员偏移量
#define ASSIGN_SIZE(X) (… …) 与 size_table 绑定,获取指定结构体或成员大小,不校验
#define MEMBER_SIZE_INIT(X, Y, Z) (… …) 初始化 size_table 表成员大小
#define STRUCT_SIZE_INIT(X, Y) (… …) 初始化 size_table 表结构体大小
命令行处理以及终端输出
extern FILE *fp; 全局变量,fprintf(fp, “xxx\n”); 命令行输出
extern char *args[MAXARGS];extern int argcnt;extern int argerrs; 插件主函数的参数集。

常用 API 集

错误处理 描述
#define FAULT_ON_ERROR (0x1) 错误终止,并输出错误信息
#define RETURN_ON_ERROR (0x2) 错误不终止,但输出错误信息
#define QUIET (0x4) 错误终止且不输出错误信息
内存相关 描述
int readmem(ulonglong, int, void *, long, char *, ulong); 参数含义 { 地址,地址类型,结果集,错误信息,错误处理 }地址类型: { KVADDR,UVADDR,PHYSADDR }例子:ulong value;readmem(0xFFFFC9000D35BCD0, KVADDR, &value, sizeof(void*), “read value err!”, FAULT_ON_ERROR);
#define GETBUF(X) getbuf((long)(X)) 申请内存,可用 malloc 替代。
#define FREEBUF(X) freebuf((char *)(X)) 释放内存,与 GETBUF 成对存在。
int kvtop(struct task_context *, ulong, physaddr_t *, int); 内核态虚拟地址转物理地址
int uvtop(struct task_context *, ulong, physaddr_t *, int); 用户态虚拟地址转物理地址
机器属性相关 描述
extern struct machdep_table *machdep; 全局变量描述目标机器的具体信息,如 va_bits、kimage_text等, 可用 help -m 查看。
#define PAGESIZE() (machdep->pagesize) 目标机器页表大小
#define PAGESHIFT() (machdep->pageshift) 目标机器页表移位
Task 相关 描述
extern struct task_table task_table, *tt; 全局变量 tt,保存 task 的信息。
#define CURRENT_CONTEXT() (tt->current) 当前 task context,可用命令 set 查看
#define CURRENT_TASK() (tt->current->task)
#define CURRENT_PID() (tt->current->pid)
#define CURRENT_COMM() (tt->current->comm)
int set_context(ulong, ulong); 设置当前 task context。
ulong pid_to_task(ulong); pid 转 task_struct 地址
ulong task_to_pid(ulong); task_struct 地址转 pid
#define RUNNING_TASKS() (tt->running_tasks)
#define FIRST_CONTEXT() (tt->context_array) 所有 task ,可用 ps 查看。首个 task context 地址,一般用于遍历所有 task 时使用。
符号相关 描述
ulong symbol_value(char *);ulong symbol_value_module(char *, char *); 获取符号地址在 xxx.ko 模块中获取符号地址
int symbol_exists(char *s);int kernel_symbol_exists(char *s); 判断符号是否存在
struct syment *value_search(ulong, ulong *);struct syment *value_search_module(ulong, ulong *); 查询地址是某个符号。
链表、树等遍历函数。、 描述
struct list_data {ulong flags;ulong start;long member_offset;long list_head_offset;ulong end;ulong searchfor;char **structname;int structname_args;char *header;ulong *list_ptr;int (*callback_func)(void *, void *);void *callback_data;long struct_list_offset;}; flags:#define VERBOSE 1#define LIST_ALLOCATE (VERBOSE << 10)LIST_ALLOCATE 该 flags 参数会为 list_ptr 分配对应内存,并将遍历得到的所有成员填充到该内存地址上,最后开发者需要用 FREEBUF 将其释放。VERBOSE 该 flags 参数会在遍历的同时打印输出结构。start: 遍历的起始地址member_offset: 链表节点在结构体中的偏移地址
int do_list(struct list_data *); 可用于 list_head, hlist_head 数据结构的遍历。
int hq_open(void);int hq_close(void); hash_table 启用备份遍历数据,crash-utility 提供的遍历函数都会使用 hq_enter(value) 将数据备份到此处。
int retrieve_list(ulong *buf, int); 拷贝 hash_table 数据到 buf 内存。
int do_rdtree(struct tree_data *); 可用 radix_tree 数据结构的遍历。
int do_rbtree(struct tree_data *); 可用 rb_root 数据结构的遍历。
int do_xatree(struct tree_data *); 可用 xarray 数据结构的遍历。
Int do_mptree(struct tree_data *); 可用 maple 数据结构的遍历。
ulong do_maple_tree(ulong, int, struct list_pair *); 可用 maple 数据结构的遍历。
#define MAPLE_TREE_COUNT (1) MAPLE_TREE_COUNT 仅统计数量
#define MAPLE_TREE_SEARCH (2) MAPLE_TREE_SEARCH 检索
#define MAPLE_TREE_DUMP (3) MAPLE_TREE_DUMP 遍历同时打印结果
#define MAPLE_TREE_GATHER (4) MAPLE_TREE_GATHER 遍历结果拷贝到 list_pair 内存
#define MAPLE_TREE_DUMP_CB (5)
ulong do_xarray(ulong, int, struct list_pair *); 与 do_maple_tree 同理,用于 xarray 数据结构的遍历。
#define XARRAY_COUNT (1)
#define XARRAY_SEARCH (2)
#define XARRAY_DUMP (3)
#define XARRAY_GATHER (4)
#define XARRAY_DUMP_CB (5)
ulong do_radix_tree(ulong, int, struct list_pair *); 同理。
#define RADIX_TREE_COUNT (1)
#define RADIX_TREE_SEARCH (2)
#define RADIX_TREE_DUMP (3)
#define RADIX_TREE_GATHER (4)
#define RADIX_TREE_DUMP_CB (5)

案例参考

开源项目: github.com/Penguin38/O… ,该项目目前已支持转储进程 Core 文件,支持解析 zram,shmem 交换页内存。关于转储细节均与 OpenCoreSDK 一致,内核版本 5.10 ~ 6.1,其它版本未做测试,性能比 gcore 插件快上许多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
lua复制代码crash> mod -s zram zram.ko
crash> mod -s zsmalloc zsmalloc.ko

crash> extend output/arm64/linux-parser.so
output/arm64/linux-parser.so: shared object loaded

crash> lp help core
Usage: core -p <PID> [--output|-o <FILE_PATH>] [option]
Option:
--zram: decompress zram page
--shmem: decompress shared memory on zram page
--filter|-f: filter vma flags
Filter Vma:
0x01: filter-special-vma
0x02: filter-file-vma
0x04: filter-shared-vma
0x08: filter-sanitizer-shadow-vma
0x10: filter-non-read-vma
Example:
lp core -p 1 --zram --shmem -f 0x1b

crash> lp core -p 1515 --zram --shmem -f 0x18
Saved [1515.core].

结合开源项目: github.com/Penguin38/O… 进行解析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
perl复制代码core-parser> top 20 -d --app
>>> '_ZN3art7Runtime9instance_E' = 0x79f9959430
Address Allocations ShallowSize NativeSize ClassName
TOTAL 1181869 68339645 56853669
------------------------------------------------------------
0x6f3a2840 180908 11229040 0 java.lang.String
0x6f3472b8 102778 7739252 0 java.lang.Object[]
0x6fc69090 101915 10599160 0 android.app.usage.UsageEvents$Event
0x6f3f1030 86669 1733380 0 java.util.ArrayList
0x6fb3c3b8 53835 861360 0 android.content.ComponentName
0x6fd00a58 43321 7277928 0 android.content.pm.parsing.component.ParsedActivity
0x6f3872e0 34173 2902220 0 int[]
0x6f349a80 24709 889524 0 sun.misc.Cleaner
0x6fb46d18 24574 614350 0 android.util.ArrayMap
0x6f5ae0f8 24421 586104 0 libcore.util.NativeAllocationRegistry$CleanerThunk
0x6f3afb08 19696 472704 0 java.util.HashMap$Node
0x6f3471d8 18612 148896 0 java.lang.Object
0x6f3875f8 17757 2258552 0 long[]
0x71b0b278 16557 3112716 0 android.os.perfdebug.MessageMonitorImpl$MessageMonitorInfoImpl
0x13413020 16557 198684 0 android.os.perfdebug.MessageMonitorImpl$MessageMonitorInfoImpl$1
0x6fdab5b8 15481 247696 0 android.util.Pair
0x137a9b70 14856 267408 0 com.android.server.pm.permission.LegacyPermissionState$PermissionState
0x6fced578 14055 1068180 0 android.content.pm.parsing.component.ParsedIntentInfo
0x6f3ccd40 13621 544840 0 java.util.HashMap
0x6fdab698 13437 408880 0 android.util.Pair[]

目前公版的状态,未来可能会支持功能,可翻阅历史文章,精力有限不定期更新。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%