[lldb-dev] https://reviews.llvm.org/D69273

Jim Ingham via lldb-dev lldb-dev at lists.llvm.org
Thu Oct 31 12:51:21 PDT 2019

It looks like this change is causing problems with swift.  I was talking a little bit with Davide about this and it seems like it wasn't obvious how this was designed to work.  So here's what this was intended to do (apologies if this is at too basic a level and the issue was something deeper I missed, but anyway this might get us started...)

The lldb ValueObject system supports two fairly different kinds of values, live and frozen.  

The classic example of a live ValueObject is ValueObjectVariable.  That ValueObject is backed by an entity in the target, and knows when that entity is valid and not.  So it can always try to do "UpdateValueIfNeeded" and that will always return good values.  However, there's on complication with this, which is that we also want ValueObjectVariable to be able to answer "IsChanged".  That's so in a UI you can mark values that change over a step in red, which is very helpful for following along in a debugging session.  So you have to copy the values into host memory, in order to have something to compare against when you stop again.  That's why there's this slightly complex dance between host and target memory for the live ValueObjects.

The example of a frozen object is the ValueObjectConstResult that is returned from expression evaluation.  That value is fixed to a StopID, so the backing entity is only known to be good at that stop id.  This is implemented by copying the value into Host memory and fetching it from there when requested.

The use case for this is for people like me who have a bad memory.  So I can stop somewhere and do:

(lldb) expr foo
struct baz $1 = {
  bar = 20

Then later on when I forget what foo.bar was at that time, I can do:

(lldb) expr $1.bar
bar = 20

At a first approximation, this leads to the statement that ConstValues should fetch what they fetch when made, and then not offer any information that wasn't gathered when the variable was fetched, and you certainly don't ever want these values to be updated.

A little complication arises because I might do:

(lldb) expr foo_which_has_a_pointer
$1 = ...
(lldb) expr *$1->the_pointer

If the StopID is the same between the first and second evaluation, then you should follow the pointer into target memory and fetch the value.  But if the StopID has changed, then trying to dereference a pointer should be an error.  After all, you are now accessing an incoherent object, and if you try to do anything fancier with it than just print some memory (like asking the Swift Language Runtime what this value happens to be) you are very likely to get into trouble.

So it's clear we need two different behaviors w.r.t. how we treat live or frozen values.  Pavel's change was addressing a failure in ValueObjectChild, and the solution was to move the ValueObjectVariable behavior up to the ValueObject level.  But then that means that ValueObjectConstResults are no longer obeying the ConstResult rules.

But it seems like the problem really is that we have only one ValueObjectChild class, but child value objects can either be live or frozen, depending on the nature of their Root ValueObject.  And this is made a little more complicated by the fact that frozen values only freeze when the stop ID changes.


More information about the lldb-dev mailing list