debug(gen): 一次性取证插桩——Generator 结构体登记/查找全链路(用完删除)

覆盖点(全部以 [DBG-GEN] 为前缀,仅打印不改行为):
- StructGenMixin.register_struct:IN(name/sha1/ty/StructCount)、DEDUP(命中条目)
- StructGenMixin.add_field:逐字段打印写入 Generator 条目的字段名与下标
- StructGenMixin.find_struct_by_module:IN / HIT / MISS
- StructGenMixin.lookup_field(field=FuncGenBase):struct_ty 名、按 Ty 指针命中条目的
  全字段名、以及结构体表内所有含 "Generator" 的条目
- VpiReader._inject_class_struct_declare:IN / EXISTING / RENUM-SKIP / EMPTY /
  FIELD-FAIL / REGISTERED
- ClassGenDef.translate_class_def:EXISTING / REGISTER / DONE

目的:一次重建即可判定 Generator.FuncGenBase 查不到是"命中空/旧条目""Ty 错配"
还是"字段名悬空",并看清是哪条登记路径产出的条目。
This commit is contained in:
TermiNexus committed 2026-10-02 02:18:55 +08:00
1 parent 1ad7abf33d
commit 01e95b51cf
3 files changed
+118 -1

No files matched your search

+24
View File
@@ -2780,6 +2780,14 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
flat_buf_c[p_len] = '_'
string.strcpy(flat_buf_c + p_len + 1, cls_name)
real_name = flat_buf_c
# [DBG-GEN] 一次性取证(用完删除)
_dg_v_isgen: int = 0
if string.strcmp(real_name, "Generator") == 0:
_dg_v_isgen = 1
_dg_v_s: str = "<null>"
if src_sha1 is not None:
_dg_v_s = src_sha1
stdio.printf("[DBG-GEN] vpi inject_class IN name=Generator src_sha1=%s\n", _dg_v_s)
# REPL(ReplStubLayoutMode,见文件末"REPL:includes 类完整布局与虚表恢复"):
# 本类若已由 .stub.ll 驱动的路径接管 ⇒ 这里整类让位——已登记(或本遍就地
# 登记成功)只标可见;父类未就绪 ⇒ 本遍不登记(收尾遍补齐);布局不可信 ⇒
@@ -2799,6 +2807,9 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
existing_c: GenTypes.StructEntry* = GenApi.find_struct_by_module(real_name, src_sha1)
if existing_c is not None and existing_c.Ty is not None:
GenApi.add_visible_struct(pool, real_name)
if _dg_v_isgen != 0:
stdio.printf("[DBG-GEN] vpi inject_class EXISTING name=Generator fcount=%d\n",
existing_c.FieldCount)
return 1
# REnum 类(class X(t.REnum))跳过:布局 {i32 __tag, <payload>} 由
# ClassGenEnum._translate_renum_def 按变体计算;vpi 侧按普通 struct 注册
@@ -2806,6 +2817,8 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
# 留给源模块正式翻译注册。LLVMType 本就因 field_count==0 早退,此守卫把
# 该行为显式化,避免将来 REnum 带直接字段时被误注册为普通 struct。
if _vpi_class_is_renum(class_cd) != 0:
if _dg_v_isgen != 0:
stdio.printf("[DBG-GEN] vpi inject_class RENUM-SKIP name=Generator\n")
return 0
# 规则 5.5 的证据前置(**必须早于**下方字段注解解析):
# 本函数在**注入期**解析字段注解(GenApi.resolve_annotation_type →
@@ -2862,6 +2875,12 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
pool, m_aa_c.annotation, imported_modules, from_imports, trans, 0)
if field_ty_c is None:
# 字段类型解析失败:不注册该类(留给源模块编译注册),不 fatal
if _dg_v_isgen != 0:
_dg_v_fn: str = "<null>"
if m_tgt_c.id is not None:
_dg_v_fn = m_tgt_c.id
stdio.printf("[DBG-GEN] vpi inject_class FIELD-FAIL name=Generator field=%s\n",
_dg_v_fn)
return 0
if field_count < GenTypes.FIELD_MAX:
field_names_buf[field_count] = sizet(m_tgt_c.id)
@@ -2870,6 +2889,8 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
# 3. vpi 存根不含类字段(只序列化 class 名 + def 签名)→ field_count 恒为 0;注册空类会让源模块编译时 find_struct_by_module 命中空类
# → "结构体已注册但字段数为0" InternalCompilerError。故改为不注册:依赖模块已编译时命中真实类(上方已处理),未编译时由 _deps_pending 多遍收敛。
if field_count == 0:
if _dg_v_isgen != 0:
stdio.printf("[DBG-GEN] vpi inject_class EMPTY name=Generator\n")
return 0
# 4. 构建 ParamNode 链表
first_node_c: rawptr[llvmlite.ParamNode] = None
@@ -2941,6 +2962,9 @@ def _inject_class_struct_declare(pool: memhub.MemBuddy*,
af_ty_c: llvmlite.LLVMType* = (llvmlite.LLVMType*)(field_types_buf[afi_c])
GenApi.add_field(pool, entry_c, af_name_c, af_ty_c)
GenApi.add_visible_struct(pool, real_name)
if _dg_v_isgen != 0:
stdio.printf("[DBG-GEN] vpi inject_class REGISTERED name=Generator fcount=%d ty=%s\n",
field_count, type_name_c)
return 1
+16
View File
@@ -94,6 +94,16 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
# 检查是否已注册(用 SHA1 区分跨模块同名类)
existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1)
# [DBG-GEN] 一次性取证(用完删除)
_dg_cd_isgen: int = 0
if class_name is not None and string.strcmp(class_name, "Generator") == 0:
_dg_cd_isgen = 1
if existing is not None:
stdio.printf("[DBG-GEN] classdef Generator EXISTING fcount=%d declare_only=%d\n",
existing.FieldCount, trans._declare_only)
else:
stdio.printf("[DBG-GEN] classdef Generator EXISTING none declare_only=%d\n",
trans._declare_only)
# 空类注册不完整检测:existing FieldCount==0 但源类体声明了字段(vpi 注入/注册缺陷)。
# 标记 _deps_pending 延迟会让空 entry 持久存在、多遍死锁不收敛 ⇒ 改为中和旧 entry
# (置空 Name + Ty=None,使 find_struct_by_module 不再命中),走下方完整注册路径重建。
@@ -571,6 +581,9 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
if entry is None:
VLogger.error(f"failed to register {class_name}", "CLASS")
return 0
if _dg_cd_isgen != 0:
stdio.printf("[DBG-GEN] classdef Generator REGISTER field_count=%d declare_only=%d\n",
field_count, trans._declare_only)
# B5:记录 packed 标记到 StructEntry(供 __sizeof__/字段布局等派生查询)
if is_packed_cd != 0:
@@ -649,6 +662,9 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
if fe_c is not None:
fe_c.IsConst = 1
if _dg_cd_isgen != 0:
stdio.printf("[DBG-GEN] classdef Generator DONE fcount=%d\n", entry.FieldCount)
# Phase 1a 声明模式:只注册 struct + 设置 OOP 标志,不翻译方法体
if trans._declare_only == 1:
self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, struct_ty, class_name, 1)
+78 -1
View File
@@ -594,12 +594,35 @@ novirtual class StructGenMixin:
sha1 参数在注册时直接设置 ModuleSha1(避免 set_struct_sha1 找错 entry)。
"""
if self.init_struct_table(pool) == 0: return None
# [DBG-GEN] 一次性取证(用完删除)
_dg_isgen: int = 0
if name is not None and string.strcmp(name, "Generator") == 0:
_dg_isgen = 1
_dg_sh0: str = "<null>"
if sha1 is not None:
_dg_sh0 = sha1
_dg_tn0: str = "<null>"
_dg_g0: str = llvmlite.get_struct_name(struct_ty)
if _dg_g0 is not None:
_dg_tn0 = _dg_g0
stdio.printf("[DBG-GEN] register_struct IN name=Generator sha1=%s ty=%s count_before=%d\n",
_dg_sh0, _dg_tn0, self.StructCount)
# 用类型指针去重(同一类型不重复注册,支持跨模块同名类)
# 用 uint64 指针值比较(is 比较会触发类型安全检查解引用悬空 Ty)
# 走 find_struct_by_type(其 Ty 索引判定已整体停用、恢复原线性扫描),
# 去重语义 = 原去重扫描"首个 Ty 指针相等条目"(首注册优先),逐字节一致。
existing: GenTypes.StructEntry* = self.find_struct_by_type(struct_ty)
if existing is not None: return existing
if existing is not None:
if _dg_isgen != 0:
_dg_en: str = "<null>"
if existing.Name is not None:
_dg_en = existing.Name
_dg_es: str = "<null>"
if existing.ModuleSha1 is not None:
_dg_es = existing.ModuleSha1
stdio.printf("[DBG-GEN] register_struct DEDUP name=Generator -> existing name=%s sha1=%s fcount=%d\n",
_dg_en, _dg_es, existing.FieldCount)
return existing
if self.StructCount >= STRUCT_MAX:
VLogger.error(f"table full, cannot register {name}", "STRUCT")
return None
@@ -748,6 +771,10 @@ novirtual class StructGenMixin:
if struct_entry.FieldCount >= FIELD_MAX:
VLogger.error(f"field table full for {struct_entry.Name}", "STRUCT")
return -1
# [DBG-GEN] 一次性取证(用完删除)
if struct_entry.Name is not None and string.strcmp(struct_entry.Name, "Generator") == 0:
stdio.printf("[DBG-GEN] add_field Generator[%d] name=%s\n",
struct_entry.FieldCount, field_name)
idx: int = struct_entry.FieldCount
fe: GenTypes.FieldEntry* = self._get_field_entry(struct_entry, idx)
if fe is None: return -1
@@ -1118,6 +1145,14 @@ novirtual class StructGenMixin:
if self.StructCount < 0 or self.StructCount > 200000:
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_module)", "STRUCT")
stdlib.exit(1)
# [DBG-GEN] 一次性取证(用完删除)
_dg_fbm_isgen: int = 0
if string.strcmp(name, "Generator") == 0:
_dg_fbm_isgen = 1
_dg_fbm_s: str = "<null>"
if sha1 is not None:
_dg_fbm_s = sha1
stdio.printf("[DBG-GEN] find_struct_by_module IN name=Generator sha1=%s\n", _dg_fbm_s)
if sha1 is not None:
# 名索引快速路径:同名条目都位于 >= 首个同名下标处,故可从该下标起扫描
# name+sha1(等价原全表扫描"首个 name 且 sha1 命中")。
@@ -1134,9 +1169,14 @@ novirtual class StructGenMixin:
if entry.ModuleSha1 is not None:
# 同上:sha1 判等蕴含首字符相等,先比首字符再 strcmp。
if entry.ModuleSha1[0] == sha1[0] and string.strcmp(entry.ModuleSha1, sha1) == 0:
if _dg_fbm_isgen != 0:
stdio.printf("[DBG-GEN] find_struct_by_module HIT name=Generator sha1=%s fcount=%d\n",
entry.ModuleSha1, entry.FieldCount)
return entry
# SHA1 查找失败:不回退到 find_struct(会返回跨模块同名错误 entry)
# 返回 None 让调用方创建新类型,避免 Phase B 用错误类型短路
if _dg_fbm_isgen != 0:
stdio.printf("[DBG-GEN] find_struct_by_module MISS name=Generator\n")
return None
# 无 SHA1:按类名查找第一个
return self.find_struct(name)
@@ -1304,6 +1344,43 @@ novirtual class StructGenMixin:
if struct_ty is None or field_name is None or self.StructTable is None:
return None
# [DBG-GEN] 一次性取证(用完删除)
if string.strcmp(field_name, "FuncGenBase") == 0:
_dg_ty: str = self._extract_struct_name(struct_ty)
_dg_ty_t: str = "<non-struct>"
if _dg_ty is not None:
_dg_ty_t = _dg_ty
stdio.printf("[DBG-GEN] lookup_field 'FuncGenBase' struct_ty=%s\n", _dg_ty_t)
_dg_pm: GenTypes.StructEntry* = self.find_struct_by_type(struct_ty)
if _dg_pm is not None:
_dg_pn: str = "<null>"
if _dg_pm.Name is not None:
_dg_pn = _dg_pm.Name
_dg_ps: str = "<null>"
if _dg_pm.ModuleSha1 is not None:
_dg_ps = _dg_pm.ModuleSha1
stdio.printf("[DBG-GEN] ptr-match name=%s sha1=%s fcount=%d\n",
_dg_pn, _dg_ps, _dg_pm.FieldCount)
_dg_fi: int = 0
while _dg_fi < _dg_pm.FieldCount:
_dg_fe: GenTypes.FieldEntry* = self._get_field_entry(_dg_pm, _dg_fi)
if _dg_fe is not None and _dg_fe.Name is not None:
stdio.printf("[DBG-GEN] field[%d]=%s\n", _dg_fi, _dg_fe.Name)
_dg_fi += 1
else:
stdio.printf("[DBG-GEN] ptr-match NONE\n")
_dg_i: int = 0
while _dg_i < self.StructCount:
_dg_e: GenTypes.StructEntry* = self._get_struct_entry(_dg_i)
if _dg_e is not None and _dg_e.Name is not None:
if string.strstr(_dg_e.Name, "Generator") is not None:
_dg_sh: str = "<null>"
if _dg_e.ModuleSha1 is not None:
_dg_sh = _dg_e.ModuleSha1
stdio.printf("[DBG-GEN] tbl[%d] name=%s fcount=%d sha1=%s\n",
_dg_i, _dg_e.Name, _dg_e.FieldCount, _dg_sh)
_dg_i += 1
# ============================================================
# 两遍查找策略(跨模块同名类冲突的根本修复):
#