snapshot before regression test

This commit is contained in:
t
2026-07-18 19:25:40 +08:00
commit 796222a300
2295 changed files with 206453 additions and 0 deletions

714
vdb.md Normal file
View File

@@ -0,0 +1,714 @@
# 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 顺序推进。**