Luke Worth
Luke Worth

Reputation: 631

Can LLDB data formatters call methods?

I'm debugging a Qt application using LLDB. At a breakpoint I can write

(lldb) p myQString.toUtf8().data()

and see the string contained within myQString, as data() returns char*. I would like to be able to write

(lldb) p myQString

and get the same output. This didn't work for me:

(lldb) type summary add --summary-string "${var.toUtf8().data()}" QString

Is it possible to write a simple formatter like this, or do I need to know the internals of QString and write a python script?

Alternatively, is there another way I should be using LLDB to view QStrings this way?

Upvotes: 5

Views: 2131

Answers (3)

Dimitry Markman
Dimitry Markman

Reputation: 34

The following does work.

First, register your summary command:

debugger.HandleCommand('type summary add -F  set_sblldbbp.qstring_summary "QString"')

Here is an implementation

def make_string_from_pointer_with_offset(F,OFFS,L):
    strval = 'u"'
    try:
        data_array = F.GetPointeeData(0, L).uint16
        for X in range(OFFS, L):
            V = data_array[X]
            if V == 0:
                break
            strval += unichr(V)
    except:
        pass
    strval = strval + '"'
    return strval.encode('utf-8')


#qt5
def qstring_summary(value, unused):
    try:
        d = value.GetChildMemberWithName('d')
        #have to divide by 2 (size of unsigned short = 2)
        offset = d.GetChildMemberWithName('offset').GetValueAsUnsigned() / 2
        size = get_max_size(value)
        return make_string_from_pointer_with_offset(d, offset, size)
    except:
        print '?????????????????????????'
        return value

def get_max_size(value):
    _max_size_ = None
    try:
        debugger = value.GetTarget().GetDebugger()
        _max_size_ = int(lldb.SBDebugger.GetInternalVariableValue('target.max-string-summary-length', debugger.GetInstanceName()).GetStringAtIndex(0))
    except:
        _max_size_ = 512
    return _max_size_

Upvotes: 2

Fox
Fox

Reputation: 2138

this is my trial-and-error adaptation of a UTF16 string interpretation lldb script I found online (I apologise that I don't remember the source - and that I can't credit the author)

Note that this is for Qt 4.3.2 and versions close to it - as the handling of the 'data' pointer has since changed between then and Qt 5.x

def QString_SummaryProvider(valobj, internal_dict):

data = valobj.GetChildMemberWithName('d')#.GetPointeeData()
strSize = data.GetChildMemberWithName('size').GetValueAsUnsigned()
newchar = -1
i = 0 
s = u'"'
while newchar != 0:
    # read next wchar character out of memory
    data_val = data.GetChildMemberWithName('data').GetPointeeData(i, 1)
    size = data_val.GetByteSize()
    e = lldb.SBError()
    if size == 1:
        newchar = data_val.GetUnsignedInt8(e, 0)    # utf-8
    elif size == 2:
        newchar = data_val.GetUnsignedInt16(e, 0)   # utf-16
    elif size == 4:
        newchar = data_val.GetUnsignedInt32(e, 0)   # utf-32
    else:
        s = s + '<unexpected char size - error parsing QString>'
        break
    if e.fail:
        s = s + '<parse error:' + e.why() + '>' 
        break

    i = i + 1 
    if i > strSize:
        break
    # add the character to our string 's'
    # print "char2 = %s" % newchar
    if newchar != 0:
        s = s + unichr(newchar)
s = s + u'"'
return s.encode('utf-8')

Upvotes: 0

Enrico Granata
Enrico Granata

Reputation: 3329

It is expected that what you tried to do won't work. The summary strings feature does not allow calling expressions.

Calling expressions in a debugger is always interesting, in a data formatter more so (if you're in an IDE - say Xcode - formatters run automatically). Every time you stop somewhere, even if you just stepped over one line, all these little expressions would all automatically run over and over again, at a large performance cost - and this is not even taking into account the fact that your data might be in a funny state already and running expressions has the potential to alter it even more, making your debugging sessions trickier than needed.

If the above wall of text still hasn't discouraged you ( :-) ), you want to write a Python formatter, and use the SB API to run your expression. Your value is an SBValue object, which has access to an SBFrame and an SBTarget. The combination of these two allows you to run EvaluateExpression("blah") and get back another SBValue, probably a char* to which you can then ask GetSummary() to get your c-string back.

If, on the other hand, you are now persuaded that running expressions in formatters is suboptimal, the good news is that QString most certainly has to store its data pointer somewhere.. if you find out where that is, you can just write a formatter as ${var.member1.member2.member3.theDataPointer} and obtain the same result!

Upvotes: 0

Related Questions