I'm sorry in advance, if it's not a correct mailing list, there doesn't seem to be lldb-usage mailing list.
I'm writing a pretty-printer python script, which - to cut to the chase, pretty prints members of a class by using EvaluateExpression and creating new object inside it. It doesn't seem to work - i'm getting "<could not resolve type>" error. Should my idea work in a first place and i't s a bug or it shouldn't and i need to find a different solution? I'm attaching a repro case: clang++ q.cpp -g -o o -std=c++20 lldb o command script import lldb_script.py br set --file q.cpp --line 19 r print c it prints: (lldb) print c (C) $0 = CCC { = <could not resolve type> } it should something akin to: (lldb) print c (C) $0 = CCC { b = B { a = A { id = "qwerty" } } }
#include <iostream> #include <string> #include <string_view> struct A { std::string_view id() const { return "qwerty"; } }; struct B { A a() const { return A(); } }; struct C { B b() const { return B(); } }; int main() { C c; return 0; }
import lldb.formatters.Logger import lldb import logging import sys import codecs import platform import json logger = lldb.formatters.Logger.Logger() logfile = codecs.open('log.txt', 'wb', encoding='utf8') log = logging.getLogger() log.setLevel(logging.INFO) FORMAT = "[%(filename)s:%(lineno)s] %(message)s" if log.handlers: log.handlers[0].setFormatter(logging.Formatter(FORMAT)) ch = logging.StreamHandler(logfile) ch.setLevel(logging.DEBUG) formatter = logging.Formatter(FORMAT) ch.setFormatter(formatter) log.addHandler(ch) log.error('-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------') log.error('starting') module = sys.modules[__name__] if sys.version_info[0] == 2: # python2-based LLDB accepts utf8-encoded ascii strings only. def to_lldb_str(s): return s.encode( 'utf8', 'backslashreplace') if isinstance(s, unicode) else s range = xrange else: to_lldb_str = str log = logging.getLogger(__name__) class V(object): def __init__(self, v, dict=None): self.v = v def EvaluateExpression(self, expr, name=None): v = self.v.CreateValueFromExpression(name, expr).dynamic assert v return V(v) class Base(V): regex = False def get_summary(self): return '' def update(self): pass def num_children(self): return 0 def has_children(self): return False def get_child_at_index(self, index): return None def get_child_index(self, name): return -1 class cc_A(Base): type = 'A' regex = False def num_children(self): return 1 def has_children(self): return True def get_child_at_index(self, index): assert index == 0 v = self.EvaluateExpression(f"id()", f'id') return v.v class cc_B(Base): type = 'B' regex = False def num_children(self): return 1 def has_children(self): return True def get_child_at_index(self, index): assert index == 0 v = self.EvaluateExpression(f"a()", f'a') return v.v class cc_C(Base): type = 'C' regex = False def get_summary(self): return 'CCC' def num_children(self): return 1 def has_children(self): return True def get_child_at_index(self, index): assert index == 0 return self.EvaluateExpression(f"b()").v def initialize_category(debugger): global module, std_category std_category = debugger.CreateCategory('C++') std_category.SetEnabled(True) glob = globals() todo = [] log.error('initialize_category') def add(a, b, c, d): todo.append(lambda: a(b, c, d)) for x, c in glob.items(): if x.startswith('ff_'): if isinstance(c.type, list): for t in c.type: add(attach_summary_to_type, c, t, c.regex) else: add(attach_summary_to_type, c, c.type, c.regex) elif x.startswith('cc_'): if isinstance(c.type, list): for t in c.type: add(attach_synthetic_to_type, c, t, c.regex) else: add(attach_synthetic_to_type, c, c.type, c.regex) for d in todo: d() def attach_synthetic_to_type(synth_class, type_name, is_regex=False): global module, std_category #log.info('attaching synthetic %s to "%s", is_regex=%s', synth_class.__name__, type_name, is_regex) synth = lldb.SBTypeSynthetic.CreateWithClassName( __name__ + '.' + synth_class.__name__) synth.SetOptions(lldb.eTypeOptionCascade) std_category.AddTypeSynthetic( lldb.SBTypeNameSpecifier(type_name, is_regex), synth) def summary_fn(valobj, dict): return get_synth_summary(synth_class, valobj, dict) # LLDB accesses summary fn's by name, so we need to create a unique one. summary_fn.__name__ = '_get_synth_summary_' + synth_class.__name__ setattr(module, summary_fn.__name__, summary_fn) attach_summary_to_type(summary_fn, type_name, is_regex) def attach_summary_to_type(summary_fn, type_name, is_regex=False): global module, std_category #log.info('attaching summary %s to "%s", is_regex=%s', summary_fn.__name__, type_name, is_regex) summary = lldb.SBTypeSummary.CreateWithFunctionName( __name__ + '.' + summary_fn.__name__) summary.SetOptions(lldb.eTypeOptionCascade) std_category.AddTypeSummary( lldb.SBTypeNameSpecifier(type_name, is_regex), summary) def get_synth_summary(synth_class, valobj, dict): synth = synth_class(valobj.GetNonSyntheticValue()) synth.update() summary = synth.get_summary() return to_lldb_str(summary) def __lldb_init_module(debugger, dict): initialize_category(debugger) _map_capping_size = 255 _list_capping_size = 255 _list_uses_loop_detector = True _deque_capping_size = 255
_______________________________________________ lldb-dev mailing list lldb-dev@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev