Files
RedBear-OS/local/recipes/dev/libclc/source/lldb/examples/python/lldbtk.py
T
vasilito cb424d7448 build: static patch-sanity linter (shift-left the malformed-patch class)
verify-patch-sanity.py validates every active recipe .patch has internally-
consistent hunk line counts — catching the 'malformed patch at line N' failure
at commit/CI/preflight time instead of hours into a cook. This cycle hit that
class three times (qtwaylandscanner, sddm, xwayland), each only discovered when
cookbook tried to apply the patch.

Running it across the repo found 29 latent malformed patches (validated against
GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22').
They were harmless only because they sit in vendored recipes (baked, not re-
applied) — but would fail on any version-bump re-derivation. --fix recounts the
hunk headers (body untouched) and repaired all 29.

Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test
(test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats
(empty placeholders, bare-@@ git hunks).
2026-08-01 05:13:02 +03:00

628 lines
20 KiB
Python

#!/usr/bin/env python
import lldb
import shlex
import sys
try:
from tkinter import *
import tkinter.ttk as ttk
except ImportError:
from Tkinter import *
import ttk
class ValueTreeItemDelegate(object):
def __init__(self, value):
self.value = value
def get_item_dictionary(self):
name = self.value.name
if name is None:
name = ""
typename = self.value.type
if typename is None:
typename = ""
value = self.value.value
if value is None:
value = ""
summary = self.value.summary
if summary is None:
summary = ""
has_children = self.value.MightHaveChildren()
return {
"#0": name,
"typename": typename,
"value": value,
"summary": summary,
"children": has_children,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
for i in range(self.value.num_children):
item_delegate = ValueTreeItemDelegate(self.value.GetChildAtIndex(i))
item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts
class FrameTreeItemDelegate(object):
def __init__(self, frame):
self.frame = frame
def get_item_dictionary(self):
id = self.frame.GetFrameID()
name = "frame #%u" % (id)
value = "0x%16.16x" % (self.frame.GetPC())
stream = lldb.SBStream()
self.frame.GetDescription(stream)
summary = stream.GetData().split("`")[1]
return {
"#0": name,
"value": value,
"summary": summary,
"children": self.frame.GetVariables(True, True, True, True).GetSize() > 0,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
variables = self.frame.GetVariables(True, True, True, True)
n = variables.GetSize()
for i in range(n):
item_delegate = ValueTreeItemDelegate(variables[i])
item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts
class ThreadTreeItemDelegate(object):
def __init__(self, thread):
self.thread = thread
def get_item_dictionary(self):
num_frames = self.thread.GetNumFrames()
name = "thread #%u" % (self.thread.GetIndexID())
value = "0x%x" % (self.thread.GetThreadID())
summary = "%u frames" % (num_frames)
return {
"#0": name,
"value": value,
"summary": summary,
"children": num_frames > 0,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
for frame in self.thread:
item_delegate = FrameTreeItemDelegate(frame)
item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts
class ProcessTreeItemDelegate(object):
def __init__(self, process):
self.process = process
def get_item_dictionary(self):
id = self.process.GetProcessID()
num_threads = self.process.GetNumThreads()
value = str(self.process.GetProcessID())
summary = self.process.target.executable.fullpath
return {
"#0": "process",
"value": value,
"summary": summary,
"children": num_threads > 0,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
for thread in self.process:
item_delegate = ThreadTreeItemDelegate(thread)
item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts
class TargetTreeItemDelegate(object):
def __init__(self, target):
self.target = target
def get_item_dictionary(self):
value = str(self.target.triple)
summary = self.target.executable.fullpath
return {
"#0": "target",
"value": value,
"summary": summary,
"children": True,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
image_item_delegate = TargetImagesTreeItemDelegate(self.target)
item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts
class TargetImagesTreeItemDelegate(object):
def __init__(self, target):
self.target = target
def get_item_dictionary(self):
value = str(self.target.triple)
summary = self.target.executable.fullpath
num_modules = self.target.GetNumModules()
return {
"#0": "images",
"value": "",
"summary": "%u images" % num_modules,
"children": num_modules > 0,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
for i in range(self.target.GetNumModules()):
module = self.target.GetModuleAtIndex(i)
image_item_delegate = ModuleTreeItemDelegate(self.target, module, i)
item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts
class ModuleTreeItemDelegate(object):
def __init__(self, target, module, index):
self.target = target
self.module = module
self.index = index
def get_item_dictionary(self):
name = "module %u" % (self.index)
value = self.module.file.basename
summary = self.module.file.dirname
return {
"#0": name,
"value": value,
"summary": summary,
"children": True,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
sections_item_delegate = ModuleSectionsTreeItemDelegate(
self.target, self.module
)
item_dicts.append(sections_item_delegate.get_item_dictionary())
symbols_item_delegate = ModuleSymbolsTreeItemDelegate(self.target, self.module)
item_dicts.append(symbols_item_delegate.get_item_dictionary())
comp_units_item_delegate = ModuleCompileUnitsTreeItemDelegate(
self.target, self.module
)
item_dicts.append(comp_units_item_delegate.get_item_dictionary())
return item_dicts
class ModuleSectionsTreeItemDelegate(object):
def __init__(self, target, module):
self.target = target
self.module = module
def get_item_dictionary(self):
name = "sections"
value = ""
summary = "%u sections" % (self.module.GetNumSections())
return {
"#0": name,
"value": value,
"summary": summary,
"children": True,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
num_sections = self.module.GetNumSections()
for i in range(num_sections):
section = self.module.GetSectionAtIndex(i)
image_item_delegate = SectionTreeItemDelegate(self.target, section)
item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts
class SectionTreeItemDelegate(object):
def __init__(self, target, section):
self.target = target
self.section = section
def get_item_dictionary(self):
name = self.section.name
section_load_addr = self.section.GetLoadAddress(self.target)
if section_load_addr != lldb.LLDB_INVALID_ADDRESS:
value = "0x%16.16x" % (section_load_addr)
else:
value = "0x%16.16x *" % (self.section.file_addr)
summary = ""
return {
"#0": name,
"value": value,
"summary": summary,
"children": self.section.GetNumSubSections() > 0,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
num_sections = self.section.GetNumSubSections()
for i in range(num_sections):
section = self.section.GetSubSectionAtIndex(i)
image_item_delegate = SectionTreeItemDelegate(self.target, section)
item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts
class ModuleCompileUnitsTreeItemDelegate(object):
def __init__(self, target, module):
self.target = target
self.module = module
def get_item_dictionary(self):
name = "compile units"
value = ""
summary = "%u compile units" % (self.module.GetNumSections())
return {
"#0": name,
"value": value,
"summary": summary,
"children": self.module.GetNumCompileUnits() > 0,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
num_cus = self.module.GetNumCompileUnits()
for i in range(num_cus):
cu = self.module.GetCompileUnitAtIndex(i)
image_item_delegate = CompileUnitTreeItemDelegate(self.target, cu)
item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts
class CompileUnitTreeItemDelegate(object):
def __init__(self, target, cu):
self.target = target
self.cu = cu
def get_item_dictionary(self):
name = self.cu.GetFileSpec().basename
value = ""
num_lines = self.cu.GetNumLineEntries()
summary = ""
return {
"#0": name,
"value": value,
"summary": summary,
"children": num_lines > 0,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
item_delegate = LineTableTreeItemDelegate(self.target, self.cu)
item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts
class LineTableTreeItemDelegate(object):
def __init__(self, target, cu):
self.target = target
self.cu = cu
def get_item_dictionary(self):
name = "line table"
value = ""
num_lines = self.cu.GetNumLineEntries()
summary = "%u line entries" % (num_lines)
return {
"#0": name,
"value": value,
"summary": summary,
"children": num_lines > 0,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
num_lines = self.cu.GetNumLineEntries()
for i in range(num_lines):
line_entry = self.cu.GetLineEntryAtIndex(i)
item_delegate = LineEntryTreeItemDelegate(self.target, line_entry, i)
item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts
class LineEntryTreeItemDelegate(object):
def __init__(self, target, line_entry, index):
self.target = target
self.line_entry = line_entry
self.index = index
def get_item_dictionary(self):
name = str(self.index)
address = self.line_entry.GetStartAddress()
load_addr = address.GetLoadAddress(self.target)
if load_addr != lldb.LLDB_INVALID_ADDRESS:
value = "0x%16.16x" % (load_addr)
else:
value = "0x%16.16x *" % (address.file_addr)
summary = (
self.line_entry.GetFileSpec().fullpath + ":" + str(self.line_entry.line)
)
return {
"#0": name,
"value": value,
"summary": summary,
"children": False,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
return item_dicts
class InstructionTreeItemDelegate(object):
def __init__(self, target, instr):
self.target = target
self.instr = instr
def get_item_dictionary(self):
address = self.instr.GetAddress()
load_addr = address.GetLoadAddress(self.target)
if load_addr != lldb.LLDB_INVALID_ADDRESS:
name = "0x%16.16x" % (load_addr)
else:
name = "0x%16.16x *" % (address.file_addr)
value = (
self.instr.GetMnemonic(self.target)
+ " "
+ self.instr.GetOperands(self.target)
)
summary = self.instr.GetComment(self.target)
return {
"#0": name,
"value": value,
"summary": summary,
"children": False,
"tree-item-delegate": self,
}
class ModuleSymbolsTreeItemDelegate(object):
def __init__(self, target, module):
self.target = target
self.module = module
def get_item_dictionary(self):
name = "symbols"
value = ""
summary = "%u symbols" % (self.module.GetNumSymbols())
return {
"#0": name,
"value": value,
"summary": summary,
"children": True,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
num_symbols = self.module.GetNumSymbols()
for i in range(num_symbols):
symbol = self.module.GetSymbolAtIndex(i)
image_item_delegate = SymbolTreeItemDelegate(self.target, symbol, i)
item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts
class SymbolTreeItemDelegate(object):
def __init__(self, target, symbol, index):
self.target = target
self.symbol = symbol
self.index = index
def get_item_dictionary(self):
address = self.symbol.GetStartAddress()
name = "[%u]" % self.index
symbol_load_addr = address.GetLoadAddress(self.target)
if symbol_load_addr != lldb.LLDB_INVALID_ADDRESS:
value = "0x%16.16x" % (symbol_load_addr)
else:
value = "0x%16.16x *" % (address.file_addr)
summary = self.symbol.name
return {
"#0": name,
"value": value,
"summary": summary,
"children": False,
"tree-item-delegate": self,
}
def get_child_item_dictionaries(self):
item_dicts = list()
return item_dicts
class DelegateTree(ttk.Frame):
def __init__(self, column_dicts, delegate, title, name):
ttk.Frame.__init__(self, name=name)
self.pack(expand=Y, fill=BOTH)
self.master.title(title)
self.delegate = delegate
self.columns_dicts = column_dicts
self.item_id_to_item_dict = dict()
frame = Frame(self)
frame.pack(side=TOP, fill=BOTH, expand=Y)
self._create_treeview(frame)
self._populate_root()
def _create_treeview(self, parent):
frame = ttk.Frame(parent)
frame.pack(side=TOP, fill=BOTH, expand=Y)
column_ids = list()
for i in range(1, len(self.columns_dicts)):
column_ids.append(self.columns_dicts[i]["id"])
# create the tree and scrollbars
self.tree = ttk.Treeview(columns=column_ids)
scroll_bar_v = ttk.Scrollbar(orient=VERTICAL, command=self.tree.yview)
scroll_bar_h = ttk.Scrollbar(orient=HORIZONTAL, command=self.tree.xview)
self.tree["yscroll"] = scroll_bar_v.set
self.tree["xscroll"] = scroll_bar_h.set
# setup column headings and columns properties
for columns_dict in self.columns_dicts:
self.tree.heading(
columns_dict["id"],
text=columns_dict["text"],
anchor=columns_dict["anchor"],
)
self.tree.column(columns_dict["id"], stretch=columns_dict["stretch"])
# add tree and scrollbars to frame
self.tree.grid(in_=frame, row=0, column=0, sticky=NSEW)
scroll_bar_v.grid(in_=frame, row=0, column=1, sticky=NS)
scroll_bar_h.grid(in_=frame, row=1, column=0, sticky=EW)
# set frame resizing priorities
frame.rowconfigure(0, weight=1)
frame.columnconfigure(0, weight=1)
# action to perform when a node is expanded
self.tree.bind("<<TreeviewOpen>>", self._update_tree)
def insert_items(self, parent_id, item_dicts):
for item_dict in item_dicts:
name = None
values = list()
first = True
for columns_dict in self.columns_dicts:
if first:
name = item_dict[columns_dict["id"]]
first = False
else:
values.append(item_dict[columns_dict["id"]])
item_id = self.tree.insert(
parent_id, END, text=name, values=values # root item has an empty name
)
self.item_id_to_item_dict[item_id] = item_dict
if item_dict["children"]:
self.tree.insert(item_id, END, text="dummy")
def _populate_root(self):
# use current directory as root node
self.insert_items("", self.delegate.get_child_item_dictionaries())
def _update_tree(self, event):
# user expanded a node - build the related directory
item_id = self.tree.focus() # the id of the expanded node
children = self.tree.get_children(item_id)
if len(children):
first_child = children[0]
# if the node only has a 'dummy' child, remove it and
# build new directory; skip if the node is already
# populated
if self.tree.item(first_child, option="text") == "dummy":
self.tree.delete(first_child)
item_dict = self.item_id_to_item_dict[item_id]
item_dicts = item_dict[
"tree-item-delegate"
].get_child_item_dictionaries()
self.insert_items(item_id, item_dicts)
@lldb.command("tk-variables")
def tk_variable_display(debugger, command, result, dict):
# needed for tree creation in TK library as it uses sys.argv...
sys.argv = ["tk-variables"]
target = debugger.GetSelectedTarget()
if not target:
print("invalid target", file=result)
return
process = target.GetProcess()
if not process:
print("invalid process", file=result)
return
thread = process.GetSelectedThread()
if not thread:
print("invalid thread", file=result)
return
frame = thread.GetSelectedFrame()
if not frame:
print("invalid frame", file=result)
return
# Parse command line args
command_args = shlex.split(command)
column_dicts = [
{"id": "#0", "text": "Name", "anchor": W, "stretch": 0},
{"id": "typename", "text": "Type", "anchor": W, "stretch": 0},
{"id": "value", "text": "Value", "anchor": W, "stretch": 0},
{"id": "summary", "text": "Summary", "anchor": W, "stretch": 1},
]
tree = DelegateTree(
column_dicts, FrameTreeItemDelegate(frame), "Variables", "lldb-tk-variables"
)
tree.mainloop()
@lldb.command("tk-process")
def tk_process_display(debugger, command, result, dict):
# needed for tree creation in TK library as it uses sys.argv...
sys.argv = ["tk-process"]
target = debugger.GetSelectedTarget()
if not target:
print("invalid target", file=result)
return
process = target.GetProcess()
if not process:
print("invalid process", file=result)
return
# Parse command line args
columnd_dicts = [
{"id": "#0", "text": "Name", "anchor": W, "stretch": 0},
{"id": "value", "text": "Value", "anchor": W, "stretch": 0},
{"id": "summary", "text": "Summary", "anchor": W, "stretch": 1},
]
command_args = shlex.split(command)
tree = DelegateTree(
columnd_dicts, ProcessTreeItemDelegate(process), "Process", "lldb-tk-process"
)
tree.mainloop()
@lldb.command("tk-target")
def tk_target_display(debugger, command, result, dict):
# needed for tree creation in TK library as it uses sys.argv...
sys.argv = ["tk-target"]
target = debugger.GetSelectedTarget()
if not target:
print("invalid target", file=result)
return
# Parse command line args
columnd_dicts = [
{"id": "#0", "text": "Name", "anchor": W, "stretch": 0},
{"id": "value", "text": "Value", "anchor": W, "stretch": 0},
{"id": "summary", "text": "Summary", "anchor": W, "stretch": 1},
]
command_args = shlex.split(command)
tree = DelegateTree(
columnd_dicts, TargetTreeItemDelegate(target), "Target", "lldb-tk-target"
)
tree.mainloop()