From aa86c0d79bfe51501dee2336e4a3e54eae8373b1 Mon Sep 17 00:00:00 2001 From: Benign X <1341398182@qq.com> Date: Wed, 22 Apr 2026 14:42:35 +0800 Subject: [PATCH] chore(gdb): fix safe_string corrupted markers, safe_color struct read, ptr_or_none null check, char** detection - safe_string: use CorruptedValue for consistent corrupted markers, never returns None - safe_color: read lv_color_t {red, green, blue} sub-fields instead of int() - ptr_or_none: handle None input from safe_field - Generator: char** (multi-level pointer) no longer marked as is_string --- scripts/gdb/lvglgdb/lvgl/data_utils.py | 4 ++-- scripts/gdb/lvglgdb/lvgl/widgets/_helpers.py | 21 ++++++++++++----- .../lvglgdb/lvgl/widgets/lv_buttonmatrix.py | 4 ++-- scripts/gdb/lvglgdb/lvgl/widgets/lv_scale.py | 4 ++-- .../scripts/generators/gen_widget_wrappers.py | 23 +++++++++++++------ 5 files changed, 37 insertions(+), 19 deletions(-) diff --git a/scripts/gdb/lvglgdb/lvgl/data_utils.py b/scripts/gdb/lvglgdb/lvgl/data_utils.py index de3c9d04ae..82272e2a8e 100644 --- a/scripts/gdb/lvglgdb/lvgl/data_utils.py +++ b/scripts/gdb/lvglgdb/lvgl/data_utils.py @@ -16,8 +16,8 @@ def fmt_cb(cb) -> str: def ptr_or_none(val) -> Optional[str]: - """Convert pointer to hex string or None if NULL.""" - if not val.is_ok: + """Convert pointer to hex string or None if NULL/missing.""" + if val is None or not val.is_ok: return None addr = int(val) return hex(addr) if addr else None diff --git a/scripts/gdb/lvglgdb/lvgl/widgets/_helpers.py b/scripts/gdb/lvglgdb/lvgl/widgets/_helpers.py index 018acb9da0..c84d1a0700 100644 --- a/scripts/gdb/lvglgdb/lvgl/widgets/_helpers.py +++ b/scripts/gdb/lvglgdb/lvgl/widgets/_helpers.py @@ -8,19 +8,28 @@ from lvglgdb.lvgl.data_utils import ptr_or_none # noqa: F401 def safe_string(obj, field_name): - """Read a char* field as string, or None.""" + """Read a char* field as string or corrupted marker. Never returns None.""" + from lvglgdb.value import CorruptedValue val = obj.safe_field(field_name) - if val is None or not getattr(val, 'is_ok', True) or not int(val): - return None - return val.string(fallback=None) + if val is None: + return str(CorruptedValue(0, ValueError("field not found"))) + if not getattr(val, 'is_ok', True): + return str(val) + addr = int(val) + if not addr: + return str(CorruptedValue(0, ValueError("NULL pointer"))) + return val.string(fallback=str(CorruptedValue(addr, MemoryError("unreadable")))) def safe_color(obj, field_name): - """Read lv_color_t as hex string.""" + """Read lv_color_t {red, green, blue} as hex string.""" val = obj.safe_field(field_name) if val is None or not getattr(val, 'is_ok', True): return None - return f"#{int(val):06x}" + r = int(val.safe_field("red", 0)) + g = int(val.safe_field("green", 0)) + b = int(val.safe_field("blue", 0)) + return f"#{r:02x}{g:02x}{b:02x}" def safe_area(obj, field_name): diff --git a/scripts/gdb/lvglgdb/lvgl/widgets/lv_buttonmatrix.py b/scripts/gdb/lvglgdb/lvgl/widgets/lv_buttonmatrix.py index d1d53400bd..eb1d629b35 100644 --- a/scripts/gdb/lvglgdb/lvgl/widgets/lv_buttonmatrix.py +++ b/scripts/gdb/lvglgdb/lvgl/widgets/lv_buttonmatrix.py @@ -6,7 +6,7 @@ Do not edit manually. Regenerate from the GDB script root with: """ from lvglgdb.lvgl.core.lv_obj import LVObject -from ._helpers import ptr_or_none, safe_string +from ._helpers import ptr_or_none class LVButtonmatrix(LVObject): @@ -19,7 +19,7 @@ class LVButtonmatrix(LVObject): @property def map_p(self): """Pointer to the current map""" - return safe_string(self._wv, "map_p") + return ptr_or_none(self._wv.safe_field("map_p")) @property def button_areas(self): diff --git a/scripts/gdb/lvglgdb/lvgl/widgets/lv_scale.py b/scripts/gdb/lvglgdb/lvgl/widgets/lv_scale.py index 8b81ce2332..15642203eb 100644 --- a/scripts/gdb/lvglgdb/lvgl/widgets/lv_scale.py +++ b/scripts/gdb/lvglgdb/lvgl/widgets/lv_scale.py @@ -6,7 +6,7 @@ Do not edit manually. Regenerate from the GDB script root with: """ from lvglgdb.lvgl.core.lv_obj import LVObject -from ._helpers import safe_string, safe_wrapper +from ._helpers import ptr_or_none, safe_wrapper class LVScale(LVObject): @@ -23,7 +23,7 @@ class LVScale(LVObject): @property def txt_src(self): - return safe_string(self._wv, "txt_src") + return ptr_or_none(self._wv.safe_field("txt_src")) @property def mode(self): diff --git a/scripts/gdb/scripts/generators/gen_widget_wrappers.py b/scripts/gdb/scripts/generators/gen_widget_wrappers.py index ecee5a83c7..94bb72a20e 100644 --- a/scripts/gdb/scripts/generators/gen_widget_wrappers.py +++ b/scripts/gdb/scripts/generators/gen_widget_wrappers.py @@ -165,7 +165,7 @@ def parse_struct_fields(body: str) -> list[StructField]: name=name, c_type=c_type, is_pointer=is_ptr, is_obj_pointer=is_ptr and "lv_obj_t" in c_type, - is_string=is_ptr and "char" in c_type, + is_string=is_ptr and "char" in c_type and c_type.count("*") <= 1, comment=comment, )) @@ -284,19 +284,28 @@ from lvglgdb.lvgl.data_utils import ptr_or_none # noqa: F401 def safe_string(obj, field_name): - """Read a char* field as string, or None.""" + """Read a char* field as string or corrupted marker. Never returns None.""" + from lvglgdb.value import CorruptedValue val = obj.safe_field(field_name) - if val is None or not getattr(val, 'is_ok', True) or not int(val): - return None - return val.string(fallback=None) + if val is None: + return str(CorruptedValue(0, ValueError("field not found"))) + if not getattr(val, 'is_ok', True): + return str(val) + addr = int(val) + if not addr: + return str(CorruptedValue(0, ValueError("NULL pointer"))) + return val.string(fallback=str(CorruptedValue(addr, MemoryError("unreadable")))) def safe_color(obj, field_name): - """Read lv_color_t as hex string.""" + """Read lv_color_t {red, green, blue} as hex string.""" val = obj.safe_field(field_name) if val is None or not getattr(val, 'is_ok', True): return None - return f"#{int(val):06x}" + r = int(val.safe_field("red", 0)) + g = int(val.safe_field("green", 0)) + b = int(val.safe_field("blue", 0)) + return f"#{r:02x}{g:02x}{b:02x}" def safe_area(obj, field_name):