
# mem-dump 功能指导

## 概述
### 简介
Mem-dump，即内存转储，是指将计算机系统中某一时刻的内存内容（包括操作系统、程序、数据等）保存到文件中的过程。它通常用于故障诊断、调试、性能分析等场景。

### mem-dump 信息
#### 用户空间信息
- 进程内存信息
    - 程序代码和数据：当前运行程序的代码段、数据段（例如全局变量和静态变量），堆栈、堆内存的内容等。
    - 堆栈（Stack）：堆栈中保存了当前线程的调用信息、局部变量、返回地址等。特别是在程序崩溃时，堆栈信息对于定位崩溃点至关重要。
    - 程序计数器（Program Counter，PC）：指示当前执行指令的地址，这有助于分析程序崩溃时到底执行到了哪一行代码。

- 线程信息
    - 线程的堆栈信息：每个线程都有一个独立的堆栈，内存转储通常会记录每个线程的堆栈信息。线程堆栈帮助调试器了解线程执行的调用链。
    - 线程状态：线程的运行状态，如运行、等待、阻塞等状态，以及是否发生了死锁等信息。

- 寄存器信息
    - CPU 寄存器保存了程序执行的状态信息，例如寄存器中的程序计数器（PC）、栈指针（SP）、基指针（BP）、通用寄存器等。

- 内存映射
    - 进程的内存映射：包括代码段、数据段、堆、共享库、栈等的内存区域。有助于分析进程内存的分布情况。

#### 内核信息
- 内核堆栈（Kernel Stack）
    - 内核堆栈保存了内核函数的调用链，通常是操作系统内核或驱动程序在崩溃时的执行状态。

- 内核模块和驱动信息
    - 内存转储会记录加载的内核模块和驱动程序的状态。有助于确定系统崩溃是否由某个特定的模块或驱动程序引起。
    - 加载的模块：包括设备驱动、系统服务等模块，它们的内存地址、大小、状态等。

- 内核数据结构
    - 内存转储可能还会包含一些重要的内核数据结构，如调度队列、进程调度信息、锁状态、文件系统状态等。

- 内核日志和状态信息
    - 内核会记录有关硬件、驱动、文件系统等的状态信息。

#### 崩溃时上下文
- 崩溃时的调用堆栈（Backtrace）
    - 调用堆栈（stack trace）是最重要的崩溃分析信息之一，它提供了从崩溃点到函数调用的完整路径。

- 崩溃的堆栈回溯（Stack Trace）
    - 堆栈回溯显示了程序崩溃时，所有活动线程的调用堆栈信息。

- 内存分配信息
    - 一些内存转储工具可以记录内存分配的历史，如内存泄漏、过度分配等。


## X5 mem-dump 功能介绍
### 功能特点
在进行系统调试或故障复现时，需要先配置好 mem-dump 环境（包括 PC 端和板端）。一旦系统发生 crash，通过预配置的 panic-action，可以让开发板进入不同的 boot 状态，或将内存镜像转储到指定存储介质。
这样开发人员能够在发生 crash 后及时获取内存镜像，对崩溃现场进行详细分析，快速定位问题根源，还能为后续的调试和性能优化提供重要的数据支持。

### 功能原理
mem-dump 是通过约定一块 uboot/kernel 都可访问的内存区域，用做标志和通知。<br>
目前 X5 使用了 PMU 的 AON STATUS 内存区域

| 地址       | 寄存器          | 说明                         |
|------------|---------------|-----------------------------|
| 0x31021000 | aon_status    | aon_status 基地址            |
| 0x31021004 | panic-action  | panic-action配置寄存器，表示发生 panic 后的 boot 状态类型，其 mask 为 0x0000f000 |


目前支持2种 boot 状态类型：

| Boot Index | 类型          | 说明                         | 备注                                                     |
|------------|---------------|-----------------------------|----------------------------------------------------------|
| 0          | normal        | 正常启动 kernel               | 默认启动流程                                              |
| 1          | ubootonce     | uboot 内等待，reset 后正常启动 | 当发生 crash 重启后进入 uboot 命令行等待，用户可执行 mem-dump 操作                         |



## mem-dump 配置
Kernel 提供了 sysfs 接口用于获取和配置 panic action，路径为: `/sys/kernel/hobot-swinfo/panic_action`

### 获取 panic-action
查看当前 panic-action 的状态值。
```shell
cat /sys/kernel/hobot-swinfo/panic_action
0: normal
```

### 配置 panic-action
配置 panic-action 状态类型。
以配置 panic-action 为 ubootonce 为例。
```shell
echo 1 > /sys/kernel/hobot-swinfo/panic_action
```

## mem-dump 使用方法

### 配置 panic-action
针对需要重启后停留在 uboot 命令行状态的场景，可按如下操作。<br>
配置 panic-action 为 ubootonce。
```shell
echo 1 > /sys/kernel/hobot-swinfo/panic_action
```
配置完成后，当故障重启，将进入 uboot 命令行
![uboot-ubootonce](_static/images/1-Mem-Dump-Manual_zh_CN/uboot-ubootonce.png)

### mem-dump 到 emmc 操作
在 uboot 下执行如下命令，可以将内存 dump 到 emmc 的 userdata 分区
```shell
memdump userdata
```
mem-dump 执行内存转储后将在 `/userdata` 目录生成如下文件
- cpu-contexts.bin: cpu 寄存器的信息
- DDRCS0-0.bin：2G 以下的内存文件
- DDRCS1-0.bin： 2G 以上的内存文件，如果使用的内存大于 2G，会存在该文件

执行 mem-dump 内存转储后分析方法可参考 [mem-dump 分析方法](#memdump_analyze)

<span id="memdump_analyze"/> </span>
## mem-dump 分析方法
mem-dump 使用 crash 工具进行解析，用户需要使用 SDK 交付包中 `software_tools\crash_tool` 进行解析。crash_tool 工具包如下:
```
├── arm64-regs.so           // arm64 寄存器扩展文件
├── crash                   // 调试工具
└── parse-cpu-contexts.py   // python 脚本用于解析 CPU 寄存器信息
```

使用步骤如下

- 解析 cpu 的寄存器信息
```shell
python3 parse-cpu-contexts.py cpu-contexts.bin >./coreregs.txt
```

- 使用 crash 工具进入 crash 现场

```shell
./crash vmlinux文件 ./DDRCS0-0.bin@0x84000000,./DDRCS1-0.bin@0x100000000 --machdep vabits_actual=48
```

**注意: vmlinux 文件需要与调试固件内核匹配，可以从路径 `out/build/kernel/vmlinux` 获取**

- 添加扩展文件
```
crash> extend arm64-regs.so
./arm64-regs.so: shared object loaded
```

- 添加 cpu 寄存器信息
```
crash> arm64_core_set -l coreregs.txt
loading cpu core regs from coreregs.txt
loading cpu core regs from coreregs.txt done
```

- 系统调试

例如:打印栈信息
```
crash> bt
PID: 957      TASK: ffff0000c6be9c80  CPU: 2    COMMAND: "bash"
 #0 [ffff80000d75bab0] __arm_smccc_smc at ffff800008026e8c
 #1 [ffff80000d75bad0] __invoke_psci_fn_smc at ffff8000087a0f14
 #2 [ffff80000d75bb10] psci_sys_reset at ffff8000087a1338
 #3 [ffff80000d75bb20] atomic_notifier_call_chain at ffff800008068d10
 #4 [ffff80000d75bb60] do_kernel_restart at ffff80000806b2a0
 #5 [ffff80000d75bb70] machine_restart at ffff8000080188f8
PID: 957      TASK: ffff0000c6be9c80  CPU: 2    COMMAND: "bash"
 #0 [ffff80000d75bab0] __arm_smccc_smc at ffff800008026e8c
 #1 [ffff80000d75bad0] __invoke_psci_fn_smc at ffff8000087a0f14
 #2 [ffff80000d75bb10] psci_sys_reset at ffff8000087a1338
 #3 [ffff80000d75bb20] atomic_notifier_call_chain at ffff800008068d10
 #4 [ffff80000d75bb60] do_kernel_restart at ffff80000806b2a0
 #5 [ffff80000d75bb70] machine_restart at ffff8000080188f8
 #6 [ffff80000d75bb90] emergency_restart at ffff80000806a6d4
 #7 [ffff80000d75bba0] panic at ffff800008a9d6ac
 #8 [ffff80000d75bc80] sysrq_handle_crash at ffff8000084fdf98
 #9 [ffff80000d75bc90] __handle_sysrq at ffff8000084fe7e8
#10 [ffff80000d75bce0] write_sysrq_trigger at ffff8000084fee60
#11 [ffff80000d75bd00] proc_reg_write at ffff80000824de70
#12 [ffff80000d75bd20] vfs_write at ffff8000081d0eb0
#13 [ffff80000d75bdc0] ksys_write at ffff8000081d1264
#14 [ffff80000d75be00] __arm64_sys_write at ffff8000081d130c
#15 [ffff80000d75be10] invoke_syscall at ffff800008027014
#16 [ffff80000d75be40] el0_svc_common.constprop.0 at ffff800008027124
#17 [ffff80000d75be70] do_el0_svc at ffff80000802720c
#18 [ffff80000d75be80] el0_svc at ffff800008ab21d8
#19 [ffff80000d75bea0] el0t_64_sync_handler at ffff800008ab25a8
#20 [ffff80000d75bfe0] el0t_64_sync at ffff800008011544
```


## 常见问题
### 发生 crash 前未配置 panic-action
如果发生 crash 前未配置 panic-action，可手动让开发板进入 uboot。同样可以使用命令 `memdump userdata` 将内存 dump 到 emmc 的 userdata 分区。

### 配置 panic-action 是否影响 reboot 或冷启动
对于非 panic 重启，panic-action不生效，不影响正常启动流程。
