Files
openidea/docs/zh/guide/debugging.mdx
T

195 lines
16 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "调试"
description: "通过内置的 Debug Adapter Protocol 客户端设置断点、单步执行、查看变量和计算表达式。"
---
OpenIDEA 通过 [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/)(DAP)调试程序。每种语言在自己的语言定义(`languages/<id>.toml` 的 `[debugger]` 表)里指定调试适配器,调试运行配置时 IDE 会启动对应的适配器。命令和快捷键沿用 IntelliJ IDEA 的习惯,在 IDEA 里熟悉的操作大多可以直接用。
## 启动调试会话
只要[运行配置](/zh/guide/run)带有调试适配器,就可以调试:
- 点击 `main` 函数或测试旁边的边栏运行图标,选择 **调试**。
- 在工具栏的运行小部件里选好配置,点击调试按钮。
- **运行 › 调试** 调试当前选中的配置;**运行 › 调试…** 先选择配置;**运行 › 调试上下文配置** 调试光标处的程序或测试。
配置用哪个调试器,由 **运行 › 编辑配置…** 中的 **调试适配器** 字段决定。设为 **无** 即可关闭该配置的调试。
会话启动前,OpenIDEA 会先保存所有打开的文件。如果适配器没有安装,IDE 会给出提示;对于能自动安装的调试器,还会提供 **安装并调试**。
调试工具窗口(`⌘5` / `Alt+5`)每个会话一个标签页,包含两个视图:
- **线程和变量**:线程列表、选中线程的栈帧,以及选中帧的变量。库代码的帧默认折叠,用 **显示所有帧** 展开。
- **Console**:程序输出,以及一个输入行,可在选中帧里计算表达式。用 **浏览控制台历史**(`⌘⌥E` / `Ctrl+Alt+E`)翻看之前输入过的表达式。
<Note>这两个视图的标签名目前还没有翻译,中文界面下也显示英文。</Note>
## 支持的调试器
| 语言 | 调试适配器 | 获取方式 |
| --------------------------------- | ---------------------------------------- | ------------------------------------------------------------------ |
| Java | Microsoft java-debug(运行在 JDT LS 内) | 一键安装 |
| Kotlin | kotlin-debug-adapter | 一键安装 |
| C、C++、Objective-C、Swift | `lldb-dap` | 随 LLVM、Xcode(`xcrun -f lldb-dap`)和 Swift 6+ 工具链提供 |
| Rust、Zig | CodeLLDB | 一键安装 |
| Go | Delve(`dlv`) | 一键安装(通过 `go install`,需先装好 Go) |
| Python | debugpy | 一键安装一份私有副本,所有解释器共用;也可以 `pip install debugpy` |
| JavaScript、TypeScript(Node.js) | vscode-js-debug | 一键安装 |
| C#、F# | netcoredbg | 一键安装 |
| PHP | PHP Debug (Xdebug) | 适配器一键安装;PHP 本身需要装 Xdebug 3 扩展 |
| Shell 脚本 | Bash Debug | 一键安装 |
| Ruby | rdbg | `gem install debug` |
| Elixir | ElixirLS 调试器 | 一键安装 |
| Dart、Flutter | `dart debug_adapter` | 随 Dart / Flutter SDK 提供 |
| OCaml | earlybird | `opam install earlybird` |
| GDScript | Godot 编辑器 | Godot 4 |
C 和 C++ 的配置也可以改用 GDB 14 及以上版本(`gdb -i dap`):在 **调试适配器** 字段里选 **GDB(C、C++)**。IDE 不会自动安装 GDB,需要自己装(`apt install gdb`、`dnf install gdb`、`brew install gdb`)。
一键安装在 **设置 › 语言和框架 › 语言服务器** 里,调试器和语言服务器列在一起,可以在这里安装、更新,或者指定自己安装的版本。
<Warning>
在 macOS 上,CodeLLDB 和 Delve 可能要开启开发者模式后才能启动或附加。执行一次 `sudo DevToolsSecurity
-enable`,再重新启动调试会话。
</Warning>
## 断点
点击行号即可添加或移除行断点,也可以用 **切换行断点**(`⌘F8` / `Ctrl+F8`)。在边栏上:
- `⌥` 点击(`Alt` 点击)添加临时断点,命中一次后自动移除。
- `⇧` 点击(`Shift` 点击)添加不挂起程序的日志断点,并打开它的属性。
- 中键点击已有断点,启用或禁用它。
- 右键点击断点,编辑它的属性。
空行和只有注释的行不能加断点。默认情况下,行断点只能放在有调试器的语言文件里;如需放开限制,在 **设置 › 构建、执行、部署 › 调试器** 中打开 **允许在任意文件中设置断点**。
### 断点属性
| 选项 | 作用 |
| -------------------- | ---------------------------------------------------------------------- |
| **已启用** | 不删除断点,只是打开或关闭它。 |
| **挂起** | 关闭后,命中断点时程序继续运行(适合只记日志)。 |
| **条件** | 只有表达式为真时才停下。 |
| **命中次数** | 只有命中次数满足条件时才停下(语法由适配器决定,例如 `5` 或 `>= 5`)。 |
| **“已到达断点”消息** | 每次命中时在控制台输出一条消息。 |
| **计算并记录** | 每次命中时计算一个表达式并输出它的值。 |
断点对话框里也有这些选项,另外还有 **命中后移除**,勾选后断点变为临时断点。这些选项能否生效取决于适配器:条件、命中次数和日志消息都是 DAP 功能,大多数适配器支持,但不是全部。
### 其他断点类型
| 类型 | 添加方式 |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| 临时行断点 | **切换临时行断点**(`⌘⌥⇧F8` / `Ctrl+Alt+Shift+F8`),或在边栏 `⌥` 点击 |
| 方法断点 | 在方法声明上执行 **切换方法断点**,或在断点对话框里点 **添加方法断点** |
| 字段监视点 | 在字段声明上执行 **切换字段监视点**,或在变量视图里对某个值选 **添加字段监视点**。可以选择在 **字段访问**、**字段修改** 或两者时挂起。 |
| 异常断点 | 断点对话框的 **异常断点** 部分列出适配器提供的异常过滤器(例如已捕获和未捕获的异常)。 |
方法断点和字段监视点需要适配器支持 DAP 的函数断点和数据断点。debugpy、java-debug、js-debug 和 CodeLLDB 的异常过滤器会直接列出;其他适配器的过滤器要用它调试过一次才会出现。
### 断点对话框
**查看断点…**(`⌘⇧F8` / `Ctrl+Shift+F8`)列出项目中的所有断点。可以在这里启用、编辑、删除断点和跳转到断点位置,打开 **静音断点**(暂时跳过所有断点而不删除),以及设置异常过滤器。**移除所有断点** 会清空列表。
断点按项目保存,重启后仍然保留。适配器无法设置的断点会标为未验证。
## 单步执行
下面的命令在 **运行** 菜单和调试工具窗口的工具栏上。
| 命令 | macOS | Windows / Linux |
| ---------------------------- | ------------- | --------------- |
| 恢复程序 | `⌘⌥R` 或 `F9` | `F9` |
| 暂停程序 | — | — |
| 步过 | `F8` | `F8` |
| 步入 | `F7` | `F7` |
| 智能步入 | `⇧F7` | `Shift+F7` |
| 步出 | `⇧F8` | `Shift+F8` |
| 强制步过 | `⌥⇧F8` | `Alt+Shift+F8` |
| 强制步入 | `⌥⇧F7` | `Alt+Shift+F7` |
| 运行到光标处 | `⌥F9` | `Alt+F9` |
| 强制运行到光标处 | `⌘⌥F9` | `Ctrl+Alt+F9` |
| 显示执行点 | `⌥F10` | `Alt+F10` |
| 重置帧 | — | — |
| 停止 | `⌘F2` | `Ctrl+F2` |
| 重新运行(在调试工具窗口中) | `⌘R` | `Ctrl+F5` |
- 当前行有多个调用时,**智能步入** 可以选择要进入哪一个。
- 带“强制”的命令会忽略途中的断点。
- 程序挂起时,行上还会出现一个内嵌的“运行到光标处”按钮(调试器设置中的 **显示内嵌的“运行到光标处”按钮**)。
- **重置帧** 回到选中帧所在方法的开头,需要适配器支持。
## 查看和修改值
程序挂起时:
- **变量** 视图显示选中帧的变量。右键点击某个值,可以 **设置值…**(`F2`)、**复制值**、**复制名称**、**跳转到源代码**(`F4`)和 **添加到监视**。
- 监视表达式显示在变量视图顶部,每次停下或切换帧时重新计算。用 **添加到监视** 添加,用 **移除监视** 删除。
- 在编辑器里悬停变量会显示它的值。`⌥` 点击(`Alt` 点击)或 **快速计算表达式**(`⌘⌥F8` / `Ctrl+Alt+F8`)计算鼠标下的表达式或选中的内容。
- 局部变量的值会内联显示在使用它们的行尾。
- **计算表达式…**(`⌥F8` / `Alt+F8`)打开对话框,在选中帧里计算任意表达式,带历史记录,也能把表达式加入监视。
表达式使用被调试程序的语言,由调试适配器计算,能写什么取决于适配器。
## 附加到正在运行的进程
**运行 › 附加到进程…**(`⌥⇧F5` / `Ctrl+Alt+F5`)列出调试器可以附加的本用户进程,按调试器分组:
| 分组 | 进程 |
| ---------------- | ------------------------------------------------------- |
| Java (JDWP) | 带 JDWP agent 启动的 JVM |
| Node.js | 用 `--inspect` 启动的 Node 进程 |
| Python (debugpy) | Python 进程(注入 debugpy,或连接它的 `--listen` 端口) |
| Go (Delve) | Go 二进制程序 |
| Native (LLDB) | 其他进程;装了 CodeLLDB 就用它,否则用 `lldb-dap` |
输入文字可按名称、PID 或命令行过滤。
### 远程调试配置
要调试在别处(另一台机器、容器里)启动的进程,在 **运行 › 编辑配置…** 里添加下面的配置。它们只能调试,不会启动进程。
| 配置 | 作用 |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **远程 JVM 调试** | 附加到带 JDWP agent 启动的 JVM,或者等待 JVM 主动连接(**调试器模式**:**附加到远程 JVM** / **监听远程 JVM**)。表单会给出远程 JVM 需要加的启动参数。 |
| **Go 远程** | 附加到用 `dlv --headless` 启动的 Delve 服务。 |
| **Python 远程调试 (debugpy)** | 附加到用 debugpy 监听的 Python 进程。 |
| **附加到 Node.js** | 附加到用 `--inspect` 启动的 Node.js 进程。 |
| **PHP 远程调试 (Xdebug)** | 监听 Xdebug 连接,用于 php-fpm 或容器里运行的 PHP。 |
| **附加到 Godot** | 调试 Godot 编辑器正在运行的游戏。 |
每个表单都有 **主机** 和 **端口** 字段,并给出远程端的启动命令。远程代码所在目录与本地不同时,用 **本地根目录** 和 **远程根目录** 做路径映射。
## 各语言的特有功能
- **Java HotSwap**:**运行 › 调试操作 › 重新加载已更改的类** 编译改动,并把变化的类重新加载到正在运行的 Java 调试会话中。已经在执行的帧要等返回后才会用上新代码。保存后 JDT LS 自动完成构建时,IDE 也会提示是否重新加载。
- **Maven 和 Gradle**:调试 Maven 或 Gradle 配置时,IDE 会让 JVM 带上 JDWP agent 启动,再用 java-debug 附加上去。
- **Dart / Flutter**:Dart 会话运行时可以用 **热重载** 和 **热重启**。
- **PHP**:如果 PHP 解释器没有加载 Xdebug,断点会被跳过;会话启动时 IDE 会提示。
- **Python**:**设置 › 构建、执行、部署 › Python 调试器** 中有 **调试时自动附加到子进程** 和 **兼容 Gevent**。
## 设置
**设置 › 构建、执行、部署 › 调试器**:
- **命中断点时显示调试窗口**、**在断点处聚焦应用程序**、**进程终止时隐藏调试窗口**。
- **断点**:**允许在任意文件中设置断点**、**显示内嵌的“运行到光标处”按钮**。
- **数据视图**:**内联显示值**、**按字母顺序对值排序**、**鼠标悬停时显示值工具提示**、**选中代码时显示值提示**、**值工具提示延迟(毫秒)**。
- **单步执行**:**不要步入库脚本**(Python 只调试自己的代码;JavaScript 跳过 `node_modules` 和 Node.js 内部代码)。
## 快捷键
| 操作 | macOS | Windows / Linux |
| ----------------- | ------ | --------------- |
| 调试 | `⌃D` | `Shift+F9` |
| 调试…(选择配置) | `⌃⌥D` | `Alt+Shift+F9` |
| 调试上下文配置 | `⌃⇧D` | — |
| 切换行断点 | `⌘F8` | `Ctrl+F8` |
| 查看断点… | `⌘⇧F8` | `Ctrl+Shift+F8` |
| 计算表达式… | `⌥F8` | `Alt+F8` |
| 附加到进程… | `⌥⇧F5` | `Ctrl+Alt+F5` |
| 调试工具窗口 | `⌘5` | `Alt+5` |
以上都是默认键位,可以在[键位映射](/zh/guide/keymap)设置中修改。