diff --git a/scripts/gdb/lvglgdb/__init__.py b/scripts/gdb/lvglgdb/__init__.py index 91f89a0127..d8436fddf1 100644 --- a/scripts/gdb/lvglgdb/__init__.py +++ b/scripts/gdb/lvglgdb/__init__.py @@ -1,4 +1,4 @@ -from .value import Value +from .value import Value, ValueInput from .lvgl import ( curr_inst, LVDisplay, @@ -44,6 +44,7 @@ __all__ = [ "decode_selector", "format_style_value", "Value", + "ValueInput", "LVCacheEntry", "LVCacheLRURB", "LVCacheLRURBIterator", diff --git a/scripts/gdb/lvglgdb/cmds/core/lv_obj.py b/scripts/gdb/lvglgdb/cmds/core/lv_obj.py index 8f59e1fa07..9b98d58730 100644 --- a/scripts/gdb/lvglgdb/cmds/core/lv_obj.py +++ b/scripts/gdb/lvglgdb/cmds/core/lv_obj.py @@ -3,7 +3,6 @@ import gdb from lvglgdb.lvgl import curr_inst from lvglgdb.lvgl import LVObject, dump_obj_info -from lvglgdb.value import Value class DumpObj(gdb.Command): @@ -52,7 +51,7 @@ class DumpObj(gdb.Command): if args.root: root = gdb.parse_and_eval(args.root) - root = LVObject(Value(root)) + root = LVObject(root) self.dump_obj(root, limit=args.level) else: # dump all displays diff --git a/scripts/gdb/lvglgdb/cmds/misc/lv_style.py b/scripts/gdb/lvglgdb/cmds/misc/lv_style.py index dc6f609c2e..61c6f65b36 100644 --- a/scripts/gdb/lvglgdb/cmds/misc/lv_style.py +++ b/scripts/gdb/lvglgdb/cmds/misc/lv_style.py @@ -1,7 +1,6 @@ import argparse import gdb -from lvglgdb.value import Value from lvglgdb.lvgl import LVStyle, dump_obj_styles @@ -38,12 +37,12 @@ class InfoStyle(gdb.Command): if not obj: print("Invalid obj:", args.obj) return - dump_obj_styles(Value(obj)) + dump_obj_styles(obj) elif args.style: style = gdb.parse_and_eval(args.style) if not style: print("Invalid style:", args.style) return - LVStyle(Value(style)).print_entries() + LVStyle(style).print_entries() else: print("Usage: info style or info style --obj ") diff --git a/scripts/gdb/lvglgdb/lvgl/core/lv_obj.py b/scripts/gdb/lvglgdb/lvgl/core/lv_obj.py index 25fc61bad6..362fdfb738 100644 --- a/scripts/gdb/lvglgdb/lvgl/core/lv_obj.py +++ b/scripts/gdb/lvglgdb/lvgl/core/lv_obj.py @@ -1,4 +1,4 @@ -from lvglgdb.value import Value +from lvglgdb.value import Value, ValueInput from lvglgdb.lvgl.misc.lv_style import LVStyle, StyleEntry, decode_selector @@ -29,8 +29,8 @@ class ObjStyle: class LVObject(Value): """LVGL object""" - def __init__(self, obj: Value): - super().__init__(obj.cast("lv_obj_t", ptr=True)) + def __init__(self, obj: ValueInput): + super().__init__(Value.normalize(obj, "lv_obj_t")) @property def class_name(self): @@ -102,9 +102,9 @@ def dump_obj_info(obj: LVObject): print(f"{clzname}@{hex(obj)} {coords}") -def dump_obj_styles(obj: Value): +def dump_obj_styles(obj: ValueInput): """Print all styles of an object, reusing LVStyle.print_entries().""" - lv_obj = LVObject(Value(obj)) + lv_obj = LVObject(obj) has_any = False for obj_style in lv_obj.obj_styles: diff --git a/scripts/gdb/lvglgdb/lvgl/display/lv_display.py b/scripts/gdb/lvglgdb/lvgl/display/lv_display.py index e6643c572d..f27f466e09 100644 --- a/scripts/gdb/lvglgdb/lvgl/display/lv_display.py +++ b/scripts/gdb/lvglgdb/lvgl/display/lv_display.py @@ -1,13 +1,13 @@ from ..core.lv_obj import LVObject from ..draw.lv_draw_buf import LVDrawBuf -from lvglgdb.value import Value +from lvglgdb.value import Value, ValueInput class LVDisplay(Value): """LVGL display""" - def __init__(self, disp: Value): - super().__init__(disp) + def __init__(self, disp: ValueInput): + super().__init__(Value.normalize(disp, "lv_display_t")) @property def hor_res(self) -> int: diff --git a/scripts/gdb/lvglgdb/lvgl/draw/lv_draw_buf.py b/scripts/gdb/lvglgdb/lvgl/draw/lv_draw_buf.py index 96e52874d7..8037702f72 100644 --- a/scripts/gdb/lvglgdb/lvgl/draw/lv_draw_buf.py +++ b/scripts/gdb/lvglgdb/lvgl/draw/lv_draw_buf.py @@ -5,7 +5,7 @@ import gdb import numpy as np from PIL import Image -from lvglgdb.value import Value +from lvglgdb.value import Value, ValueInput class LVDrawBuf(Value): @@ -25,8 +25,8 @@ class LVDrawBuf(Value): "XRGB8888": 32, } - def __init__(self, draw_buf: Value): - super().__init__(draw_buf) + def __init__(self, draw_buf: ValueInput): + super().__init__(Value.normalize(draw_buf, "lv_draw_buf_t")) self._init_color_formats() def _init_color_formats(self): diff --git a/scripts/gdb/lvglgdb/lvgl/misc/lv_cache.py b/scripts/gdb/lvglgdb/lvgl/misc/lv_cache.py index beeea4cc75..8fbc910b8b 100644 --- a/scripts/gdb/lvglgdb/lvgl/misc/lv_cache.py +++ b/scripts/gdb/lvglgdb/lvgl/misc/lv_cache.py @@ -1,34 +1,21 @@ from typing import Union, List, Optional, Dict import gdb -from lvglgdb.value import Value +from lvglgdb.value import Value, ValueInput from .lv_cache_iter_factory import create_cache_iterator class LVCache(Value): """LVGL cache wrapper - focuses on cache-level operations""" - def __init__( - self, cache: Union[Value, gdb.Value, int], datatype: Union[gdb.Type, str] - ): - # Convert to Value first if needed - if isinstance(cache, int): - cache = Value(cache).cast("lv_cache_t", ptr=True) - if cache is None: - raise ValueError("Failed to cast pointer to lv_cache_t") - elif isinstance(cache, gdb.Value) and not isinstance(cache, Value): - cache = Value(cache) - elif not cache: - raise ValueError("Invalid cache") - + def __init__(self, cache: ValueInput, datatype: Union[gdb.Type, str]): + super().__init__(Value.normalize(cache, "lv_cache_t")) self.datatype = ( gdb.lookup_type(datatype).pointer() if isinstance(datatype, str) else datatype ) - super().__init__(cache) - def print_info(self): """Dump cache information""" print(f"Cache Info:") @@ -91,9 +78,7 @@ class LVCache(Value): print(f" ... {cache_entries_cnt - count} more entries not shown") -def dump_cache_info( - cache: Union[Value, gdb.Value, int], datatype: Union[gdb.Type, str] -): +def dump_cache_info(cache: ValueInput, datatype: Union[gdb.Type, str]): """Dump cache information""" cache_obj = LVCache(cache, datatype) cache_obj.print_info() diff --git a/scripts/gdb/lvglgdb/lvgl/misc/lv_cache_entry.py b/scripts/gdb/lvglgdb/lvgl/misc/lv_cache_entry.py index 1120bb058c..a29b8e79d8 100644 --- a/scripts/gdb/lvglgdb/lvgl/misc/lv_cache_entry.py +++ b/scripts/gdb/lvglgdb/lvgl/misc/lv_cache_entry.py @@ -1,37 +1,22 @@ from typing import Union import gdb -from lvglgdb.value import Value +from lvglgdb.value import Value, ValueInput class LVCacheEntry(Value): """LVGL cache entry wrapper - focuses on entry-level operations""" - def __init__( - self, entry: Union[Value, gdb.Value, int], datatype: Union[gdb.Type, str] - ): - # Convert to Value first if needed - if isinstance(entry, int): - entry = Value(entry).cast("lv_cache_entry_t", ptr=True) - if entry is None: - raise ValueError("Failed to cast pointer to lv_cache_entry_t") - elif isinstance(entry, gdb.Value) and not isinstance(entry, Value): - entry = Value(entry) - elif not entry: - raise ValueError("Invalid cache entry") - + def __init__(self, entry: ValueInput, datatype: Union[gdb.Type, str]): + super().__init__(Value.normalize(entry, "lv_cache_entry_t")) self.datatype = ( gdb.lookup_type(datatype).pointer() if isinstance(datatype, str) else datatype ) - super().__init__(entry) - @classmethod - def from_data_ptr( - cls, data_ptr: Union[Value, gdb.Value, int], datatype: Union[gdb.Type, str] - ): + def from_data_ptr(cls, data_ptr: ValueInput, datatype: Union[gdb.Type, str]): """Create LVCacheEntry from data pointer""" if data_ptr.type == gdb.lookup_type("void").pointer() and datatype is None: @@ -95,9 +80,7 @@ class LVCacheEntry(Value): return super().__str__() -def dump_cache_entry_info( - entry: Union[Value, gdb.Value, int], datatype: Union[gdb.Type, str] -): +def dump_cache_entry_info(entry: ValueInput, datatype: Union[gdb.Type, str]): """Dump cache entry information""" entry_obj = LVCacheEntry(entry, datatype) entry_obj.print_info() diff --git a/scripts/gdb/lvglgdb/lvgl/misc/lv_cache_lru_rb.py b/scripts/gdb/lvglgdb/lvgl/misc/lv_cache_lru_rb.py index 5f784d3014..6b444d0816 100644 --- a/scripts/gdb/lvglgdb/lvgl/misc/lv_cache_lru_rb.py +++ b/scripts/gdb/lvglgdb/lvgl/misc/lv_cache_lru_rb.py @@ -1,7 +1,6 @@ -from typing import Union, List, Optional import gdb -from lvglgdb.value import Value +from lvglgdb.value import Value, ValueInput from .lv_cache_iter_base import LVCacheIteratorBase from .lv_rb import LVRedBlackTree from .lv_cache_entry import LVCacheEntry @@ -42,18 +41,10 @@ class LVCacheLRURBIterator(LVCacheIteratorBase): class LVCacheLRURB(LVCache): """LVGL LRU-based cache using red-black tree iterator""" - def __init__(self, cache: Union[Value, gdb.Value, int]): - # Convert to Value first if needed - if isinstance(cache, int): - cache = Value(cache).cast("lv_cache_lru_rb_t", ptr=True) - if cache is None: - raise ValueError("Failed to cast pointer to lv_cache_lru_rb_t") - elif isinstance(cache, gdb.Value) and not isinstance(cache, Value): - cache = Value(cache) - elif not cache: - raise ValueError("Invalid cache") - self.cache_base = cache - super().__init__(cache, cache.datatype) + def __init__(self, cache: ValueInput): + datatype = cache.datatype if isinstance(cache, LVCache) else None + super().__init__(cache, datatype) + self.cache_base = Value(self) def print_info(self): """Dump LRU RB cache information""" @@ -98,7 +89,7 @@ class LVCacheLRURB(LVCache): return entries -def dump_lru_rb_cache_info(cache: Union[Value, gdb.Value, int]): +def dump_lru_rb_cache_info(cache: ValueInput): """Dump LRU RB cache information""" cache_obj = LVCacheLRURB(cache) cache_obj.print_info() diff --git a/scripts/gdb/lvglgdb/lvgl/misc/lv_ll.py b/scripts/gdb/lvglgdb/lvgl/misc/lv_ll.py index abb038c88c..4e5c369532 100644 --- a/scripts/gdb/lvglgdb/lvgl/misc/lv_ll.py +++ b/scripts/gdb/lvglgdb/lvgl/misc/lv_ll.py @@ -1,16 +1,14 @@ from typing import Union import gdb -from lvglgdb.value import Value +from lvglgdb.value import Value, ValueInput class LVList(Value): """LVGL linked list iterator""" - def __init__(self, ll: Value, nodetype: Union[gdb.Type, str] = None): - if not ll: - raise ValueError("Invalid linked list") - super().__init__(ll) + def __init__(self, ll: ValueInput, nodetype: Union[gdb.Type, str] = None): + super().__init__(Value.normalize(ll, "lv_ll_t")) self.nodetype = ( gdb.lookup_type(nodetype).pointer() diff --git a/scripts/gdb/lvglgdb/lvgl/misc/lv_rb.py b/scripts/gdb/lvglgdb/lvgl/misc/lv_rb.py index 9148986e44..b3f0b02a67 100644 --- a/scripts/gdb/lvglgdb/lvgl/misc/lv_rb.py +++ b/scripts/gdb/lvglgdb/lvgl/misc/lv_rb.py @@ -1,28 +1,15 @@ from typing import Union import gdb -from lvglgdb.value import Value +from lvglgdb.value import Value, ValueInput class LVRedBlackTree(Value): """LVGL red-black tree iterator""" - def __init__( - self, rb: Union[Value, gdb.Value, int], datatype: Union[gdb.Type, str] = None - ): - # Convert to Value first if needed - if isinstance(rb, int): - rb = Value(rb).cast("lv_rb_t", ptr=True) - if rb is None: - raise ValueError("Failed to cast pointer to lv_rb_t") - elif isinstance(rb, gdb.Value) and not isinstance(rb, Value): - rb = Value(rb) - elif not rb: - raise ValueError("Invalid red-black tree") - super().__init__(rb) - + def __init__(self, rb: ValueInput, datatype: Union[gdb.Type, str] = None): + super().__init__(Value.normalize(rb, "lv_rb_t")) self.lv_rb_node_t = gdb.lookup_type("lv_rb_node_t").pointer() - self.datatype = ( gdb.lookup_type(datatype).pointer() if isinstance(datatype, str) @@ -175,9 +162,7 @@ class LVRedBlackTreeIterator: return f"LVRedBlackTreeIterator(current=0x{int(current):x})" -def dump_rb_info( - rb: Union[Value, gdb.Value, int], datatype: Union[gdb.Type, str] = None -): +def dump_rb_info(rb: ValueInput, datatype: Union[gdb.Type, str] = None): """Dump red-black tree information""" tree = LVRedBlackTree(rb, datatype=datatype) tree.print_info() diff --git a/scripts/gdb/lvglgdb/lvgl/misc/lv_style.py b/scripts/gdb/lvglgdb/lvgl/misc/lv_style.py index a4dc9e800b..eff7b1edc1 100644 --- a/scripts/gdb/lvglgdb/lvgl/misc/lv_style.py +++ b/scripts/gdb/lvglgdb/lvgl/misc/lv_style.py @@ -3,7 +3,7 @@ from typing import Iterator import gdb from prettytable import PrettyTable -from lvglgdb.value import Value +from lvglgdb.value import Value, ValueInput from .lv_style_consts import ( STYLE_PROP_NAMES, PART_NAMES, @@ -74,12 +74,8 @@ class StyleEntry: class LVStyle(Value): """LVGL style wrapper for lv_style_t.""" - def __init__(self, style: Value): - # Ensure we always hold a lv_style_t* pointer, like LVObject does - typ = style.type.strip_typedefs() - if typ.code != gdb.TYPE_CODE_PTR: - style = Value(style.address) - super().__init__(style.cast("lv_style_t", ptr=True)) + def __init__(self, style: ValueInput): + super().__init__(Value.normalize(style, "lv_style_t")) def __iter__(self) -> Iterator[StyleEntry]: prop_cnt = int(self.prop_cnt) diff --git a/scripts/gdb/lvglgdb/value.py b/scripts/gdb/lvglgdb/value.py index 0ea7705406..e5e0ce3c45 100644 --- a/scripts/gdb/lvglgdb/value.py +++ b/scripts/gdb/lvglgdb/value.py @@ -7,6 +7,47 @@ class Value(gdb.Value): def __init__(self, value: Union[gdb.Value, "Value"]): super().__init__(value) + @staticmethod + def normalize(val: "ValueInput", target_type: Optional[str] = None) -> "Value": + """Normalize input to a typed Value pointer. + + Args: + val: Input value - int (address), gdb.Value, or Value instance + target_type: C type name (e.g. "lv_obj_t"). If provided, + result is cast to target_type* + + Returns: + Value instance, optionally cast to target_type* + + Raises: + ValueError: If target_type lookup fails or cast fails + """ + if isinstance(val, int): + val = gdb.Value(val) + + if not isinstance(val, Value): + val = Value(val) + + if target_type is not None: + try: + gdb.lookup_type(target_type) + except gdb.error: + raise ValueError(f"Type not found: {target_type}") + + typ = val.type.strip_typedefs() + if typ.code != gdb.TYPE_CODE_PTR: + if typ.code in (gdb.TYPE_CODE_INT, gdb.TYPE_CODE_ENUM): + val = Value(val.cast(gdb.lookup_type(target_type).pointer())) + else: + val = Value(val.address) + + result = val.cast(target_type, ptr=True) + if result is None: + raise ValueError(f"Failed to cast to {target_type}*") + val = result + + return val + def __getitem__(self, key): try: value = super().__getitem__(key) @@ -61,3 +102,7 @@ class Value(gdb.Value): pass return f"Value({self.__str__()})" + + +# Type alias for all wrapper class __init__ parameters +ValueInput = Union[int, gdb.Value, Value]