Linux驱动的调试

工欲善其事必先利其器嘛。

调试 Linux 驱动程序是开发过程中非常关键的环节,因为驱动程序直接与硬件交互,任何错误可能导致系统崩溃或硬件故障。调试 Linux 驱动程序可以通过多种方法和工具进行,以下是常见的调试方法和步骤:

### 1. 使用 `printk` 调试

`printk` 是 Linux 内核中最常用的调试方法之一。它类似于用户空间的 `printf`,可以将调试信息输出到内核日志中。

#### 1.1 使用 `printk`

- 在驱动代码中插入 `printk` 语句来打印调试信息:

  ```c
  printk(KERN_INFO "MyDriver: Initialization started\n");
  printk(KERN_DEBUG "MyDriver: Value of x = %d\n", x);
  ```

- 内核日志级别:
  - `KERN_EMERG`:紧急信息,系统崩溃前的信息。
  - `KERN_ALERT`:需要立即处理的信息。
  - `KERN_CRIT`:严重错误。
  - `KERN_ERR`:错误信息。
  - `KERN_WARNING`:警告信息。
  - `KERN_NOTICE`:正常但重要的信息。
  - `KERN_INFO`:信息级别。
  - `KERN_DEBUG`:调试信息。

- 查看内核日志:
  - 使用 `dmesg` 命令查看内核日志:
    ```bash
    dmesg | grep MyDriver
    ```
  - 也可以通过 `journalctl -k` 查看系统日志。

### 2. 使用 `gdb` 调试

`gdb` 是 GNU 调试器,可以用于调试用户空间应用和内核模块。

#### 2.1 内核模块调试

- 加载模块并附加 `gdb`:
  - 使用 `kgdb`(Kernel GNU Debugger)或 `kgdboc`(Kernel GNU Debugger over Console)来调试内核模块。需要配置内核支持 `kgdb`。
  
  - 启动内核调试:
    1. 启动系统时,在内核启动参数中添加 `kgdboc=ttyS0,115200 kgdbwait`。
    2. 在另一台计算机上使用 `gdb` 连接:
       ```bash
       gdb vmlinux
       (gdb) target remote /dev/ttyS0
       ```

- 使用 QEMU 和 GDB 调试内核:
  - 使用 QEMU 启动内核时,可以指定 GDB 调试端口,然后通过 GDB 连接调试:
    ```bash
    qemu-system-x86_64 -kernel bzImage -append "kgdbwait kgdboc=ttyS0,115200" -serial stdio -s -S
    ```
    然后在主机上启动 GDB 并连接到 QEMU:
    ```bash
    gdb vmlinux
    (gdb) target remote :1234
    ```

### 3. 使用动态调试(Dynamic Debugging)

Linux 内核支持动态调试,可以在运行时控制 `printk` 语句的启用和禁用,而不需要重新编译内核或模块。

#### 3.1 启用动态调试

- 在内核启动参数中添加 `dynamic_debug.verbose=1`。
- 使用以下命令控制特定模块的调试信息:
  ```bash
  echo 'module my_driver +p' > /sys/kernel/debug/dynamic_debug/control
  ```

### 4. 使用 `ftrace` 进行函数跟踪

`ftrace` 是 Linux 内核中强大的跟踪工具,适用于函数调用跟踪和性能分析。

#### 4.1 使用 `ftrace` 跟踪函数

- 启用 `ftrace` 并跟踪特定函数:
  ```bash
  echo function > /sys/kernel/debug/tracing/current_tracer
  echo "my_driver_function" > /sys/kernel/debug/tracing/set_ftrace_filter
  ```

- 通过查看 `/sys/kernel/debug/tracing/trace` 文件来获取跟踪信息:
  ```bash
  cat /sys/kernel/debug/tracing/trace
  ```

### 5. 使用 `kprobes` 和 `tracepoints`

#### 5.1 `kprobes`

`kprobes` 允许在运行时动态插入探针到内核代码中的特定地址,用于调试和监视。

- 插入 `kprobe`:
  ```c
  static struct kprobe kp = {
      .symbol_name = "target_function",
  };

  int handler_pre(struct kprobe *p, struct pt_regs *regs) {
      printk(KERN_INFO "kprobe pre_handler: function called\n");
      return 0;
  }

  kp.pre_handler = handler_pre;
  register_kprobe(&kp);
  ```

#### 5.2 `tracepoints`

`tracepoints` 是内核中预定义的跟踪点,驱动程序可以动态启用这些跟踪点以进行调试和性能分析。

- 使用 `tracepoints`:
  - 在代码中插入 `tracepoint`:
    ```c
    tracepoint(my_tp, my_event, arg1, arg2);
    ```

  - 在运行时启用跟踪:
    ```bash
    echo 1 > /sys/kernel/debug/tracing/events/my_tp/my_event/enable
    ```

### 6. 使用 `kgdb`(Kernel GNU Debugger)

`kgdb` 是用于调试运行中的 Linux 内核的调试工具。它可以帮助你在内核崩溃时查看寄存器、堆栈、内核变量等。

#### 6.1 设置 `kgdb`

- 配置内核支持 `kgdb`,并通过串口或网络接口调试内核。
- 启动调试会话并附加到内核。

### 7. 使用虚拟机或模拟器

- **QEMU**:通过 QEMU 模拟内核环境,使用 GDB 进行调试。
- **Buildroot** 或 **Yocto**:创建自定义嵌入式 Linux 环境,并在虚拟机中调试。

### 8. 查看 `sysfs` 和 `procfs`

通过 `/sys` 和 `/proc` 文件系统,可以访问和检查内核状态、驱动程序状态、设备配置等信息。

- 例如,检查模块的参数:
  ```bash
  cat /sys/module/my_driver/parameters/param_name
  ```

### 9. 内核崩溃时使用 `crash` 工具

当内核崩溃时,内存转储(`core dump`)可以用于调试。

- 使用 `crash` 工具分析内核崩溃:
  ```bash
  crash vmlinux vmcore
  ```

### 总结

调试 Linux 驱动程序是一个复杂的过程,需要使用多种工具和方法。`printk` 是最简单和最常用的方法,但对于复杂的驱动程序,使用 `gdb`、`ftrace`、`kprobes`、`kgdb` 等工具可以提供更深入的调试能力。此外,利用设备树和 `sysfs` 等接口可以方便地获取系统状态和配置,从而帮助快速定位问题。根据具体的调试需求和问题性质,选择合适的调试工具和方法可以有效提高开发效率和代码质量。

使用VScode调试驱动

要在 Qualcomm 嵌入式设备上使用 Visual Studio Code (VSCode) 调试 Linux 驱动程序,您需要进行一些配置,使得 VSCode 能够与目标设备进行通信并使用调试工具(如 GDB)调试驱动程序。以下是如何配置和使用 VSCode 调试部署在 Qualcomm 设备上的驱动程序的详细步骤:

### 1. 准备环境

#### 1.1 安装必要的工具

首先,在主机系统上安装以下工具:

- **VSCode**: 下载并安装最新版本的 Visual Studio Code。
- **GDB**: GNU 调试器,用于调试远程设备上的内核模块或驱动程序。
- **GDB Server**: 用于在目标设备上运行 GDB 服务器。
- **SSH**: 用于通过 SSH 远程访问设备(如果是通过网络连接设备)。

#### 1.2 安装 VSCode 扩展

在 VSCode 中安装以下扩展:

- **C/C++**: Microsoft 提供的 C/C++ 语言扩展,支持调试和语法高亮。
- **Remote - SSH**: 用于通过 SSH 连接和调试远程设备。
- **Cortex-Debug**: 如果目标设备是基于 ARM 架构的 Qualcomm 设备,这个扩展可能会有所帮助。

### 2. 在 Qualcomm 设备上设置调试环境

#### 2.1 确保设备上安装了 GDB Server

在 Qualcomm 设备上,您需要确保安装了 GDB Server。大多数嵌入式 Linux 系统都带有 GDB Server,您可以通过以下命令确认:

```bash
gdbserver --version
```

如果没有安装 GDB Server,您可以使用包管理器(例如 `apt` 或 `opkg`)安装,或者手动编译并安装。

#### 2.2 加载内核模块

假设您要调试的驱动程序已经编译为内核模块(.ko 文件),您需要将其加载到设备中:

```bash
insmod my_driver.ko
```

您可以在加载模块时通过 `dmesg` 查看内核日志,确保模块加载成功并获取调试信息。

### 3. 配置 VSCode 进行远程调试

#### 3.1 配置 SSH 连接

1. 打开 VSCode,点击左下角的远程图标,选择 `Remote-SSH: Connect to Host...`。
2. 输入设备的 SSH 地址,格式为 `user@hostname`,然后点击回车。
3. 在弹出的窗口中选择 `Linux` 系统类型。VSCode 将连接到远程设备,并安装必要的组件。

#### 3.2 配置 `launch.json`

在 VSCode 中配置 `launch.json`,以便通过 GDB 远程调试您的驱动程序。以下是一个基本的配置示例:

```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug Qualcomm Driver",
            "type": "cppdbg",
            "request": "launch",
            "program": "/path/to/vmlinux",  // 目标设备上运行的内核映像路径
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "/usr/bin/gdb",  // 本地主机的 gdb 路径
            "setupCommands": [
                {
                    "description": "Enable KGDB",
                    "text": "target remote localhost:1234"
                },
                {
                    "description": "Set Breakpoint",
                    "text": "break <function_name>"  // 设置驱动程序中的断点
                }
            ],
            "logging": {
                "engineLogging": true
            },
            "visualizerFile": "${workspaceFolder}/gdb_visualizer"
        }
    ]
}
```

- `program`: 指定设备上的内核映像路径(例如 `vmlinux`)。
- `miDebuggerPath`: 主机系统中 GDB 的路径。
- `setupCommands`: 包含连接到目标设备上的 GDB Server 的命令。

#### 3.3 启动 GDB Server

在目标设备上,启动 GDB Server 并指定端口和要调试的进程(或内核):

```bash
gdbserver :1234 --attach <pid>
```

如果您调试的是内核模块,可以通过以下方式启动 GDB Server,并使其等待 VSCode 的 GDB 客户端连接:

```bash
gdbserver :1234 /path/to/vmlinux
```

### 4. 启动调试

1. 确保 GDB Server 在设备上运行。
2. 在 VSCode 中,选择刚刚配置的调试配置(例如 `Debug Qualcomm Driver`)。
3. 点击“开始调试”按钮,VSCode 将连接到远程设备上的 GDB Server 并开始调试。

### 5. 调试过程

- **设置断点**: 在 VSCode 中,您可以通过单击行号设置断点。GDB 会在执行到该位置时暂停。
- **单步执行**: 使用 VSCode 的调试工具栏进行单步执行,或在控制台中输入 GDB 命令进行更精细的控制。
- **查看变量和内存**: 您可以在 VSCode 的“变量”窗口中查看当前上下文的变量值,或使用 GDB 命令查看内存状态。

### 6. 总结

通过 VSCode 配置远程 SSH 连接,并结合 GDB 和 GDB Server,可以实现对部署在 Qualcomm 设备上的驱动程序的远程调试。VSCode 提供了良好的用户界面和调试体验,但配置步骤比较复杂,需要一定的熟悉度。您可以通过上述步骤设置调试环境,并根据实际需要调整 `launch.json` 文件,以适应不同的调试场景和设备配置。

 Android的驱动

要在 Qualcomm Android 设备上使用 Visual Studio Code (VSCode) 调试 `.ko` 驱动程序,您可以通过结合 Android 调试桥 (ADB)、GDB 和 GDB Server 来实现远程调试。以下是详细步骤:

### 1. 准备环境

#### 1.1 安装必要工具

在主机系统上安装以下工具:

- **VSCode**: 安装 Visual Studio Code。
- **Android SDK 和 NDK**: Android SDK 包含 ADB,NDK 包含用于调试的 GDB。
- **ADB**: Android 调试桥,用于与 Android 设备通信。
- **GDB 和 GDB Server**: 用于远程调试驱动程序。

#### 1.2 安装 VSCode 扩展

在 VSCode 中安装以下扩展:

- **C/C++**: 支持 C/C++ 语言的调试和语法高亮。
- **Android**: 允许 VSCode 与 Android 设备进行交互。
- **Remote - SSH** (可选): 如果需要通过 SSH 远程连接到 Android 设备,可以使用此扩展。

### 2. 设置 Android 设备

#### 2.1 启用开发者选项和 USB 调试

1. 在 Android 设备上,进入“设置” -> “关于手机”。
2. 连续点击“版本号”七次,启用开发者选项。
3. 在“开发者选项”中,启用“USB 调试”。

#### 2.2 使用 ADB 连接设备

通过 USB 连接 Android 设备,并使用 ADB 确认连接:

```bash
adb devices
```

确保设备在列表中显示。

### 3. 编译并加载 `.ko` 驱动程序

#### 3.1 编译驱动程序

首先,确保已经在主机上编译好驱动程序的 `.ko` 文件,并将其推送到 Android 设备:

```bash
adb push my_driver.ko /data/local/tmp/
```

#### 3.2 加载驱动程序

使用 ADB shell 进入设备,然后加载驱动程序:

```bash
adb shell
insmod /data/local/tmp/my_driver.ko
```

使用 `dmesg` 检查驱动程序是否正确加载。

### 4. 设置 GDB 和 GDB Server

#### 4.1 在 Android 设备上启动 GDB Server

启动 GDB Server 并附加到内核:

```bash
adb shell
gdbserver :5039 --attach $(pgrep -n my_driver)  # 使用你的驱动进程名
```

#### 4.2 配置 ADB 端口转发

将设备上的 GDB 端口转发到本地主机上:

```bash
adb forward tcp:5039 tcp:5039
```

### 5. 配置 VSCode 进行远程调试

#### 5.1 配置 `launch.json`

在 VSCode 工作区中创建或修改 `.vscode/launch.json` 文件,配置 GDB 远程调试:

```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug Android Kernel Module",
            "type": "cppdbg",
            "request": "launch",
            "program": "/path/to/vmlinux",  // 内核映像的路径
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerServerAddress": "localhost:5039",  // 本地转发的端口
            "miDebuggerPath": "/path/to/gdb",  // GDB 的路径,一般位于 NDK 中
            "setupCommands": [
                {
                    "description": "Connect to target",
                    "text": "target remote localhost:5039"
                },
                {
                    "description": "Set Breakpoint",
                    "text": "break <your_module_function>"  // 需要调试的函数
                }
            ],
            "logging": {
                "engineLogging": true
            },
            "visualizerFile": "${workspaceFolder}/gdb_visualizer"
        }
    ]
}
```

关键字段:

- `program`: 指定设备上的内核映像(如 `vmlinux`)。
- `miDebuggerServerAddress`: ADB 转发的端口。
- `miDebuggerPath`: 主机上 GDB 的路径,通常在 Android NDK 中。

### 6. 启动调试

1. 确保 GDB Server 正在设备上运行,并且 ADB 端口已正确转发。
2. 在 VSCode 中,选择 `Debug Android Kernel Module` 配置。
3. 点击“开始调试”按钮,VSCode 将连接到设备上的 GDB Server,并开始调试。

### 7. 调试过程

- **设置断点**: 在 VSCode 中,点击行号区域设置断点。
- **单步执行**: 使用调试工具栏中的按钮进行单步调试。
- **查看变量和内存**: 在“变量”窗口中查看变量值,或使用 GDB 命令检查内存内容。

### 8. 总结

通过 VSCode 配置远程调试,可以有效调试部署在 Qualcomm Android 设备上的 `.ko` 驱动程序。这个流程结合了 ADB、GDB 和 GDB Server 的使用,尽管设置较为复杂,但提供了强大的调试能力,适合深度分析和解决驱动程序的问题。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值