Files
TransPyC/vdb.md
2026-07-18 19:25:40 +08:00

715 lines
23 KiB
Markdown
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.
# TransPyC 调试器vdb设计文档
> **状态**:设计阶段,暂不实现
> **创建时间**2026-06-26
> **目标**:为 TransPyC 编译的程序提供源码级调试能力,支持断点、变量查看、单步、调用栈、异常栈跟踪
---
## 1. 背景与动机
TransPyC 将 Python 子集编译为 LLVM IR 再编译为原生机器码。当前编译产物**完全不含调试信息**(无 DWARF/PDB运行时崩溃只能看到错误码和消息无法定位源码行、查看变量、回溯调用栈。
本设计文档规划一个 TransPyC 专用调试器 **vdb**,目标是:
- 源码级断点(`break main.py:30`
- 变量查看(`print x` / `info locals`
- 单步执行(`step` / `next`
- 调用栈回溯(`backtrace`
- 异常栈跟踪(`raise` 时记录栈帧)
- 硬错误捕获segfault / 溢出)
---
## 2. 现状分析
### 2.1 已有可复用资产
| 资产 | 位置 | 复用方式 |
|------|------|---------|
| 变量映射三件套 `variables`/`_direct_values`/`_reg_values` | `lib/core/LLVMCG/BaseGen.py:79-81` | 序列化到 .tpd 供变量查看 |
| 变量类型信息 `var_type_info`/`var_signedness`/`var_struct_class` | `lib/core/LLVMCG/BaseGen.py:82-112,124` | 序列化为 VarBinding.TypeDesc |
| 源码行号跟踪 `_current_lineno`/`_set_node_info`/`_get_source_line` | `lib/core/LLVMCG/BaseGen.py:126-127,138,297-440` | 扩展为 SourceMap |
| 类元信息表 `class_members`/`class_member_defaults`/`class_parent`/`Vtables` | `lib/core/LLVMCG/BaseGen.py:85-100` | 序列化为 TypeMeta |
| 符号表序列化 `SymbolTable.ToDict` | `lib/core/SymbolTable.py:265-319` | vdb 直接加载,无需重建 |
| 异常机制 `__eh_msg_out__`/`__eh_code_out__` | `lib/core/Handles/HandlesRaise.py` / `HandlesTry.py` / `HandlesExprCall.py` | 扩展携带栈信息 |
| VLogger `compile_error(file, line, code)` 三元组 | `lib/core/VLogger.py:286` | 复用错误位置格式 |
| 本地堆指针记录 `_local_heap_ptrs`/`_var_to_heap_ptr` | `lib/core/LLVMCG/MemoryOps.py:7-15` | 堆对象追踪起点 |
### 2.2 关键缺口
| 能力 | 现状 | 缺口说明 |
|------|------|---------|
| DWARF 调试信息 | ❌ 完全未生成 | `lib/` 下无任何 `DIBuilder`/`!dbg`/`DICompileUnit` 调用 |
| PDB 调试信息 | ❌ 完全未生成 | Windows 下 WinDbg/VS 无法源码级调试 |
| 源码行 → IR 指令映射 | ❌ 无数据结构 | 最核心缺口,需从零构建 SourceMap |
| 变量名 → 运行时内存 | ⚠️ 仅编译期 ephemeral | `Gen.variables` 随 Gen 实例销毁,需持久化 |
| 类型元信息运行时查询 | ❌ 无 RTTI/反射 | `class_members` 等均编译期状态,未发射到二进制 |
| 运行时调用栈 | ❌ 完全无 | 异常仅传 `(code, msg)`,无栈帧链 |
| 硬错误处理 | ❌ 无 | `__builtin_trap` 仅声明未实现segfault/SIGFPE 无捕获 |
| 断点/单步/变量查看 | ❌ 完全无 | `lib/` 下搜索 `breakpoint`/`step`/`watch` 零命中 |
---
## 3. 路线选择
### 3.1 方案 A纯 DWARF + GDB/LLDB
**优点**:生态成熟,无需自研前端
**缺点**
- llvmlite 的 DIBuilder 支持度需验证
- Python 语义与 C 不完全对应(`self` 是指针但 Python 视为对象)
- SHA1 命名导致符号名难读
- 泛型特化类型(`Stack[int]`)在 DWARF 中表达困难
- 跨模块符号(`6d71a13705da41ad.main`)可读性差
### 3.2 方案 B纯自研 vdb
**优点**:完全匹配 Python 语义,可显示原始源码,理解泛型/SHA1/跨模块
**缺点**:开发量大,需自研调试协议与前端
### 3.3 方案 C混合推荐
- 生成轻量 DWARF仅行号 + 变量名)让 GDB 可用作后备
- 同时生成 TransPyC 专用调试元数据 `.tpd` 文件
- vdb 前端优先使用 `.tpd`,可降级到 GDB 后端
**本设计采用方案 C**,但优先实现 `.tpd` + vdbDWARF 作为可选增强。
---
## 4. 核心数据结构
### 4.1 .tpd 文件格式TransPyC Debug
每个 `.ll` 文件配套生成一个 `.tpd` 文件JSON 格式),包含以下结构:
```python
from dataclasses import dataclass, field
from typing import Any
@dataclass
class IrLocation:
"""单条 IR 指令的源码位置映射"""
FuncName: str # mangled 函数名(含 SHA1 头,如 '6d71a13705da41ad.main'
BlockName: str # 基本块名(如 'entry'、'if.then'
InstrIdx: int # 指令在块中的索引
SourceFile: str # 源码相对路径
LineNo: int # 源码行号
ColNo: int # 列号
@dataclass
class VarBinding:
"""变量绑定信息(作用域内)"""
VarName: str # Python 变量名(如 'x'、'self'
LlvmName: str # alloca 名或 SSA如 '%x'、'%".1"'
TypeDesc: str # 类型描述('i32' / 'Stack[int]*' / 'i8*'
IsSigned: bool # 是否有符号整数
StructClass: str | None # 所属结构体类名(如 'Stack[int]'
StartLine: int # 作用域起始行
EndLine: int # 作用域结束行
Storage: str # 'stack' | 'register' | 'direct' | 'global'
StackOffset: int | None # 栈偏移(仅 'stack'
@dataclass
class TypeMeta:
"""类型元数据"""
TypeName: str # 'Stack[int]' / 'IntPair' / 'memory_block'
Members: list[tuple[str, str, int]] # (成员名, 类型, 字节偏移)
Size: int # 总大小(字节)
Align: int # 对齐
Parent: str | None # 父类名
IsException: bool # 是否异常类
ExceptionCode: int # 异常码(仅 IsException=True
HasVTable: bool # 是否有虚表
IsPacked: bool # 是否紧凑布局
@dataclass
class FuncSig:
"""函数签名"""
FuncName: str # mangled 名
RawName: str # 原始 Python 名(去 SHA1
ReturnType: str # 返回类型描述
ParamNames: list[str]
ParamTypes: list[str]
IsExport: bool # 是否导出(@t.CExport
IsMethod: bool # 是否实例方法
ClassName: str | None # 所属类名(方法)
SourceFile: str
StartLine: int
EndLine: int
HasException: bool # 是否可能抛异常(有 __eh_msg_out__
@dataclass
class TpdFile:
"""完整的 .tpd 调试信息文件"""
SourceMap: list[IrLocation]
VarScopes: dict[str, list[VarBinding]] # FuncName -> bindings
TypeMeta: dict[str, TypeMeta]
FuncSignatures: dict[str, FuncSig]
ExceptionCodes: dict[int, str] # code -> exception name
SourceFiles: dict[str, list[str]] # file -> 源码行列表(供 vdb 显示上下文)
ModuleSha1: str | None
Version: str = "1.0"
```
### 4.2 序列化格式
`.tpd` 文件使用 JSON字段名采用 PascalCase与代码一致。示例
```json
{
"Version": "1.0",
"ModuleSha1": "6d71a13705da41ad",
"SourceFiles": {
"App/main.py": ["import t", "import stdio", ...]
},
"SourceMap": [
{"FuncName": "main", "BlockName": "entry", "InstrIdx": 0, "SourceFile": "App/main.py", "LineNo": 255, "ColNo": 0},
...
],
"VarScopes": {
"6d71a13705da41ad.test_generic_stack": [
{"VarName": "s", "LlvmName": "%s", "TypeDesc": "Stack[int]*", "IsSigned": false, "StructClass": "Stack[int]", "StartLine": 66, "EndLine": 73, "Storage": "stack", "StackOffset": 0}
]
},
"TypeMeta": {
"Stack[int]": {
"TypeName": "Stack[int]",
"Members": [["data", "[16 x i32]", 0], ["top", "i32", 64]],
"Size": 68,
"Align": 4,
"Parent": null,
"IsException": false,
"ExceptionCode": 0,
"HasVTable": false,
"IsPacked": false
}
},
"ExceptionCodes": {
"1": "ValueError",
"2": "TypeError",
"99": "Exception",
"100": "MyCustomError"
}
}
```
---
## 5. 实现阶段
### 5.1 Phase 1源码级断点最小可用
**目标**`break main.py:30` + `continue` + `run`
#### 5.1.1 编译器改动
**位置**`lib/core/LLVMCG/BaseGen.py`
1. **扩展 `_set_node_info`**:记录当前指令的源码位置到 `SourceMap`
```python
def _set_node_info(self, Node: ast.AST) -> None:
self._current_lineno = getattr(Node, 'lineno', 0)
self._current_col = getattr(Node, 'col_offset', 0)
self._current_node_info = f" [line {self._current_lineno}, col {self._current_col}]"
# 新增:记录到 SourceMap
if self.func and self.builder and self.builder.block:
loc: IrLocation = IrLocation(
FuncName=self.func.name,
BlockName=self.builder.block.name,
InstrIdx=len(self.builder.block.instructions),
SourceFile=self._current_source_file or '',
LineNo=self._current_lineno,
ColNo=self._current_col
)
self._source_map.append(loc)
```
2. **插入断点桩**:在每行源码对应的首条 IR 指令前插入
```llvm
; 运行时断点桩声明
declare void @__tpc_breakpoint(i32 %line, i8* %file)
; 在 main.py:255 的首条指令前插入
%src_file_ptr = getelementptr [12 x i8], [12 x i8]* @.src.main_py, i32 0, i32 0
call void @__tpc_breakpoint(i32 255, i8* %src_file_ptr)
```
3. **条件性插入**:仅当 `--debug` 编译选项启用时插入release 构建完全剥离
4. **生成 .tpd 文件**:函数编译结束时,序列化 `SourceMap``.tpd`
#### 5.1.2 运行时库
新建 `includes/vdb_runtime.py`
```python
import t
import c
# 全局断点表(行号 -> 是否启用)
_Breakpoints: t.CArray[t.CInt, 65536] | t.CPtr = [0]
# 当前调试器状态0=运行, 1=暂停)
_DebugState: t.CInt = 0
# 当前源码文件名(用于断点匹配)
_CurrentFile: t.CArray[t.CInt8T, 256] | t.CPtr = [0]
@t.CExport
def __tpc_breakpoint(line: t.CInt, file: t.CPtr) -> None:
"""断点桩入口,由编译器在每个源码行前插入调用"""
# 检查是否启用断点
if _Breakpoints[line] == 0:
return
# 命中断点,陷入调试器循环
_DebugState = 1
_tpc_debug_loop(line, file)
def _tpc_debug_loop(line: t.CInt, file: t.CPtr) -> None:
"""调试器主循环,等待用户命令"""
# 通过 IPC 或 stdio 与 vdb 前端通信
# 解析命令continue / step / next / print / info / backtrace
while _DebugState == 1:
cmd: t.CArray[t.CInt8T, 256] | t.CPtr = [0]
stdio.scanf("%s", cmd)
# ... 命令分派
```
#### 5.1.3 vdb 前端
新建 `lib/vdb/` 目录:
```
lib/vdb/
├── __init__.py
├── TpdLoader.py # .tpd 文件加载器
├── BreakpointManager.py # 断点管理
├── DebugSession.py # 调试会话主循环
├── CommandParser.py # 命令解析
└── SourceView.py # 源码显示
```
**核心命令**
- `break <file>:<line>` / `b <file>:<line>` — 设置断点
- `delete <n>` / `d <n>` — 删除断点
- `continue` / `c` — 继续执行
- `run` / `r` — 启动程序
- `list` / `l` — 显示当前源码上下文
- `info breakpoints` — 列出断点
### 5.2 Phase 2变量查看
**目标**`print x` / `info locals` / `info args`
#### 5.2.1 编译器改动
**位置**`lib/core/LLVMCG/FuncGen.py``lib/core/Handles/HandlesFunctions.py`
函数编译结束时,序列化变量绑定:
```python
def _serialize_var_scope(self, FuncName: str) -> list[VarBinding]:
bindings: list[VarBinding] = []
for var_name, llvm_val in self.variables.items():
if llvm_val is None:
continue
binding: VarBinding = VarBinding(
VarName=var_name,
LlvmName=llvm_val.name if hasattr(llvm_val, 'name') else '',
TypeDesc=self._describe_llvm_type(llvm_val.type),
IsSigned=self.var_signedness.get(var_name, True),
StructClass=self.var_struct_class.get(var_name),
StartLine=self._func_start_line,
EndLine=self._func_end_line,
Storage='stack',
StackOffset=self._get_alloca_offset(llvm_val) # 新增:记录栈偏移
)
bindings.append(binding)
# 同样处理 _direct_values 和全局变量
return bindings
```
#### 5.2.2 运行时变量读取
调试器通过以下方式读取变量值:
1. **栈变量**:通过 `StackOffset` + 当前栈帧基址读取
2. **全局变量**:通过符号表查找全局符号地址
3. **寄存器变量**:需调试器理解 SSA 值较复杂Phase 2 可跳过,仅支持 stack
#### 5.2.3 类型渲染
```python
def RenderValue(llvm_val: bytes, type_meta: TypeMeta, type_desc: str) -> str:
"""根据类型渲染变量值"""
if type_desc == 'i32':
return str(int.from_bytes(llvm_val, 'little', signed=True))
elif type_desc == 'i8*':
# 尝试作为 C 字符串读取
return f'"{read_cstring(llvm_val)}"'
elif type_desc.endswith('*') and type_meta:
# 结构体指针:展开成员
return RenderStruct(llvm_val, type_meta)
...
```
### 5.3 Phase 3单步执行
**目标**`step` / `next` / `finish`
基于 SourceMap 实现:
- `step`(步入):在下一行源码的首条 IR 指令前设临时断点,包括被调用函数内部
- `next`(步过):在当前函数的下一行设临时断点,跳过函数调用
- `finish`(步出):在当前函数的返回点设临时断点
**实现**
1. 查 SourceMap 找到当前行的下一个源码行
2. 设置临时断点(一次性)
3. `continue`
4. 命中后自动删除临时断点
### 5.4 Phase 4调用栈跟踪
**目标**`backtrace` / `bt` / `frame <n>`
#### 5.4.1 编译器改动
每个函数入口/出口插入栈帧维护调用:
```llvm
; 函数入口
call void @__tpc_push_frame(
i8* getelementptr([N x i8], [N x i8]* @.func.name, i32 0, i32 0), ; 函数名
i8* getelementptr([M x i8], [M x i8]* @.src.file, i32 0, i32 0), ; 源文件
i32 255 ; 起始行
)
; 函数出口(每个 ret 前)
call void @__tpc_pop_frame()
```
#### 5.4.2 运行时栈结构
```python
import t
@t.CStruct
class FrameInfo:
FuncName: t.CPtr # i8* 函数名
SrcFile: t.CPtr # i8* 源文件
LineNo: t.CInt # 当前行号(动态更新)
PrevFrame: 'FrameInfo' | t.CPtr # 上一帧(链表)
# 全局栈顶
_FrameTop: FrameInfo | t.CPtr = t.CPtr(0)
@t.CExport
def __tpc_push_frame(func_name: t.CPtr, src_file: t.CPtr, line: t.CInt) -> None:
frame: FrameInfo | t.CPtr = c.cast(FrameInfo, mb.alloc(FrameInfo.__sizeof__()))
frame.FuncName = func_name
frame.SrcFile = src_file
frame.LineNo = line
frame.PrevFrame = _FrameTop
_FrameTop = frame
@t.CExport
def __tpc_pop_frame() -> None:
if _FrameTop != t.CPtr(0):
old: FrameInfo | t.CPtr = _FrameTop
_FrameTop = _FrameTop.PrevFrame
mb.free(old)
```
#### 5.4.3 断点桩更新当前行
`__tpc_breakpoint` 命中时,更新 `_FrameTop.LineNo`
```python
@t.CExport
def __tpc_breakpoint(line: t.CInt, file: t.CPtr) -> None:
if _Breakpoints[line] == 0:
return
if _FrameTop != t.CPtr(0):
_FrameTop.LineNo = line
_DebugState = 1
_tpc_debug_loop(line, file)
```
### 5.5 Phase 5异常栈跟踪
**目标**`raise ValueError("msg")` 时输出完整调用栈
#### 5.5.1 编译器改动
**位置**`lib/core/Handles/HandlesRaise.py`
`_HandleRaiseLlvm` 中,抛异常前捕获栈:
```python
def _HandleRaiseLlvm(self, Node: ast.Raise) -> None:
# ... 原有错误码计算 ...
# 新增:捕获调用栈
capture_call = self.Gen.builder.call(
self._get_or_declare_function('__tpc_capture_trace', ir.FunctionType(ir.VoidType(), [])),
[]
)
# ... 原有异常传播逻辑 ...
```
#### 5.5.2 异常结构扩展
`__eh_msg_out__`i8**)扩展为指向包含栈的结构:
```python
import t
@t.CStruct
class ExceptionInfo:
Code: t.CInt
Message: t.CArray[t.CInt8T, 256] | t.CPtr
TraceDepth: t.CInt
TraceFuncs: t.CArray[t.CPtr, 64] # 函数名指针数组
TraceLines: t.CArray[t.CInt, 64] # 对应行号
TraceFiles: t.CArray[t.CPtr, 64] # 对应源文件
```
#### 5.5.3 未捕获异常处理
`main` 函数返回前检查异常,打印栈:
```python
def main() -> t.CInt:
# ... 用户代码 ...
# 编译器自动插入:检查未捕获异常
if _UnhandledException != t.CPtr(0):
_tpc_print_trace(_UnhandledException)
return 1
return testcheck.end()
```
### 5.6 Phase 6硬错误捕获
**目标**segfault / 除零 / 栈溢出时进入调试器
#### 5.6.1 信号处理器注册
```python
import t
import c
@t.CExport
def __tpc_signal_handler(sig: t.CInt) -> None:
"""OS 信号处理入口"""
__tpc_capture_trace()
# 打印信号类型
if sig == 11: # SIGSEGV
stdio.printf("Segmentation fault\n")
elif sig == 8: # SIGFPE
stdio.printf("Arithmetic exception\n")
# 陷入调试器
_tpc_debug_loop(0, t.CPtr(0))
def __tpc_install_signal_handlers() -> None:
"""在 main 入口前自动调用"""
c.signal(11, __tpc_signal_handler) # SIGSEGV
c.signal(8, __tpc_signal_handler) # SIGFPE
```
#### 5.6.2 编译器改动
`main` 函数入口自动插入 `__tpc_install_signal_handlers()` 调用(仅 `--debug` 模式)。
---
## 6. vdb 命令参考
### 6.1 启动与控制
| 命令 | 缩写 | 说明 |
|------|------|------|
| `run [args]` | `r` | 启动被调试程序 |
| `continue` | `c` | 继续执行至下一断点 |
| `step` | `s` | 单步进入函数 |
| `next` | `n` | 单步跳过函数 |
| `finish` | `f` | 执行至当前函数返回 |
| `quit` | `q` | 退出调试器 |
### 6.2 断点管理
| 命令 | 缩写 | 说明 |
|------|------|------|
| `break <file>:<line>` | `b` | 设置源码行断点 |
| `break <func>` | `b` | 设置函数入口断点 |
| `tbreak <file>:<line>` | `tb` | 临时断点(命中后删除) |
| `delete <n>` | `d` | 删除断点 n |
| `info breakpoints` | `i b` | 列出所有断点 |
### 6.3 变量查看
| 命令 | 缩写 | 说明 |
|------|------|------|
| `print <expr>` | `p` | 打印表达式值 |
| `info locals` | `i lo` | 列出当前局部变量 |
| `info args` | `i ar` | 列出函数参数 |
| `display <expr>` | - | 每次暂停自动显示 |
| `set <var>=<val>` | - |修改变量值 |
### 6.4 栈操作
| 命令 | 缩写 | 说明 |
|------|------|------|
| `backtrace` | `bt` | 显示调用栈 |
| `frame <n>` | `fr` | 切换到第 n 帧 |
| `up` | - | 向上切换一帧 |
| `down` | `do` | 向下切换一帧 |
### 6.5 源码浏览
| 命令 | 缩写 | 说明 |
|------|------|------|
| `list` | `l` | 显示当前行上下文 |
| `list <file>:<line>` | `l` | 显示指定位置 |
| `info source` | `i so` | 显示当前源文件信息 |
### 6.6 类型与结构
| 命令 | 缩写 | 说明 |
|------|------|------|
| `ptype <typename>` | `pt` | 显示类型定义 |
| `info types` | `i ty` | 列出所有类型 |
| `info exceptions` | `i ex` | 列出异常码表 |
---
## 7. 实现优先级
| 优先级 | 阶段 | 价值 | 改动量 |
|--------|------|------|--------|
| P0 | Phase 1源码断点+ Phase 2变量查看 | 80% 调试价值 | 小 |
| P1 | Phase 4调用栈 | 崩溃定位关键 | 中 |
| P2 | Phase 5异常栈 | Python 语义匹配 | 中 |
| P3 | Phase 3单步 | 体验提升 | 中(依赖 Phase 1 |
| P4 | Phase 6硬错误 | 兜底保护 | 中 |
| P5 | DWARF 生成 | GDB 互操作 | 大(可选) |
---
## 8. 风险与考量
### 8.1 性能开销
- **断点桩**:仅 `--debug` 构建启用release 完全剥离
- **IR 膨胀**:每行插入断点桩约增加 10-20% IR 体积,可接受
- **运行时开销**:断点桩检查为单次数组访问 + 分支预测,开销极低
- **栈帧维护**:每函数调用增加 2 次 `push/pop_frame`,约 5-10% 调用开销
### 8.2 兼容性
- **SHA1 命名**vdb 需理解 SHA1 前缀,通过 `ModuleSha1` 字段还原为 `模块名.函数名` 显示
- **泛型特化**`Stack[int]` 需作为完整类型名处理TypeMeta 中保留特化名
- **跨模块**`.tpd` 文件按模块生成vdb 启动时合并所有相关 `.tpd`
- **`main` 特化**`main` 函数无 SHA1 头vdb 需特殊处理
### 8.3 安全性
- **栈帧分配**:使用 `mb.alloc` 而非 `c.malloc`,确保与 TransPyC 内存管理一致
- **信号处理器**:异步信号中避免调用非异步信号安全函数,仅设置标志位
### 8.4 限制
- **优化构建**:高优化级别(`-O2`+)下变量可能被优化掉,`.tpd` 中的 VarBinding 可能失效
- **内联函数**:内联后栈帧信息丢失,需在 `.tpd` 中标记 `IsInline`
- **尾调用优化**:破坏调用栈链,需禁用或特殊处理
---
## 9. 文件结构规划
```
lib/vdb/ # vdb 调试器前端
├── __init__.py
├── TpdLoader.py # .tpd 文件加载与合并
├── BreakpointManager.py # 断点管理
├── DebugSession.py # 调试会话主循环
├── CommandParser.py # 命令解析
├── SourceView.py # 源码显示
├── ValueRenderer.py # 变量值渲染
├── StackWalker.py # 调用栈遍历
└── IpcChannel.py # 与被调试进程的 IPC 通信
lib/core/LLVMCG/
└── DebugInfoGen.py # 新增:.tpd 生成器(编译器侧)
includes/
└── vdb_runtime.py # 运行时断点/栈帧/信号处理库
```
---
## 10. 与现有系统的集成点
### 10.1 编译器集成
- **`Phase2Translator.py`**:在生成 `.ll` 后,调用 `DebugInfoGen.GenerateTpd(module, gen, output_path)`
- **`BaseGen.py`**`_set_node_info` 扩展记录 SourceMap函数编译结束序列化 VarScope
- **`HandlesFunctions.py`**:函数入口/出口插入 `__tpc_push_frame`/`__tpc_pop_frame`(仅 debug 模式)
- **`HandlesRaise.py`**`_HandleRaiseLlvm` 插入 `__tpc_capture_trace`
### 10.2 project.json 配置
新增 `debug` 选项:
```json
{
"options": {
"debug": true,
"debug_info": "tpd"
}
}
```
- `debug: true` — 启用调试构建(插入断点桩、栈帧维护、信号处理)
- `debug_info: "tpd"` — 生成 .tpd 文件(默认)
- `debug_info: "dwarf"` — 生成 DWARF未来支持
- `debug_info: "both"` — 同时生成(未来支持)
### 10.3 命令行集成
```bash
# 编译带调试信息
transpyc build --debug
# 直接启动调试器
transpyc debug ./output/MyApp.exe
# 等价于
vdb ./output/MyApp.exe
```
---
## 11. 开放问题
1. **llvmlite DIBuilder 支持度**:需验证 llvmlite 是否暴露 DIBuilder 接口,决定 DWARF 生成可行性
2. **IPC 协议**vdb 前端与被调试进程的通信方式(管道/Socket/共享内存)待定
3. **远程调试**:是否支持远程调试(如 ViperOS 裸机目标)需进一步设计
4. **表达式求值**`print x.y.z` 等复杂表达式是否需要完整 Python 解释器,还是简化为路径访问
5. **多线程**TransPyC 当前是否支持多线程,调试器如何处理线程切换
---
## 12. 参考文档
- 现状分析:基于 2026-06-26 对 `lib/core/``lib/Projectrans/` 的完整搜索
- 异常机制:`wiki/09-exceptions.md`
- 导入机制:`wiki/10-imports.md`
- 符号表:`lib/core/SymbolTable.py`
- 类型系统:`lib/core/TypeSpec.py` / `lib/core/Handles/HandlesBase.py`
- LLVM 生成:`lib/core/LLVMCG/BaseGen.py` / `FuncGen.py` / `MemoryOps.py`
---
> **本文档为设计阶段产物,暂不实现。待社区需求或开发优先级提升后,按 Phase 1 → 2 → 4 → 5 → 3 → 6 顺序推进。**