支持 tls 关键字,全面准备清退 t, c

This commit is contained in:
TermiNexus committed 2026-10-17 23:40:06 +08:00
1 parent 6e17716a69
commit 3242560d02
74 files changed
+524 -576

No files matched your search

+138 -70
View File
@@ -1,5 +1,4 @@
import lib.core.Gen.GenApi as GenApi
import t, c
from stdint import *
import stdio
import string
@@ -262,8 +261,8 @@ class BuildResult:
OutputPath: str
ErrorMsg: str
def __new__(self) -> t.CPtr:
return t.CPtr(_mbuddy.alloc(BuildResult.__sizeof__()))
def __new__(self) -> rawptr:
return rawptr(_mbuddy.alloc(BuildResult.__sizeof__()))
def __init__(self):
self.Success = 0
@@ -576,12 +575,12 @@ def _run_cmd_wait(cmd: str) -> int:
string.memset(&sa, 0, win32.win32base.SECURITY_ATTRIBUTES.__sizeof__())
string.memset(&pi, 0, win32process.PROCESS_INFORMATION.__sizeof__())
sa.nLength = win32.win32base.SECURITY_ATTRIBUTES.__sizeof__()
sa.lpSecurityDescriptor = t.CPtr(0)
sa.lpSecurityDescriptor = None
sa.bInheritHandle = 1
si.cb = win32process.STARTUPINFOA.__sizeof__()
# create_flags=0: the child inherits the parent console (output shown, like system);
# si.dwFlags stays 0 after memset (no STARTF_USESTDHANDLES, no std handles).
ok: int = win32process.CreateProcessA(t.CPtr(0), cmd_line, t.CPtr(0), t.CPtr(0), 1, 0, t.CPtr(0), t.CPtr(0), &si, &pi)
ok: int = win32process.CreateProcessA(None, cmd_line, None, None, 1, 0, None, None, &si, &pi)
# CreateProcessA failure diagnostics: read GetLastError immediately (later calls overwrite
# it). Use warning, not error (error would sys.exit in a worker thread).
if ok == 0:
@@ -597,10 +596,10 @@ def _run_cmd_wait(cmd: str) -> int:
return int(exit_code)
def _llc_task_worker(arg: t.CPtr) -> t.CPtr:
def _llc_task_worker(arg: rawptr) -> rawptr:
"""llc thread entry: only calls _run_cmd_wait, no pool allocation (thread-safe)."""
task: LlcTask* = (LlcTask*)(arg)
if task is None: return t.CPtr(0)
if task is None: return None
# MLIR backend: validate (mlir-opt) -> lower (mlir-translate), then ASan opt -> llc
if task.MlirOptCmd is not None:
mo_rc: int = _run_cmd_wait(task.MlirOptCmd)
@@ -608,21 +607,21 @@ def _llc_task_worker(arg: t.CPtr) -> t.CPtr:
task.ExitCode = mo_rc
task.FailStage = LLC_STAGE_MLIR_OPT
task.Result = 1
return t.CPtr(0)
return None
if task.MlirTranslateCmd is not None:
mt_rc: int = _run_cmd_wait(task.MlirTranslateCmd)
if mt_rc != 0:
task.ExitCode = mt_rc
task.FailStage = LLC_STAGE_MLIR_TRANSLATE
task.Result = 1
return t.CPtr(0)
return None
if task.OptCmd is not None:
opt_rc: int = _run_cmd_wait(task.OptCmd)
if opt_rc != 0:
task.ExitCode = opt_rc
task.FailStage = LLC_STAGE_ASAN_OPT
task.Result = 1
return t.CPtr(0)
return None
llc_rc: int = _run_cmd_wait(task.LlcCmd)
task.ExitCode = llc_rc
if llc_rc != 0:
@@ -631,7 +630,7 @@ def _llc_task_worker(arg: t.CPtr) -> t.CPtr:
else:
task.FailStage = LLC_STAGE_NONE
task.Result = 0
return t.CPtr(0)
return None
def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
@@ -650,7 +649,7 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
return 0
if max_threads <= 0: max_threads = 1
# Thread-handle array: list[str] (str=bytes=i8*, explicit elem_size=8) stores handles;
# list[t.CPtr] append crashes reading page zero. Grab the handle right after start().
# list[rawptr] append crashes reading page zero. Grab the handle right after start().
handles: list[str]* = list[str](_mbuddy, 8)
if handles is None:
VLogger.error("run_llc_parallel: failed to allocate thread handle array", "PhaseB")
@@ -664,13 +663,13 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
# spawn this batch
for j in range(int(batch_n)):
tsk: LlcTask* = (LlcTask*)(uint64(tasks) + sizet(batch_start + j) * slot_size)
th: vthreading.Thread* = vthreading.Thread(_llc_task_worker, t.CPtr(tsk))
th: vthreading.Thread* = vthreading.Thread(_llc_task_worker, rawptr(tsk))
th.start()
# Read the handle right after start() (the Thread object's stack slot may be
# reused; reading self.handle at join could see a cleared/overwritten value).
handles.append(t.CPtr(th.handle))
handles.append(rawptr(th.handle))
for j in range(int(batch_n)):
h_j: t.CPtr = t.CPtr(handles.get(batch_start + j))
h_j: rawptr = rawptr(handles.get(batch_start + j))
wr: uint32 = win32sync.WaitForSingleObject(h_j, 600000)
if wr != 0: VLogger.error("llc thread join timeout/failure (not finished within 600 seconds)", "PhaseB")
win32.win32base.CloseHandle(h_j)
@@ -1052,8 +1051,8 @@ class TbPeLayout:
SizeOfImage: uint64
TextRva: uint64
def __new__(self) -> t.CPtr:
return t.CPtr(_mbuddy.alloc(TbPeLayout.__sizeof__()))
def __new__(self) -> rawptr:
return rawptr(_mbuddy.alloc(TbPeLayout.__sizeof__()))
def __init__(self):
self.Ok = 0
@@ -1071,8 +1070,8 @@ class TbDump:
FuncCap: int
FuncCount: int
def __new__(self) -> t.CPtr:
return t.CPtr(_mbuddy.alloc(TbDump.__sizeof__()))
def __new__(self) -> rawptr:
return rawptr(_mbuddy.alloc(TbDump.__sizeof__()))
def __init__(self):
self.RowBuf = None
@@ -1090,8 +1089,8 @@ class TbPool:
Offs: bytes
OffCount: int
def __new__(self) -> t.CPtr:
return t.CPtr(_mbuddy.alloc(TbPool.__sizeof__()))
def __new__(self) -> rawptr:
return rawptr(_mbuddy.alloc(TbPool.__sizeof__()))
def __init__(self):
self.Pool = None
@@ -1118,9 +1117,12 @@ def _tb_rd_u32(buf: bytes, off: sizet) -> uint32:
def _tb_rd_u64(buf: bytes, off: sizet) -> uint64:
lo: uint64 = uint64(_tb_rd_u32(buf, off))
hi: uint64 = uint64(_tb_rd_u32(buf, off + 4))
return lo | (hi << 32)
# Assemble via memcpy instead of u32 widening + shifts: the manual form left 0xFFFFFFFF in
# the high half (a stale register/slot), which then looked like a wild pointer in the
# stackmap tables. memcpy is exact and little-endian on x86-64.
v: uint64 = 0
string.memcpy(&v, buf + off, 8)
return v
def _tb_wr_u32(buf: bytes, off: sizet, v: uint64):
@@ -1131,8 +1133,18 @@ def _tb_wr_u32(buf: bytes, off: sizet, v: uint64):
def _tb_wr_u64(buf: bytes, off: sizet, v: uint64):
_tb_wr_u32(buf, off, v & 0xFFFFFFFF)
_tb_wr_u32(buf, off + 4, (v >> 32) & 0xFFFFFFFF)
string.memcpy(buf + off, &v, 8)
def _tb_wr_ptr(buf: bytes, off: sizet, p: str):
"""Store a string pointer into a byte table without a ptr->int cast.
Do NOT write `memcpy(buf + off, &p, 8)`: passing `&p` (i8**) to a `rawptr` parameter is
currently compiled as a dereference (it copies the string's first 8 bytes instead of the
pointer value), so go through a typed slot instead.
"""
slot: str* = str*(buf + off)
slot[0] = p
# ---- tiny string helpers (no re module) ----
@@ -1142,6 +1154,18 @@ def _tb_cc(s: str, i: sizet) -> int:
return int(s[i]) & 0xFF
def _tb_str_ok(s: str) -> int:
"""Return 1 when s is a plausible user-space string pointer (not 0, -1 or garbage).
DWARF/objdump text is parsed into pointer-bearing tables; a single bad slot would later be
dereferenced by _tb_cc/strlen and crash the compiler with ASan "unknown address 0xffff...".
Callers use this to reject such a slot at the boundary instead of storing it.
"""
if s is None: return 0
v: uint64 = uint64(s)
return 1 if v >= 65536 and v <= 0x7FFFFFFFFFFF else 0
def _tb_contains(s: str, sub: str) -> int:
if s is None or sub is None: return 0
return 1 if string.strstr(s, sub) is not None else 0
@@ -1331,7 +1355,13 @@ def _tb_quoted_after(mb: memhub.MemBuddy*, s: str, key: str) -> str:
def _tb_dir_lookup(dirs: bytes, count: int, idx: int) -> str:
for i in range(int(count)):
if int(_tb_rd_u32(dirs, sizet(i) * TB_DIR_SIZE)) == idx: return rawptr(_tb_rd_u64(dirs, sizet(i) * TB_DIR_SIZE + 8))
if int(_tb_rd_u32(dirs, sizet(i) * TB_DIR_SIZE)) == idx:
p: uint64 = _tb_rd_u64(dirs, sizet(i) * TB_DIR_SIZE + 8)
# fail-fast: a wild name pointer would crash inside _tb_is_abs_path/strlen later.
if p < 65536 or p > 0x7FFFFFFFFFFF:
VLogger.error(f"--traceback: internal error: DWARF directory record {i} has an invalid name pointer ({p})", "TRACEBACK")
return None
return rawptr(p)
return None
@@ -1345,8 +1375,20 @@ def _tb_resolve_file(mb: memhub.MemBuddy*, files: bytes, fcount: int, dirs: byte
"""Resolve a file-table entry to a path (absolute name wins, else dir join)."""
roff: sizet = sizet(frec) * TB_FILE_SIZE
cached: uint64 = _tb_rd_u64(files, roff + 24)
if cached != 0: return rawptr(cached)
name: str = rawptr(_tb_rd_u64(files, roff + 8))
if cached != 0:
# fail-fast: a wild cached path would crash inside strlen/is_abs_path below; report the
# record that carries it together with the table state instead.
if cached < 65536 or cached > 0x7FFFFFFFFFFF:
VLogger.error(f"--traceback: internal error: DWARF file record {frec} has an invalid cached path pointer ({cached})", "TRACEBACK")
return None
return rawptr(cached)
nptr: uint64 = _tb_rd_u64(files, roff + 8)
if nptr < 65536 or nptr > 0x7FFFFFFFFFFF:
ridx: uint64 = uint64(_tb_rd_u32(files, roff))
rdir: uint64 = uint64(_tb_rd_u32(files, roff + 4))
VLogger.error(f"--traceback: internal error: DWARF file record {frec} has an invalid name pointer ({nptr}); record idx={ridx} dir_index={rdir}, records in table={fcount}", "TRACEBACK")
return None
name: str = rawptr(nptr)
path: str = name
if name is not None and _tb_is_abs_path(name) == 0:
didx: int = int(_tb_rd_u32(files, roff + 4))
@@ -1357,7 +1399,7 @@ def _tb_resolve_file(mb: memhub.MemBuddy*, files: bytes, fcount: int, dirs: byte
if root is not None and _tb_is_abs_path(root) != 0: base = _tb_join(mb, root, base)
path = _tb_join(mb, base, name)
if path is None or string.strlen(path) == 0: path = "??"
_tb_wr_u64(files, roff + 24, uint64(path))
_tb_wr_ptr(files, roff + 24, path)
return path
@@ -1371,6 +1413,10 @@ def _tb_grow_rec(mb: memhub.MemBuddy*, buf: bytes, old_cap: int, rec_size: int,
def _tb_emit_row(mb: memhub.MemBuddy*, d: TbDump*, addr: uint64, path: str, line: int, fname: str = None) -> int:
if d is None: return 1
# Every row must carry a file path. A caller that could not resolve one passes None (or a
# wild sentinel); storing that as-is makes the later strlen() sizing pass fault. Normalise to
# the stackmap's existing "??" convention (the DWARF path already does the same).
if _tb_str_ok(path) == 0: path = "??"
if d.RowCount >= d.RowCap:
ncap: int = d.RowCap * 2
nb: bytes = _tb_grow_rec(mb, d.RowBuf, d.RowCap, TB_ROW_SIZE, ncap)
@@ -1381,11 +1427,10 @@ def _tb_emit_row(mb: memhub.MemBuddy*, d: TbDump*, addr: uint64, path: str, line
d.RowCap = ncap
off: sizet = sizet(d.RowCount) * TB_ROW_SIZE
_tb_wr_u64(d.RowBuf, off, addr)
_tb_wr_u64(d.RowBuf, off + TB_ROW_OFF_FILE, uint64(path))
_tb_wr_ptr(d.RowBuf, off + TB_ROW_OFF_FILE, path)
_tb_wr_u32(d.RowBuf, off + TB_ROW_OFF_LINE, uint64(line))
fv: uint64 = 0
if fname is not None: fv = uint64(fname)
_tb_wr_u64(d.RowBuf, off + TB_ROW_OFF_FUNC, fv)
if _tb_str_ok(fname) != 0: _tb_wr_ptr(d.RowBuf, off + TB_ROW_OFF_FUNC, fname)
else: _tb_wr_u64(d.RowBuf, off + TB_ROW_OFF_FUNC, 0)
d.RowCount = d.RowCount + 1
d.RawRowCount = d.RawRowCount + 1
return 0
@@ -1404,7 +1449,7 @@ def _tb_emit_func(mb: memhub.MemBuddy*, d: TbDump*, low: uint64, high: uint64, n
off: sizet = sizet(d.FuncCount) * TB_FUNC_SIZE
_tb_wr_u64(d.FuncBuf, off, low)
_tb_wr_u64(d.FuncBuf, off + 8, high)
_tb_wr_u64(d.FuncBuf, off + 16, uint64(name))
_tb_wr_ptr(d.FuncBuf, off + 16, name)
d.FuncCount = d.FuncCount + 1
return 0
@@ -1549,10 +1594,10 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*:
if in_line != 0:
if _tb_startswith(st, "debug_line[") != 0:
# new CU: commit pending file, reset both tables
if pkind == 1 and pname is not None and file_count < TB_FILE_CAP:
if pkind == 1 and _tb_str_ok(pname) != 0 and file_count < TB_FILE_CAP:
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx))
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname))
_tb_wr_ptr(files, sizet(file_count) * TB_FILE_SIZE + 8, pname)
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0))
file_count += 1
pkind = 0
@@ -1562,10 +1607,10 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*:
file_count = 0
continue
if _tb_startswith(st, "file_names[") != 0:
if pkind == 1 and pname is not None and file_count < TB_FILE_CAP:
if pkind == 1 and _tb_str_ok(pname) != 0 and file_count < TB_FILE_CAP:
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx))
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname))
_tb_wr_ptr(files, sizet(file_count) * TB_FILE_SIZE + 8, pname)
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0))
file_count += 1
pname = None
@@ -1574,10 +1619,10 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*:
pidx = _tb_bracket_idx(st)
continue
if _tb_startswith(st, "directory_names[") != 0 or _tb_startswith(st, "include_directories[") != 0:
if pkind == 1 and pname is not None and file_count < TB_FILE_CAP:
if pkind == 1 and _tb_str_ok(pname) != 0 and file_count < TB_FILE_CAP:
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx))
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname))
_tb_wr_ptr(files, sizet(file_count) * TB_FILE_SIZE + 8, pname)
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0))
file_count += 1
pname = None
@@ -1586,9 +1631,13 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*:
val: str = _tb_value_after_sep(_tb_after_bracket(st))
if val is not None and _tb_len_trimmed(val) > 0:
if dir_count < TB_DIR_CAP:
_tb_wr_u32(dirs, sizet(dir_count) * TB_DIR_SIZE, uint64(pidx))
_tb_wr_u64(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, uint64(_tb_unquote(mb, val)))
dir_count += 1
dname: str = _tb_unquote(mb, val)
if _tb_str_ok(dname) != 0:
_tb_wr_u32(dirs, sizet(dir_count) * TB_DIR_SIZE, uint64(pidx))
_tb_wr_ptr(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, dname)
dir_count += 1
else:
VLogger.warning("--traceback: ignoring a DWARF directory entry whose name could not be copied", "TRACEBACK")
pkind = 0
else: pkind = 2
continue
@@ -1596,9 +1645,9 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*:
val2: str = _tb_unquote(mb, _tb_ltrim(st + 5))
if pkind == 1: pname = val2
else:
if dir_count < TB_DIR_CAP and val2 is not None:
if dir_count < TB_DIR_CAP and _tb_str_ok(val2) != 0:
_tb_wr_u32(dirs, sizet(dir_count) * TB_DIR_SIZE, uint64(pidx))
_tb_wr_u64(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, uint64(val2))
_tb_wr_ptr(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, val2)
dir_count += 1
pkind = 0
continue
@@ -1608,10 +1657,10 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*:
pdir = _tb_parse_dec(_tb_ltrim(st + 10))
continue
if _tb_startswith(st, "Address") != 0 and _tb_contains(st, "Column") != 0:
if pkind == 1 and pname is not None and file_count < TB_FILE_CAP:
if pkind == 1 and _tb_str_ok(pname) != 0 and file_count < TB_FILE_CAP:
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx))
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname))
_tb_wr_ptr(files, sizet(file_count) * TB_FILE_SIZE + 8, pname)
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0))
file_count += 1
pkind = 0
@@ -1619,10 +1668,10 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*:
pdir = 0
continue
if _tb_cc(linebuf, 0) == 48 and _tb_cc(linebuf, 1) == 120:
if pkind == 1 and pname is not None and file_count < TB_FILE_CAP:
if pkind == 1 and _tb_str_ok(pname) != 0 and file_count < TB_FILE_CAP:
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx))
_tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir))
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname))
_tb_wr_ptr(files, sizet(file_count) * TB_FILE_SIZE + 8, pname)
_tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0))
file_count += 1
pkind = 0
@@ -1657,7 +1706,7 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*:
# ---- DWARF debug_info subprogram parsing ----
if _tb_contains(linebuf, "DW_TAG_") != 0:
if in_prog != 0 and cur_has_low != 0 and cname is not None and string.strlen(cname) > 0:
if in_prog != 0 and cur_has_low != 0 and _tb_str_ok(cname) != 0 and string.strlen(cname) > 0:
hi: uint64 = cur_low + 1
if cur_has_high != 0:
hi = cur_high
@@ -1734,8 +1783,8 @@ class TbCallParse:
Grp: bytes # array of TB_GRP_SIZE slots
GrpCap: int
def __new__(self) -> t.CPtr:
return t.CPtr(_mbuddy.alloc(TbCallParse.__sizeof__()))
def __new__(self) -> rawptr:
return rawptr(_mbuddy.alloc(TbCallParse.__sizeof__()))
def __init__(self):
self.Cr = None
@@ -1776,8 +1825,8 @@ def _tb_grp_get(grp: bytes, cap: int, caller: str, callee: str, do_insert: int)
if uint64(_tb_rd_u32(grp, off + TB_GRP_OFF_USED)) == 0:
if do_insert == 0: return -1
_tb_wr_u32(grp, off + TB_GRP_OFF_USED, uint64(1))
_tb_wr_u64(grp, off + TB_GRP_OFF_CALLER, uint64(caller))
_tb_wr_u64(grp, off + TB_GRP_OFF_CALLEE, uint64(callee))
_tb_wr_ptr(grp, off + TB_GRP_OFF_CALLER, caller)
_tb_wr_ptr(grp, off + TB_GRP_OFF_CALLEE, callee)
_tb_wr_u32(grp, off + TB_GRP_OFF_HEAD, uint64(TB_IDX_NONE))
_tb_wr_u32(grp, off + TB_GRP_OFF_TAIL, uint64(TB_IDX_NONE))
_tb_wr_u32(grp, off + TB_GRP_OFF_CURSOR, uint64(TB_IDX_NONE))
@@ -1811,9 +1860,9 @@ def _tb_cp_add_cr(mb: memhub.MemBuddy*, cp: TbCallParse*, caller: str, callee: s
cp.Cr = nb
cp.CrCap = ncap
off: sizet = sizet(cp.CrN) * TB_CR_SIZE
_tb_wr_u64(cp.Cr, off + TB_CR_OFF_CALLER, uint64(caller))
_tb_wr_u64(cp.Cr, off + TB_CR_OFF_CALLEE, uint64(callee))
_tb_wr_u64(cp.Cr, off + TB_CR_OFF_FILE, uint64(file))
_tb_wr_ptr(cp.Cr, off + TB_CR_OFF_CALLER, caller)
_tb_wr_ptr(cp.Cr, off + TB_CR_OFF_CALLEE, callee)
_tb_wr_ptr(cp.Cr, off + TB_CR_OFF_FILE, file)
_tb_wr_u32(cp.Cr, off + TB_CR_OFF_LINE, uint64(line))
_tb_wr_u32(cp.Cr, off + TB_CR_OFF_NEXT, uint64(TB_IDX_NONE))
cp.CrN = cp.CrN + 1
@@ -1830,8 +1879,8 @@ def _tb_cp_add_fr(mb: memhub.MemBuddy*, cp: TbCallParse*, sym: str, file: str, d
cp.Fr = nb
cp.FrCap = ncap
off: sizet = sizet(cp.FrN) * TB_FR_SIZE
_tb_wr_u64(cp.Fr, off + TB_FR_OFF_SYM, uint64(sym))
_tb_wr_u64(cp.Fr, off + TB_FR_OFF_FILE, uint64(file))
_tb_wr_ptr(cp.Fr, off + TB_FR_OFF_SYM, sym)
_tb_wr_ptr(cp.Fr, off + TB_FR_OFF_FILE, file)
_tb_wr_u32(cp.Fr, off + TB_FR_OFF_DEFLINE, uint64(defline))
cp.FrN = cp.FrN + 1
return 0
@@ -1853,6 +1902,10 @@ def _tb_read_whole(mb: memhub.MemBuddy*, path: str) -> str:
got: LONG = f.read_all(buf, sizet(sz) + 2)
f.close()
if got < 0: return None
# NUL-terminate at the actually read length. The pool buffer is NOT zero-filled (MemBuddy's
# diagnostic fill is 0xCD), so without this the caller's strlen() walks into uninitialised
# bytes and can run past the end of the arena.
buf[got] = 0
return buf
@@ -1873,7 +1926,7 @@ def _tb_parse_f_line(mb: memhub.MemBuddy*, s: str, a: sizet, b: sizet, cp: TbCal
defline: int = int(_tb_parse_dec(s + p))
p = f3 + 1
file: str = _tb_dup_span(mb, s + p, b - p)
if sym is None or file is None: return 0
if _tb_str_ok(sym) == 0 or _tb_str_ok(file) == 0: return 0
return _tb_cp_add_fr(mb, cp, sym, file, defline)
@@ -1899,7 +1952,7 @@ def _tb_parse_c_line(mb: memhub.MemBuddy*, s: str, a: sizet, b: sizet, cp: TbCal
line: int = int(_tb_parse_dec(s + p))
p = e4 + 1
file: str = _tb_dup_span(mb, s + p, b - p)
if caller is None or callee is None or file is None: return 0
if _tb_str_ok(caller) == 0 or _tb_str_ok(callee) == 0 or _tb_str_ok(file) == 0: return 0
return _tb_cp_add_cr(mb, cp, caller, callee, file, line)
@@ -1967,7 +2020,7 @@ def _tb_build_groups(mb: memhub.MemBuddy*, cp: TbCallParse*) -> int:
def _tb_emit_call_row(mb: memhub.MemBuddy*, d: TbDump*, cp: TbCallParse*, img_lo: uint64, caller: str, callee: str, ret_va: uint64) -> int:
"""Emit a row for a return address from the next unconsumed C record of (caller, callee)."""
if caller is None or callee is None or cp.Grp is None or ret_va < img_lo: return 0
if _tb_str_ok(caller) == 0 or _tb_str_ok(callee) == 0 or cp.Grp is None or ret_va < img_lo: return 0
slot: int = _tb_grp_get(cp.Grp, cp.GrpCap, caller, callee, 0)
if slot < 0: return 0
goff: sizet = sizet(slot) * TB_GRP_SIZE
@@ -1984,11 +2037,11 @@ def _tb_emit_call_row(mb: memhub.MemBuddy*, d: TbDump*, cp: TbCallParse*, img_lo
def _tb_emit_entry_row(mb: memhub.MemBuddy*, d: TbDump*, cp: TbCallParse*, img_lo: uint64, addr: uint64, sym: str) -> int:
"""Emit a fallback function-entry row for an objdump label sym (file/line from the F record)."""
if sym is None or cp.Fr is None or cp.FrN <= 0 or addr < img_lo: return 0
if _tb_str_ok(sym) == 0 or cp.Fr is None or cp.FrN <= 0 or addr < img_lo: return 0
for i in range(int(cp.FrN)):
off: sizet = sizet(i) * TB_FR_SIZE
s: str = rawptr(_tb_rd_u64(cp.Fr, off + TB_FR_OFF_SYM))
if s is not None and string.strcmp(s, sym) == 0:
if _tb_str_ok(s) != 0 and string.strcmp(s, sym) == 0:
file: str = rawptr(_tb_rd_u64(cp.Fr, off + TB_FR_OFF_FILE))
dl: int = int(_tb_rd_u32(cp.Fr, off + TB_FR_OFF_DEFLINE))
return _tb_emit_row(mb, d, addr, file, dl, sym)
@@ -2066,7 +2119,7 @@ def _tb_scan_objdump(mb: memhub.MemBuddy*, dump: str, img_lo: uint64, d: TbDump*
j: sizet = lb
while j < le and _tb_cc(dump, j) != 62: j += 1
cur_func = _tb_dup_span(mb, dump + lb, j - lb)
if cur_func is not None: _tb_emit_entry_row(mb, d, cp, img_lo, laddr, cur_func)
if _tb_str_ok(cur_func) != 0: _tb_emit_entry_row(mb, d, cp, img_lo, laddr, cur_func)
continue
# ---- instruction line `ADDR: bytes mnemonic operands` ----
k: sizet = ls
@@ -2275,7 +2328,14 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
pool_need: sizet = 1
i = 0
while i < uniq:
pth: str = rawptr(_tb_rd_u64(d.RowBuf, sizet(i) * TB_ROW_SIZE + TB_ROW_OFF_FILE))
fptr: uint64 = _tb_rd_u64(d.RowBuf, sizet(i) * TB_ROW_SIZE + TB_ROW_OFF_FILE)
# fail-fast: Windows x64 user addresses stay below 0x7FFF_FFFF_FFFF; anything else is a
# wild pointer (0, -1 or an uninitialised slot). Report the record instead of letting
# strlen walk off into unmapped memory (ASan access-violation at 0xffffffffffffffff).
if fptr < 65536 or fptr > 0x7FFFFFFFFFFF:
VLogger.error(f"--traceback: internal error: line record {i} carries an invalid file-path pointer ({fptr})", "TRACEBACK")
return 1
pth: str = rawptr(fptr)
pool_need += string.strlen(pth) + 1
i += 1
# our rows carry the function name directly (string pool); DWARF rows take it from the subprogram table.
@@ -2283,13 +2343,21 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int:
while i < uniq:
fp: uint64 = _tb_rd_u64(d.RowBuf, sizet(i) * TB_ROW_SIZE + TB_ROW_OFF_FUNC)
if fp != 0:
if fp > 0x7FFFFFFFFFFF:
VLogger.error(f"--traceback: internal error: line record {i} carries an invalid function-name pointer ({fp})", "TRACEBACK")
return 1
fns: str = rawptr(fp)
if fns is not None: pool_need += string.strlen(fns) + 1
pool_need += string.strlen(fns) + 1
i += 1
i = 0
while i < fkept:
nm0: str = rawptr(_tb_rd_u64(d.FuncBuf, sizet(i) * TB_FUNC_SIZE + 16))
if nm0 is not None: pool_need += string.strlen(nm0) + 1
nmf: uint64 = _tb_rd_u64(d.FuncBuf, sizet(i) * TB_FUNC_SIZE + 16)
if nmf != 0:
if nmf > 0x7FFFFFFFFFFF:
VLogger.error(f"--traceback: internal error: subprogram record {i} carries an invalid name pointer ({nmf})", "TRACEBACK")
return 1
nm0: str = rawptr(nmf)
pool_need += string.strlen(nm0) + 1
i += 1
p: TbPool* = TbPool()
if p is None:
+5 -6
View File
@@ -1,4 +1,3 @@
import t, c
from stdint import *
import string
import stdlib
@@ -368,10 +367,10 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
class_names_buf: bytes = mb.alloc(sizet(Phase1.MAX_CLASSES) * Phase1.CLASS_NAME_LEN)
parent_names_buf: bytes = mb.alloc(sizet(Phase1.MAX_CLASSES) * Phase1.CLASS_NAME_LEN)
def_sha1s_buf: bytes = mb.alloc(Phase1.MAX_CLASSES * Phase1.SHA1_LEN)
topo_order: t.CPtr = mb.alloc(4 * Phase1.MAX_FILE_DEPS)
topo_count_box: t.CPtr = mb.alloc(4)
generic_file_indices: t.CPtr = mb.alloc(4 * Phase1.MAX_FILE_DEPS)
generic_file_count_box: t.CPtr = mb.alloc(4)
topo_order: rawptr = mb.alloc(4 * Phase1.MAX_FILE_DEPS)
topo_count_box: rawptr = mb.alloc(4)
generic_file_indices: rawptr = mb.alloc(4 * Phase1.MAX_FILE_DEPS)
generic_file_count_box: rawptr = mb.alloc(4)
if generic_file_indices is not None: string.memset(generic_file_indices, 0, 4 * Phase1.MAX_FILE_DEPS)
if generic_file_count_box is not None: string.memset(generic_file_count_box, 0, 4)
topo_count: int = 0
@@ -427,7 +426,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg
file_idx: int = int(i)
if topo_count > 0:
od_addr: uint64 = uint64(topo_order) + i * 4
od_ptr: int* = (int*)(t.CPtr(od_addr))
od_ptr: int* = int*(od_addr)
if od_ptr is not None: file_idx = od_ptr[0]
entry_addr_r: uint64 = uint64(result.Entries) + file_idx * entry_size
+2 -19
View File
@@ -1,31 +1,14 @@
import t, c
from stdint import *
import string
import stdlib
import memhub
import viperlib
import sys
import win32.fileio as fileio
import win32.win32file
import win32.win32base
import ast
import mlirlite
import lib.core.VLogger as VLogger
import lib.core.Gen.Translator as HandlesTranslator
import lib.core.IncludesScanner as IncludesScanner
import lib.Stub.StubMerger as StubMerger
import lib.core.Gen.Generator as GenGenerator
import lib.core.CompilerFactory as CompilerFactory
import lib.Phase.BuildPipeline as BuildPipeline
import lib.Projectrans.Config as Config
import lib.Stub.StubGen.Converter as StubConverter
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect
import lib.Stub.StubMerger.StubMergerIR as StubMergerIR
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
import lib.Phase.Phase1.Phase1Scan as Phase1Scan
import lib.Phase.Phase1.Phase1Topo as Phase1Topo
import lib.Phase.Phase1 as Phase1
import lib.core.Gen.GenApi as GenApi
@@ -40,7 +23,7 @@ import lib.core.Gen.GenApi as GenApi
# _ScanClassInheritance - pre-scan includes files, parse ASTs and collect ClassDef
# names/parent names into flat byte arrays; returns the class count (-1 on failure).
def _ScanClassInheritance(mb: memhub.MemBuddy*, result: IncludesScanner.ScanResult*, reachable_set: str, reachable_count: int, use_reachable: int, sha1_set: str, set_count: int, class_names_buf: bytes, parent_names_buf: bytes, def_sha1s_buf: bytes, generic_file_indices: t.CPtr, generic_file_count_box: t.CPtr) -> int:
def _ScanClassInheritance(mb: memhub.MemBuddy*, result: IncludesScanner.ScanResult*, reachable_set: str, reachable_count: int, use_reachable: int, sha1_set: str, set_count: int, class_names_buf: bytes, parent_names_buf: bytes, def_sha1s_buf: bytes, generic_file_indices: rawptr, generic_file_count_box: rawptr) -> int:
"""Pre-scan includes files and collect class inheritance info."""
if result is None: return -1
# The three flat buffers are mb.alloc'ed by the caller; a NULL buffer would make
@@ -322,7 +305,7 @@ def _AnnIsContainer(ann: ast.AST*) -> int:
return 0
def _ScanTreeForContainers(node: ast.AST*, need_list_box: t.CPtr, need_dict_box: t.CPtr, depth: int = 0):
def _ScanTreeForContainers(node: ast.AST*, need_list_box: rawptr, need_dict_box: rawptr, depth: int = 0):
"""Recursively scan the AST for list/dict container usage."""
# Recursion depth guard: a self-referential AST cycle would recurse until the
# stack is exhausted; fail-fast abort.
+4 -20
View File
@@ -1,30 +1,14 @@
import t, c
from stdint import *
import string
import stdlib
import memhub
import viperlib
import win32.fileio as fileio
import win32.win32file
import win32.win32base
import ast
import mlirlite
import lib.core.VLogger as VLogger
import lib.core.Gen.Translator as HandlesTranslator
import lib.core.IncludesScanner as IncludesScanner
import lib.Stub.StubMerger as StubMerger
import lib.core.Gen.Generator as GenGenerator
import lib.core.CompilerFactory as CompilerFactory
import lib.Phase.BuildPipeline as BuildPipeline
import lib.Projectrans.Config as Config
import lib.Stub.StubGen.Converter as StubConverter
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect
import lib.Stub.StubMerger.StubMergerIR as StubMergerIR
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
import lib.Phase.Phase1.Phase1Scan as Phase1Scan
import lib.Phase.Phase1.Phase1Topo as Phase1Topo
import lib.Phase.Phase1 as Phase1
# Phase1Topo - topologically sort source files by class inheritance and import dependencies.
@@ -32,7 +16,7 @@ import lib.Phase.Phase1 as Phase1
# _TopoSortFiles - topologically sort files by class inheritance (Kahn).
# Builds a "file SHA1 -> dependency SHA1 set" map, computes in-degrees (parent-file first), then outputs the order; returns 0 or -1.
def _TopoSortFiles(mb: memhub.MemBuddy*, result: IncludesScanner.ScanResult*, reachable_set: str, reachable_count: int, use_reachable: int, sha1_set: str, set_count: int, class_names_buf: bytes, parent_names_buf: bytes, def_sha1s_buf: bytes, class_count: int, out_order: t.CPtr, out_count: t.CPtr, temp_dir: str, td_len_ts: sizet) -> int:
def _TopoSortFiles(mb: memhub.MemBuddy*, result: IncludesScanner.ScanResult*, reachable_set: str, reachable_count: int, use_reachable: int, sha1_set: str, set_count: int, class_names_buf: bytes, parent_names_buf: bytes, def_sha1s_buf: bytes, class_count: int, out_order: rawptr, out_count: rawptr, temp_dir: str, td_len_ts: sizet) -> int:
"""Topologically sort files by class inheritance and import dependencies."""
if result is None or out_order is None or out_count is None: return -1
@@ -44,9 +28,9 @@ def _TopoSortFiles(mb: memhub.MemBuddy*, result: IncludesScanner.ScanResult*, re
# 取消整数提升后,模块属性 CDefine(Phase1.MAX_*) 按最小位宽物化为 i16/i8;三段乘积 256*16*17=69632 会在 i16 回绕,
# 首乘数显式 sizet() 加宽到 64 位。上一行 256*17=4352 未超 i16,故无需改。
file_deps_buf: bytes = mb.alloc(sizet(Phase1.MAX_FILE_DEPS) * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN)
file_dep_counts: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4)
file_indegrees: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4)
file_processed: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4)
file_dep_counts: rawptr = mb.alloc(Phase1.MAX_FILE_DEPS * 4)
file_indegrees: rawptr = mb.alloc(Phase1.MAX_FILE_DEPS * 4)
file_processed: rawptr = mb.alloc(Phase1.MAX_FILE_DEPS * 4)
if file_sha1s_buf is None or file_deps_buf is None or file_dep_counts is None or file_indegrees is None or file_processed is None:
if file_sha1s_buf is not None: mb.free(file_sha1s_buf)
-1
View File
@@ -1,4 +1,3 @@
import t, c
from stdint import *
import memhub
+1 -3
View File
@@ -1,5 +1,4 @@
import lib.core.Gen.GenApi as GenApi
import t, c
from stdint import *
import stdio
import string
@@ -38,8 +37,7 @@ define SRC_BUF_SIZE = 1048576
# Max source files (recursive scanning grows the count; too small truncates the list -> undefined symbol)
define MAX_SRC_FILES = 128
@t.NoVTable
class SrcFileEntry:
novirtual class SrcFileEntry:
"""Source file entry"""
Path: str # full path
Sha1: str # first 16 chars of SHA1