From 4c1eebab967dc3a920828f478ef6a3c76f39bd05 Mon Sep 17 00:00:00 2001 From: jyelon Date: Mon, 20 Apr 2026 08:42:36 -0400 Subject: [PATCH] Working on lldb data formatting some more --- tools/UEDataFormatter.py | 233 +++++++++++++++------------------------ 1 file changed, 91 insertions(+), 142 deletions(-) diff --git a/tools/UEDataFormatter.py b/tools/UEDataFormatter.py index ee60c209..b07dcd29 100644 --- a/tools/UEDataFormatter.py +++ b/tools/UEDataFormatter.py @@ -1,6 +1,13 @@ import lldb, signal, sys, time import lldb.formatters.Logger +import codelldb.value + +############################################################ +# +# Store pointers to some important types and globals. +# +############################################################ _FNameEntryType = None @@ -9,6 +16,28 @@ _FUObjectItemType = None _GNameBlocksDebug = None _GObjectArrayForDebugVisualizers = None +def _init_globals(target): + global _FNameEntryType, _FNameEntryStride, _FUObjectItemType + global _GNameBlocksDebug, _GObjectArrayForDebugVisualizers + + _FNameEntryType = target.FindFirstType('FNameEntry') + if not _FNameEntryType.IsValid(): + print('UEDataFormatter: FNameEntry type not found') + _FNameEntryStride = _FNameEntryType.GetByteAlign() + + _FUObjectItemType = target.FindFirstType('FUObjectItem') + if not _FUObjectItemType.IsValid(): + print('UEDataFormatter: FUObjectItem type not found') + + _GNameBlocksDebug = target.FindFirstGlobalVariable('GNameBlocksDebug') + if not _GNameBlocksDebug.IsValid(): + print('UEDataFormatter: GNameBlocksDebug not found') + + _GObjectArrayForDebugVisualizers = target.FindFirstGlobalVariable('GObjectArrayForDebugVisualizers') + if not _GObjectArrayForDebugVisualizers.IsValid(): + print('UEDataFormatter: GObjectArrayForDebugVisualizers not found') + + ############################################################ # # A forwarding synth provider is a provider that @@ -952,157 +981,36 @@ def UObjectSummaryProvider(valobj, dict): # return 'expired' # return Object.Dereference().GetSummary() or ('0x%x' % addr) -def __lldb_init_module(debugger, dict): - print("Running lldb_init_module") - debugger.HandleCommand('type category delete UEDataFormatters') - global _FNameEntryType, _FNameEntryStride, _FUObjectItemType - global _GNameBlocksDebug, _GObjectArrayForDebugVisualizers - target = debugger.GetSelectedTarget() - _FNameEntryType = target.FindFirstType('FNameEntry') - _FNameEntryStride = _FNameEntryType.GetByteAlign() - _FUObjectItemType = target.FindFirstType('FUObjectItem') - _GNameBlocksDebug = target.FindFirstGlobalVariable('GNameBlocksDebug') - if not _GNameBlocksDebug.IsValid(): - print('UEDataFormatter: GNameBlocksDebug not found') - _GObjectArrayForDebugVisualizers = target.FindFirstGlobalVariable('GObjectArrayForDebugVisualizers') - if not _GObjectArrayForDebugVisualizers.IsValid(): - print('UEDataFormatter: GObjectArrayForDebugVisualizers not found') - debugger.HandleCommand('type summary add -F UEDataFormatter.UEFStringSummaryProvider -e FString -w UEDataFormatters') - debugger.HandleCommand('type summary add -F UEDataFormatter.UEFNameSummaryProvider -e FName -w UEDataFormatters') - debugger.HandleCommand('type synthetic add -l UEDataFormatter.TObjectPtrSynthProvider -x "^TObjectPtr<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type summary add -F UEDataFormatter.TObjectPtrSummaryProvider -e -x "^TObjectPtr<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type synthetic add -l UEDataFormatter.TStrongObjectPtrSynthProvider -x "^TStrongObjectPtr<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type summary add -F UEDataFormatter.TStrongObjectPtrSummaryProvider -e -x "^TStrongObjectPtr<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type synthetic add -l UEDataFormatter.TSharedPtrSynthProvider -x "^TSharedPtr<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type summary add -F UEDataFormatter.TSharedPtrSummaryProvider -e -x "^TSharedPtr<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type synthetic add -l UEDataFormatter.TSharedPtrSynthProvider -x "^TSharedRef<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type summary add -F UEDataFormatter.TSharedPtrSummaryProvider -e -x "^TSharedRef<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type synthetic add -l UEDataFormatter.TWeakPtrSynthProvider -x "^TWeakPtr<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type summary add -F UEDataFormatter.TWeakPtrSummaryProvider -e -x "^TWeakPtr<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type synthetic add -l UEDataFormatter.TWeakObjectPtrSynthProvider -x "^TWeakObjectPtr<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type summary add -F UEDataFormatter.TWeakObjectPtrSummaryProvider -e -x "^TWeakObjectPtr<.+>$" -w UEDataFormatters') - debugger.HandleCommand('type synthetic add -l UEDataFormatter.TWeakObjectPtrSynthProvider -x "^FWeakObjectPtr$" -w UEDataFormatters') - debugger.HandleCommand('type summary add -F UEDataFormatter.TWeakObjectPtrSummaryProvider -e FWeakObjectPtr -w UEDataFormatters') - debugger.HandleCommand('type synthetic add -l UEDataFormatter.UObjectSynthProvider UObject -w UEDataFormatters') - debugger.HandleCommand('type summary add -F UEDataFormatter.UObjectSummaryProvider -e UObject -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UEUObjectBaseSummaryProvider -e UObjectBase -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UEFFieldClassSummaryProvider -e FFieldClass -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UEFFieldSummaryProvider -e FField -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UEFWeakObjectPtrSummaryProvider -e FWeakObjectPtr -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UETWeakObjectPtrSynthProvider -x "TWeakObjectPtr<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UETWeakObjectPtrSynthProvider -x "TAutoWeakObjectPtr<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UEArraySynthProvider -x "TArray<.+,.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UEArraySummaryProvider -e -x "TArray<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UEBitArraySynthProvider -x "TBitArray<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UEBitArraySummaryProvider -e -x "TBitArray<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UESparseArraySynthProvider -x "TSparseArray<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UESparseArraySummaryProvider -e -x "TSparseArray<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UEChunkedArraySynthProvider -x "TChunkedArray<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UEChunkedArraySummaryProvider -e -x "TChunkedArray<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UESetSynthProvider -x "TSet<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UESetSummaryProvider -e -x "TSet<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UEMapSynthProvider -x "TMap<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UEMapSummaryProvider -e -x "TMap<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UEMapSynthProvider -x "TMapBase<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UEMapSummaryProvider -e -x "TMapBase<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UETObjectPtrSynthProvider -x "^TObjectPtr<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UETObjectPtrSummaryProvider -e -x "^TObjectPtr<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UETSharedPtrSynthProvider -x "^TSharedPtr<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UETSharedPtrSummaryProvider -e -x "^TSharedPtr<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UETSharedPtrSynthProvider -x "^TSharedRef<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UETSharedPtrSummaryProvider -e -x "^TSharedRef<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UETWeakPtrSynthProvider -x "^TWeakPtr<.+>$" -w UEDataFormatters') - # debugger.HandleCommand('type summary add -F UEDataFormatter.UETWeakPtrSummaryProvider -e -x "^TWeakPtr<.+>$" -w UEDataFormatters') - debugger.HandleCommand("type category enable UEDataFormatters") - -def _patch_codelldb_value(): - """Patch codelldb.value.Value with Unreal-friendly navigation: - - __getattr__ auto-derefs pointers and falls back to iterating - children by GetName() (so base classes like 'UWidget' resolve). - - This affects every /se and /py expression that uses Value — strictly - more forgiving than the stock behavior (paths that used to fail now - succeed), but it IS a global behavior change. - """ - try: - from codelldb.value import Value - except ImportError: - return - def __getattr__(self, name): - sbv = self._Value__sbvalue - if sbv.GetType().IsPointerType(): - sbv = sbv.Dereference() - child = sbv.GetChildMemberWithName(name) - if not child.IsValid(): - for i in range(sbv.GetNumChildren()): - c = sbv.GetChildAtIndex(i) - if c.GetName() == name: - child = c - break - if not child.IsValid(): - raise AttributeError("Attribute '%s' is not defined" % name) - return Value(child) - Value.__getattr__ = __getattr__ - -_patch_codelldb_value() ############################################################## # -# FV +# The getattr which is built in to codelldb.value.Value +# fails to fetch synthetic values. Monkey-patch it. # -############################################################# +############################################################## +def _value_getattr(self, name): + sbv = self._Value__sbvalue + if sbv.GetType().IsPointerType(): + sbv = sbv.Dereference() + child = sbv.GetChildMemberWithName(name) + if not child.IsValid(): + for i in range(sbv.GetNumChildren()): + c = sbv.GetChildAtIndex(i) + if c.GetName() == name: + child = c + break + if not child.IsValid(): + raise AttributeError("Attribute '%s' is not defined" % name) + return codelldb.value.Value(child) -def fv(expr): - """Evaluate a Python-syntax expression against the current frame's variables. - - Every frame variable is pre-wrapped in a codelldb Value and placed in - the eval globals, so e.g. fv("Widget.Object.SCompoundWidget") walks via - the (patched) Value.__getattr__, fv("Arr[3].Field") works via - Value.__getitem__, and arithmetic/comparisons work via Value's dunders. - - Usage in Watch: /py fv("Widget.Object.SCompoundWidget.SWidget") - """ - from codelldb.value import Value - frame = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() - eval_globals = {} - for var in frame.GetVariables(True, True, True, True): - name = var.GetName() - if var.IsValid() and name: - eval_globals[name] = Value(var) - try: - result = eval(expr, eval_globals, {}) - except Exception as e: - return "<%s: %s>" % (type(e).__name__, e) - if isinstance(result, Value): - return Value.unwrap(result) - return result - -def fv2(): - frame = lldb.debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() - top = frame.FindVariable('Top') - if not top.IsValid(): - return - widget = top.GetChildMemberWithName('Widget') - if not widget.IsValid(): - return - uwidget = FindNamedChild(widget, 'UWidget') - if not uwidget.IsValid(): - return - return uwidget - -def FindNamedChild(value, name): - for i in range(value.GetNumChildren()): - child = value.GetChildAtIndex(i) - if child.IsValid() and child.GetName() == name: - return child - return lldb.SBValue() - +codelldb.value.Value.__getattr__ = _value_getattr ############################################################## # -# The standard repr for SBValue will recurse infinitely if you -# provide useful synth providers for smart pointers +# The standard repr for SBValue will recurse infinitely if +# you provide useful synth providers for smart pointers. +# Monkey-patch it. # ############################################################## @@ -1126,3 +1034,44 @@ def _sbvalue_display(v): lldb.SBValue.__repr__ = _sbvalue_repr +############################################################## +# +# Module Initialization +# +############################################################# + +def __lldb_init_module(debugger, dict): + print("Running lldb_init_module") + _init_globals(debugger.GetSelectedTarget()) + debugger.HandleCommand('type category delete UEDataFormatters') + debugger.HandleCommand('type summary add -F UEDataFormatter.UEFStringSummaryProvider -e FString -w UEDataFormatters') + debugger.HandleCommand('type summary add -F UEDataFormatter.UEFNameSummaryProvider -e FName -w UEDataFormatters') + debugger.HandleCommand('type synthetic add -l UEDataFormatter.TObjectPtrSynthProvider -x "^TObjectPtr<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type summary add -F UEDataFormatter.TObjectPtrSummaryProvider -e -x "^TObjectPtr<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type synthetic add -l UEDataFormatter.TStrongObjectPtrSynthProvider -x "^TStrongObjectPtr<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type summary add -F UEDataFormatter.TStrongObjectPtrSummaryProvider -e -x "^TStrongObjectPtr<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type synthetic add -l UEDataFormatter.TSharedPtrSynthProvider -x "^TSharedPtr<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type summary add -F UEDataFormatter.TSharedPtrSummaryProvider -e -x "^TSharedPtr<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type synthetic add -l UEDataFormatter.TSharedPtrSynthProvider -x "^TSharedRef<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type summary add -F UEDataFormatter.TSharedPtrSummaryProvider -e -x "^TSharedRef<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type synthetic add -l UEDataFormatter.TWeakPtrSynthProvider -x "^TWeakPtr<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type summary add -F UEDataFormatter.TWeakPtrSummaryProvider -e -x "^TWeakPtr<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type synthetic add -l UEDataFormatter.TWeakObjectPtrSynthProvider -x "^TWeakObjectPtr<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type summary add -F UEDataFormatter.TWeakObjectPtrSummaryProvider -e -x "^TWeakObjectPtr<.+>$" -w UEDataFormatters') + debugger.HandleCommand('type synthetic add -l UEDataFormatter.TWeakObjectPtrSynthProvider -x "^FWeakObjectPtr$" -w UEDataFormatters') + debugger.HandleCommand('type summary add -F UEDataFormatter.TWeakObjectPtrSummaryProvider -e FWeakObjectPtr -w UEDataFormatters') + debugger.HandleCommand('type synthetic add -l UEDataFormatter.UObjectSynthProvider UObject -w UEDataFormatters') + debugger.HandleCommand('type summary add -F UEDataFormatter.UObjectSummaryProvider -e UObject -w UEDataFormatters') + # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UEArraySynthProvider -x "TArray<.+,.+>$" -w UEDataFormatters') + # debugger.HandleCommand('type summary add -F UEDataFormatter.UEArraySummaryProvider -e -x "TArray<.+>$" -w UEDataFormatters') + # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UEBitArraySynthProvider -x "TBitArray<.+>$" -w UEDataFormatters') + # debugger.HandleCommand('type summary add -F UEDataFormatter.UEBitArraySummaryProvider -e -x "TBitArray<.+>$" -w UEDataFormatters') + # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UESparseArraySynthProvider -x "TSparseArray<.+>$" -w UEDataFormatters') + # debugger.HandleCommand('type summary add -F UEDataFormatter.UESparseArraySummaryProvider -e -x "TSparseArray<.+>$" -w UEDataFormatters') + # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UESetSynthProvider -x "TSet<.+>$" -w UEDataFormatters') + # debugger.HandleCommand('type summary add -F UEDataFormatter.UESetSummaryProvider -e -x "TSet<.+>$" -w UEDataFormatters') + # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UEMapSynthProvider -x "TMap<.+>$" -w UEDataFormatters') + # debugger.HandleCommand('type summary add -F UEDataFormatter.UEMapSummaryProvider -e -x "TMap<.+>$" -w UEDataFormatters') + # debugger.HandleCommand('type synthetic add -l UEDataFormatter.UEMapSynthProvider -x "TMapBase<.+>$" -w UEDataFormatters') + # debugger.HandleCommand('type summary add -F UEDataFormatter.UEMapSummaryProvider -e -x "TMapBase<.+>$" -w UEDataFormatters') + debugger.HandleCommand("type category enable UEDataFormatters")