Custom data formatter in LLDB

Viewed 646

I'm doing a deep dive into the LLDB and its custom data formatter. Let's say I want to examine the following code:

import simd

let f2 = float2(42, 50)
print(f2.x)

I place a break on the print line then in the debugger, print the value of f2:

(lldb) p f2
(float2) $R3 = (_vector = Builtin.Vec2xFPIEEE32 @ 0x00007fd15a9b4520)

Nothing useful here! So I made my custom summary string in LLDB:

(lldb) type summary add --summary-string "x = ${var.x}, y = ${var.y}" float2
(lldb) p f2
(float2) $R2 = error: summary string parsing error

I'm flummoxed at the error on the last line. It is valid according to the LLDB Data Formatter page. My next intuition is float2 does not have a property with name x but that's not the case at all.

Why does the summary string fail?


Edit: with Jim Ingham's help I was able to come up with the following solution:

In file simd.py:

import lldb

def GetSummary(valobj, internal_dict):
    frame = valobj.GetFrame()
    name = valobj.GetName()
    x_value = frame.EvaluateExpression('{0}.x'.format(name))
    y_value = frame.EvaluateExpression('{0}.y'.format(name))
    x = x_value.GetValueAsUnsigned()
    y = y_value.GetValueAsUnsigned()
    return 'x = {0}, y = {1}'.format(x, y)

Then load the function in LLDB:

(lldb) command script import ~/simd.py
(lldb) type summary add -F simd.GetSummary float2

Now it works with fr v f2 but not p f2:

(lldb) fr v f2
(float2) f2 = x = 42, y = 50
(lldb) p f2
(float2) $R4 = x = 0, y = 0

It also doesn't handle floating point numbers, if I change f2's values to floating point numbers

let f2 = float2(42, 50)
(lldb) fr v f2
(float2) f2 = x = 42, y = 50
1 Answers

The ${var.*} syntax of the lldb data formatters only does ivar lookup to find *, it doesn't run an expression with the string you've provided. It will have access to all the elements of the object that the lldb command frame var can show.

The reason for that restriction is that calling functions is much more expensive than straight ivar access and if we ran all the ${var.*} specs as function calls you could easily end up with a pretty non-performant formatter.

If you do need to call functions in your formatter, you can use the Python function flavor of formatter, and SBFrame.EvaluateExpression to run the expression.

That's relevant here because x is a computed property on float2, it isn't an ivar:

(lldb) fr v --raw f2
(simd.float2) f2 = {
  _value = {}
}

The only actual ivar of float2 is the opaque _value.

Note also for this particular need that Xcode 10 has data formatters for the simd types, so there you will see:

(lldb) fr v f2
(float2) f2 = (4.200000e+01, 5.000000e+01)

The person who wrote that data formatter knows how the simd data is actually laid out so they wrote one that could gather the values by memory accesses not function calls, so it will still be pretty fast. For the observant, that's also why I had to add the --raw in the frame var command above.

Related