fix(dwarf): DIFile 改用绝对路径,栈转储显示完整路径并回读源码行

根因:CurrentFile 是项目相对路径(./Test/LLvmLiteTest/App/main.vp),LLVM 把该目录写成 CU 的 DW_AT_comp_dir,主文件条目用 dir_index: 0 指向 comp_dir;stackmap 写入端只解析 --debug-line(无 comp_dir)⇒ 行记录退化成裸名 main.vp,运行期既显示不全也无法按路径重读源码行

改法:DIFile filename 保留整条绝对路径(相对路径先经 w32file.GetCurrentDirectoryA 前置 CWD,与 Repl.vp 同款低层调用,不经 os._mbuddy);directory 另存目录前缀。无论 LLVM 保留整条 name 还是拆成 dir+basename,写端都得到绝对路径,故无需改写入端
This commit is contained in:
TermiNexus committed 2026-09-27 19:18:16 +08:00
1 parent bb864dff6f
commit a79e723e8d
1 file changed
+34 -6
+34 -6
View File
@@ -5,6 +5,7 @@ import memhub
import string
import stdlib
import viperlib
import w32.win32file as w32file
import lib.core.VLogger as VLogger
# ============================================================
@@ -156,29 +157,56 @@ def _EnsureModuleNodes(pool: memhub.MemBuddy*) -> int:
mod: llvmlite.LLVMModule* = _g_mod
if mod is None:
return 1
# DIFile: basename + absolute directory, backslashes normalised to '/'
# DIFile: **绝对**路径(正斜杠),filename 保留整条路径。
# 为什么必须绝对:本工程给 CurrentFile 的是**项目相对**路径(如
# "./Test/LLvmLiteTest/App/main.vp"),LLVM 会把该目录写成 CU 的 DW_AT_comp_dir,
# 而主文件条目用 `dir_index: 0` 指向 comp_dir;stackmap 写入端只解析
# `llvm-dwarfdump --debug-line`(其中**没有** comp_dir)⇒ 行记录只能退化成裸文件名
# "main.vp":运行期既显示不全,也无法按路径重读源码行(实证:曾整段栈都打印
# `File "main.vp", line N` 而无源码行)。
# 绝对化后,无论 LLVM 保留整条 name(写入端 `_tb_is_abs_path` 命中 ⇒ 原样采用)
# 还是把它拆成 dir+basename(dir_index 指向同一个绝对目录 ⇒ 拼回绝对路径),
# 结果都是绝对路径 —— 故本改动不需要动写入端。
src: str = _g_file_path
if src is None:
src = ""
slen: sizet = string.strlen(src)
nbuf: str = pool.alloc(slen + 4)
cap_n: sizet = slen + 4112
nbuf: str = pool.alloc(cap_n)
if nbuf is None:
VLogger.error("--traceback: DIFile 路径缓冲分配失败,终止编译", "DWARF")
return 1
if slen > 0:
string.strncpy(nbuf, src, slen)
nbuf[slen] = '\0'
if slen > 0 and nbuf[0] != '/' and not (slen >= 2 and nbuf[1] == ':'):
# 相对路径 → 前置当前工作目录。用 w32file 低层调用(同 Repl.vp),
# 不经 os._mbuddy:编译器进程未必初始化过那个内存管理器。
CwdBuf: bytes = pool.alloc(4112)
if CwdBuf is not None:
CwdBuf[0] = '\0'
nc: ULONG = w32file.GetCurrentDirectoryA(ULONG(4111), CwdBuf)
if nc > 0:
# 防御:缓冲区不足时 GetCurrentDirectoryA 的写入内容未定义,强制补 NUL
CwdBuf[4110] = '\0'
viperlib.snprintf(nbuf, cap_n, "%s/%s", CwdBuf, src)
# 归一所有反斜杠(CWD 段同样可能含 '\')
flen: sizet = string.strlen(nbuf)
ni: sizet = 0
for ni in range(slen):
for ni in range(flen):
if nbuf[ni] == '\\':
nbuf[ni] = '/'
# filename 取整条路径;directory 另存其目录前缀(两段各自 NUL 结尾,互不污染)
fname: str = nbuf
directory: str = ""
slash: str = string.strrchr(nbuf, '/')
if slash is not None:
fname = slash + 1
slash[0] = '\0'
directory = nbuf
dlen: sizet = string.strlen(nbuf) - string.strlen(slash + 1) - 1
dirbuf: str = pool.alloc(dlen + 1)
if dirbuf is not None:
string.strncpy(dirbuf, nbuf, dlen)
dirbuf[dlen] = '\0'
directory = dirbuf
dsize: sizet = string.strlen(fname) + string.strlen(directory) + 96
dbuf: str = pool.alloc(dsize)
if dbuf is None: