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

Reply via email to