Lldb: a custom resume for vector elements (C ++)

I have a custom class MyNameSpace::String

for which I have created a summary in lldb. For example, for a, MyNameSpace::String myString="a string"

here's a summary in lldb:

frame variable myString
   (MyNameSpace::String) myString = "a string"

      

How do I get a summary for std::vector<MyNameSpace::String>vecString

what looks like a summary std::vector<std::string>vec

?

So far, here are the command results frame variable

for different variables:

  • standard string vector

    frame variable vec
    (std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >) vec = size=3 {
    [0] = "bonjour"
    [1] = "je suis"
    [2] = "vincent"
    }
    
          

  • my string vector

    frame variable vecString
    (std::__1::vector< MyNameSpace::String, std::__1::allocator< MyNameSpace::String> >) vecString = size=2 {
      [0] = {
        value = 7453010373645639777
      }
      [1] = {
        value = 18302628889929726940
      }
    }
    
          

How do I get my custom resume to apply to my vector elements?

Thanks a lot for any help.

V.

Edit: in response to comment

I am using lldb-310.2.37.

I created a summary for my String class using a script:

def generic_summary(valueObject,dict):
    name=valueObject.GetName()
    return valueObject.GetFrame().EvaluateExpression(name+".toString().toStdString()").GetSummary()

debugger.HandleCommand('type summary add MyNameSpace::String -F CustomSummaries.generic_summary')

      

which comes with the appropriate command in ~ / .lldbinit.

frame variable -T vecString

:

(lldb) frame variable -T vecString
(std::__1::vector<MyNameSpace::String, std::__1::allocator< MyNameSpace::String> >) vecString = size=2 {
  (MyNameSpace::String) [0] = {
    (MyNameSpace::uint8) value = 7453010373645639777
  }
  (MyNameSpace::String) [1] = {
    (MyNameSpace::uint8) value = 18302628889929726844
  }
}

      

+3


source to share


1 answer


So, as you understood - correct - your problem is here:

name=valueObject.GetName()

      

The true answer to your question is, "Don't do what you do." Let's take it step by step.

This is where you set a value for your name. if I have

struct Foo { int x; int y; } aFoo;

      

the SBValue name for "x" will be "x". If you want "aFoo.x", what you want to request is the path of the expression, which, as its name suggests, is what you would enter in the expression to refer to that value.

Things get more complicated when synthetic babies appear.

You might think that your element [0] has an expression path for vecString [0]. But this is not the case. Most likely it will just be [0]. Why?

This has to do with how synthetic babies are created. In particular, while the "x" in "aFoo" knows that its parent is the structure "aFoo", the [0] vecString does not. It is created from a solid fabric as a value whose location is a specific memory address. Given the location of the libc ++ vector:

struct vector<T> { T* begin; T* end; T* endStorage; };

      

formula: locationOfXElement = begin + X * sizeof (T)

(it's all sketched and pseudocode, but handle me!)

What LLDB does is calculate that location and then says - well, now create a ValueObject (internal term for SBValue, if you like) at that location in memory. It has nothing to do with the base vector. It's just value in some place. Hence, the notion of an expression path is wrong.

“But you can fix it!” You proclaim.

Yes, we probably could. Suppose a synthetic child has a boolean parent and also an idea of ​​what type of struct access is being modeled: is it like an array? type pointer? structure like? This means that one could write myObject [N], vs. myObject-> foo vs. myObject.bar

So that it can be done. It still won't solve your problem.

Instead of a vector, now consider

std::map<yourString,int> myMap;

      



LLDB presents this as a glorified set

pair<myString,int> { myString key; int value };

      

named [0], [1], ...

Let's say we get the expression path syntax correct and we represent it as

myMap[0].key

      

Try using that in an expression! Yes, you guessed it - it will fail! myMap :: operator [] expects a string, not a numeric index. In this case, the very presentation mode chosen by LLDB breaks the usability of synthetic children in code, no matter how smart the expression paths are.

I'm sure this can be fixed too, but at the end of the day there are good reasons not to use synthetic children when evaluating expressions. Consider the following:

vecString[0].size()

      

Do you want your vector element to be available to the [] operator? Or do you want synthetic babies to be used?

How about this?

vecString[0] = "hello"

      

And now?

vecString[0] = vecString[0] + " world!"

      

In general, the problem of mixing synthetic children and expressions is hard enough that we went with no no - synthetic children are completely transparent to the expression evaluator.

And now we're back to "don't do what you do", don't try to run the code in formatting unless you really really really need to, and even then be prepared for such headaches.

I'm guessing that "toString (). ToStdString ()" essentially does some memory accesses and some computation - what you want to do is replicated in Python code using memory reads, and instead doing computations in Python learning code functions for evaluating expressions.

The resulting formatter will be faster, potentially much more reliable - and will work in all cases.

+3


source







All Articles