refactor(gdb): refactor gdb script (#7123)

Signed-off-by: Benign X <1341398182@qq.com>
Co-authored-by: Neo Xu <neo.xu1990@gmail.com>
This commit is contained in:
Benign X
2024-10-23 13:45:18 +08:00
committed by GitHub
parent c70262696e
commit 9dfa1b8631
6 changed files with 137 additions and 91 deletions
+2 -2
View File
@@ -15,14 +15,14 @@ if your device crashes and you have a core dump, you can use GDB to analyze the
core dump. To load the LVGL GDB plugin within GDB's command line, type the core dump. To load the LVGL GDB plugin within GDB's command line, type the
following command: following command:
``source lvgl/scripts/gdb/lvgl.py`` ``source lvgl/scripts/gdb/gdbinit.py``
Example of usage: Example of usage:
.. code:: bash .. code:: bash
(gdb) source lvgl/scripts/gdb/lvgl.py (gdb) source lvgl/scripts/gdb/gdbinit.py
(gdb) dump obj -L 2 (gdb) dump obj -L 2
obj@0x60700000dd10 (0,0,799,599) obj@0x60700000dd10 (0,0,799,599)
+13
View File
@@ -0,0 +1,13 @@
import sys
from os import path
here = path.dirname(path.abspath(__file__))
if __name__ == "__main__":
if here not in sys.path:
sys.path.insert(0, here)
for key in tuple(filter(lambda m: m.startswith("lvglgdb"), sys.modules.keys())):
del sys.modules[key]
import lvglgdb # noqa: F401
+7
View File
@@ -0,0 +1,7 @@
from .lvgl import *
from .value import *
DumpObj()
InfoStyle()
InfoDrawUnit()
set_lvgl_instance(None)
+19
View File
@@ -0,0 +1,19 @@
class Debugger(object):
def __init__(self, host="localhost", port=11451):
self.__host = host
self.__port = port
def connect_to_pycharm(self):
try:
import pydevd_pycharm
except ImportError:
print("pydevd_pycharm module not found. Please install it using pip.")
return
pydevd_pycharm.settrace(self.__host, port=self.__port, stdoutToServer=True, stderrToServer=True)
def connect_to_vscode(self):
raise NotImplementedError()
def connect_to_eclipse(self):
raise NotImplementedError()
@@ -1,9 +1,10 @@
# Usage: source lvgl.py
import argparse import argparse
from typing import Iterator, Union from typing import Iterator, Union, Optional
import gdb import gdb
from .value import Value
gdb.execute("set pagination off") gdb.execute("set pagination off")
gdb.write("set pagination off\n") gdb.write("set pagination off\n")
gdb.execute("set python print-stack full") gdb.execute("set python print-stack full")
@@ -12,31 +13,31 @@ gdb.write("set python print-stack full\n")
g_lvgl_instance = None g_lvgl_instance = None
class LVList: class LVList(Value):
"""LVGL linked list iterator""" """LVGL linked list iterator"""
def __init__(self, ll: gdb.Value, nodetype: Union[gdb.Type, str] = None): def __init__(self, ll: Value, nodetype: Union[gdb.Type, str] = None):
if not ll: if not ll:
raise ValueError("Invalid linked list") raise ValueError("Invalid linked list")
super().__init__(ll)
self.ll = ll
self.nodetype = ( self.nodetype = (
gdb.lookup_type(nodetype).pointer() gdb.lookup_type(nodetype).pointer()
if isinstance(nodetype, str) if isinstance(nodetype, str)
else nodetype else nodetype
) )
self.lv_ll_node_t = gdb.lookup_type("lv_ll_node_t").pointer() self.lv_ll_node_t = gdb.lookup_type("lv_ll_node_t").pointer()
self.current = ll["head"] self.current = self.head
self._next_offset = ll["n_size"] + self.lv_ll_node_t.sizeof self._next_offset = self.n_size + self.lv_ll_node_t.sizeof
self._prev_offset = ll["n_size"] self._prev_offset = self.n_size
def _next(self, node): def _next(self, node):
next = gdb.Value(int(node) + self._next_offset) next_value = Value(int(node) + self._next_offset)
return next.cast(self.lv_ll_node_t.pointer()).dereference() return next_value.cast(self.lv_ll_node_t, ptr=True).dereference()
def _prev(self, node): def _prev(self, node):
prev = gdb.Value(int(node) + self._prev_offset) prev_value = Value(int(node) + self._prev_offset)
return prev.cast(self.lv_ll_node_t) return prev_value.cast(self.lv_ll_node_t, ptr=True).dereference()
def __iter__(self): def __iter__(self):
return self return self
@@ -54,130 +55,99 @@ class LVList:
@property @property
def len(self): def len(self):
len = 0 len = 0
node = self.ll["head"] node = self.head
while node: while node:
len += 1 len += 1
node = self._next(node) node = self._next(node)
return len return len
@property
def head(self):
return self.ll["head"]
@property class LVObject(Value):
def tail(self):
return self.ll["tail"]
@property
def size(self):
return self.ll["n_size"]
class LVObject(gdb.Value):
"""LVGL object""" """LVGL object"""
def __init__(self, obj: gdb.Value): def __init__(self, obj: Value):
super().__init__(obj) super().__init__(obj.cast("lv_obj_t", ptr=True))
self.obj = obj
@property
def class_p(self):
return self.obj["class_p"]
@property @property
def class_name(self): def class_name(self):
name = self.class_p["name"] name = self.class_p.name
return name.string() if name else "unknown" return name.string() if name else "unknown"
@property
def coords(self):
return self.obj["coords"]
@property @property
def x1(self): def x1(self):
return int(self.coords["x1"]) return int(self.coords.x1)
@property @property
def y1(self): def y1(self):
return int(self.coords["y1"]) return int(self.coords.y1)
@property @property
def x2(self): def x2(self):
return int(self.coords["x2"]) return int(self.coords.x2)
@property @property
def y2(self): def y2(self):
return int(self.coords["y2"]) return int(self.coords.y2)
@property @property
def child_count(self): def child_count(self):
return self.obj["spec_attr"]["child_cnt"] if self.obj["spec_attr"] else 0 return self.spec_attr.child_cnt if self.spec_attr else 0
@property @property
def childs(self): def childs(self):
if not self.obj["spec_attr"]: if not self.spec_attr:
return return
for i in range(self.child_count): for i in range(self.child_count):
child = self.obj["spec_attr"]["children"][i] child = self.spec_attr.children[i]
yield LVObject(child) yield LVObject(child)
@property @property
def styles(self): def styles(self):
LV_STYLE_PROP_INV = 0 LV_STYLE_PROP_INV = 0
LV_STYLE_PROP_ANY = 0xFF LV_STYLE_PROP_ANY = 0xFF
count = self.obj["style_cnt"] count = self.style_cnt
if count == 0: if count == 0:
return return
styles = self.obj["styles"] styles = self.super_value("styles")
for i in range(count): for i in range(count):
style = styles[i]["style"] style = styles[i].style
prop_cnt = style["prop_cnt"] prop_cnt = style.prop_cnt
values_and_props = style["values_and_props"].cast( values_and_props = style.values_and_props.cast("lv_style_const_prop_t", ptr=True)
gdb.lookup_type("lv_style_const_prop_t").pointer()
)
for j in range(prop_cnt): for j in range(prop_cnt):
prop = values_and_props[j]["prop"] prop = values_and_props[j].prop
if prop == LV_STYLE_PROP_INV or prop == LV_STYLE_PROP_ANY: if prop == LV_STYLE_PROP_INV or prop == LV_STYLE_PROP_ANY:
continue continue
yield values_and_props[j] yield values_and_props[j]
def get_child(self, index: int): def get_child(self, index: int):
return ( return (
self.obj["spec_attr"]["children"][index] if self.obj["spec_attr"] else None self.spec_attr.children[index] if self.spec_attr else None
) )
class LVDisplay(gdb.Value): class LVDisplay(Value):
"""LVGL display""" """LVGL display"""
def __init__(self, disp: gdb.Value): def __init__(self, disp: Value):
super().__init__(disp) super().__init__(disp)
self.disp = disp
@property @property
def screens(self): def screens(self):
screens = self.super_value("screens")
for i in range(self.screen_cnt): for i in range(self.screen_cnt):
yield LVObject(self.disp["screens"][i]) yield LVObject(screens[i])
@property
def screen_cnt(self):
return self.disp["screen_cnt"]
@property
def act_scr(self):
return self.disp["act_scr"]
class LVGL: class LVGL:
"""LVGL instance""" """LVGL instance"""
def __init__(self, lv_global: gdb.Value): def __init__(self, lv_global: Value):
self.lv_global = lv_global.cast(gdb.lookup_type("lv_global_t").pointer()) self.lv_global = lv_global.cast("lv_global_t", ptr=True)
def displays(self) -> Iterator[LVDisplay]: def displays(self) -> Iterator[LVDisplay]:
ll = self.lv_global["disp_ll"] ll = self.lv_global.disp_ll
if not ll: if not ll:
return return
@@ -185,27 +155,36 @@ class LVGL:
yield LVDisplay(disp) yield LVDisplay(disp)
def screen_active(self): def screen_active(self):
disp = self.lv_global["disp_default"] disp = self.lv_global.disp_default
return disp["act_scr"] if disp else None return disp.act_scr if disp else None
def draw_units(self): def draw_units(self):
unit = self.lv_global["draw_info"]["unit_head"] unit = self.lv_global.draw_info.unit_head
# Iterate through all draw units # Iterate through all draw units
while unit: while unit:
yield unit yield unit
unit = unit["next"] unit = unit.next
def set_lvgl_instance(lv_global: gdb.Value):
def set_lvgl_instance(lv_global: Union[gdb.Value, Value, None]):
global g_lvgl_instance global g_lvgl_instance
if not lv_global: if not lv_global:
try: try:
lv_global = gdb.parse_and_eval("lv_global").address lv_global = Value(gdb.parse_and_eval("lv_global").address)
except gdb.error as e: except gdb.error as e:
print(f"Failed to get lv_global: {e}") print(f"Failed to get lv_global: {e}")
return return
if not isinstance(lv_global, Value):
lv_global = Value(lv_global)
inited = lv_global.inited
if not inited:
print("\x1b[31mlvgl is not initialized yet. Please call `set_lvgl_instance(None)` later.\x1b[0m")
return
g_lvgl_instance = LVGL(lv_global) g_lvgl_instance = LVGL(lv_global)
@@ -216,9 +195,9 @@ def dump_obj_info(obj: LVObject):
# Dump lv_style_const_prop_t # Dump lv_style_const_prop_t
def dump_style_info(style: gdb.Value): def dump_style_info(style: Value):
prop = int(style["prop"]) prop = int(style.prop)
value = style["value"] value = style.value
print(f"{prop} = {value}") print(f"{prop} = {value}")
@@ -306,13 +285,14 @@ class InfoStyle(gdb.Command):
print("Invalid obj: ", args.obj) print("Invalid obj: ", args.obj)
return return
obj = obj.cast(gdb.lookup_type("lv_obj_t").pointer()) obj = Value(obj)
# show all styles applied to this obj # show all styles applied to this obj
for style in LVObject(obj).styles: for style in LVObject(obj).styles:
print(" ", end="") print(" ", end="")
dump_style_info(style) dump_style_info(style)
class InfoDrawUnit(gdb.Command): class InfoDrawUnit(gdb.Command):
"""dump draw unit info""" """dump draw unit info"""
@@ -321,9 +301,9 @@ class InfoDrawUnit(gdb.Command):
"info draw_unit", gdb.COMMAND_USER, gdb.COMPLETE_EXPRESSION "info draw_unit", gdb.COMMAND_USER, gdb.COMPLETE_EXPRESSION
) )
def dump_draw_unit(self, draw_unit:gdb.Value): def dump_draw_unit(self, draw_unit: Value):
# Dereference to get the string content of the name from draw_unit # Dereference to get the string content of the name from draw_unit
name = draw_unit["name"].string() name = draw_unit.name.string()
# Print draw_unit information and the name # Print draw_unit information and the name
print(f"Draw Unit: {draw_unit}, Name: {name}") print(f"Draw Unit: {draw_unit}, Name: {name}")
@@ -347,14 +327,9 @@ class InfoDrawUnit(gdb.Command):
"VG_LITE": lookup_type("lv_draw_vg_lite_unit_t"), "VG_LITE": lookup_type("lv_draw_vg_lite_unit_t"),
} }
type = types.get(name) or lookup_type("lv_draw_unit_t") type = types.get(name, lookup_type("lv_draw_unit_t"))
print(draw_unit.cast(type.pointer()).dereference().format_string(pretty_structs=True, symbols=True)) print(draw_unit.cast(type, ptr=True).dereference().format_string(pretty_structs=True, symbols=True))
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
for unit in g_lvgl_instance.draw_units(): for unit in g_lvgl_instance.draw_units():
self.dump_draw_unit(unit) self.dump_draw_unit(unit)
DumpObj()
InfoStyle()
InfoDrawUnit()
set_lvgl_instance(None)
+32
View File
@@ -0,0 +1,32 @@
import gdb
from typing import Optional, Union
class Value(gdb.Value):
def __init__(self, value: Union[gdb.Value, 'Value']):
super().__init__(value)
def __getitem__(self, key):
try:
value = super().__getitem__(key)
except gdb.error:
value = super().__getattr__(key)
return Value(value)
def __getattr__(self, key):
if hasattr(super(), key):
return Value(super().__getattribute__(key))
return Value(super().__getitem__(key))
def cast(self, type_name: str | gdb.Type, ptr: bool = False) -> Optional['Value']:
try:
gdb_type = gdb.lookup_type(type_name) if isinstance(type_name, str) else type_name
if ptr:
gdb_type = gdb_type.pointer()
return Value(super().cast(gdb_type))
except gdb.error:
return None
def super_value(self, attr: str) -> 'Value':
return self[attr]