<div dir="ltr">The type of RVALUE is defined as follows<div><br></div><div><div>typedef struct RVALUE {</div><div>    union {</div><div><span class="" style="white-space:pre">       </span>struct {</div><div><span class="" style="white-space:pre">   </span>    VALUE flags;<span class="" style="white-space:pre">                </span>/* always 0 for freed obj */</div>
<div><span class="" style="white-space:pre">    </span>    struct RVALUE *next;</div><div><span class="" style="white-space:pre"> </span>} free;</div><div><span class="" style="white-space:pre">    </span>struct RBasic  basic;</div>
<div><span class="" style="white-space:pre">    </span>struct RObject object;</div><div><span class="" style="white-space:pre">     </span>struct RClass  klass;</div><div><span class="" style="white-space:pre">     </span>struct RFloat  flonum;</div>
<div><span class="" style="white-space:pre">    </span>struct RString string;</div><div><span class="" style="white-space:pre">     </span>struct RArray  array;</div><div><span class="" style="white-space:pre">     </span>struct RRegexp regexp;</div>
<div><span class="" style="white-space:pre">    </span>struct RHash   hash;</div><div><span class="" style="white-space:pre">      </span>struct RData   data;</div><div><span class="" style="white-space:pre">      </span>struct RTypedData   typeddata;</div>
<div><span class="" style="white-space:pre">    </span>struct RStruct rstruct;</div><div><span class="" style="white-space:pre">    </span>struct RBignum bignum;</div><div><span class="" style="white-space:pre">     </span>struct RFile   file;</div>
<div><span class="" style="white-space:pre">    </span>struct RNode   node;</div><div><span class="" style="white-space:pre">      </span>struct RMatch  match;</div><div><span class="" style="white-space:pre">     </span>struct RRational rational;</div>
<div><span class="" style="white-space:pre">    </span>struct RComplex complex;</div><div><span class="" style="white-space:pre">   </span>struct {</div><div><span class="" style="white-space:pre">   </span>    struct RBasic basic;</div>
<div><span class="" style="white-space:pre">    </span>    VALUE v1;</div><div><span class="" style="white-space:pre">    </span>    VALUE v2;</div><div><span class="" style="white-space:pre">    </span>    VALUE v3;</div><div><span class="" style="white-space:pre">    </span>} values;</div>
<div>    } as;</div><div>#if GC_DEBUG</div><div>    const char *file;</div><div>    VALUE line;</div><div>#endif</div><div>} RVALUE;</div></div><div><br></div><div>So I guess it's not actually anonymous. It has the name "as" I wonder if the fact that "as" is a python keyword is what's causing the problem.</div>
<div><br></div><div><a href="https://docs.python.org/2.7/reference/lexical_analysis.html#keywords">https://docs.python.org/2.7/reference/lexical_analysis.html#keywords</a><br></div><div><br></div><div>page.start[0][0] seemed to give me an IndexError</div>
<div><br></div><div><div>>>> page.start[0][0]</div><div>Traceback (most recent call last):</div><div>  File "<console>", line 1, in <module></div><div>  File "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/Resources/Python/lldb/__init__.py", line 10848, in __getitem__</div>
<div>    raise IndexError("Index '%d' is out of range" % key)</div><div>IndexError: Index '0' is out of range</div></div><div><br></div><div>I did inspect the SBValue of page.start[0] a little further. GetNumChildren() == 1 and when I get that child and call GetName() it equals "as"</div>
<div><br></div><div>I think it really is a python reserved word thing. page.start[0].as gives me this</div><div><br></div><div><div>>>> print page.start[0].as</div><div>  File "<console>", line 1</div>
<div>    print page.start[0].as</div><div>                         ^</div><div>SyntaxError: invalid syntax</div></div><div><br></div><div>but this works perfectly fine</div><div> </div><div>>>> print page.start[0].__getattr__('as').basic.flags</div>
<div>(VALUE) flags = 98</div><div><br></div><div>I'm not quite sure though why page.start[0][0] doesn't work. If GetNumChildren() == 1 and there clearly is a "as" child I would have thought it would work. Looking closer though at __getitem__ it's doing</div>
<div><br></div><div>child_sbvalue = (self.sbvalue.GetValueForExpressionPath("[%i]" % key))<br></div><div><br></div><div>Which isn't the same thing as self.sbvalue.GetChildAtIndex[0]</div><div><br></div><div>
I can stick to doing</div><div><br></div><div><span style="font-family:arial,sans-serif;font-size:13px">rvalue_as = lldb.value(rvalue.__dict__['</span><span style="font-family:arial,sans-serif;font-size:13px">sbvalue'].GetChildAtIndex[0])</span><br>
</div><div><span style="font-family:arial,sans-serif;font-size:13px"><br></span></div><div><font face="arial, sans-serif">And then I can do rvalue_as.basic.flags fine, but like I said for some reason having that line inside a loop that runs 600,000 times seems to cause it to slow down slower and slower and slower. If I remove that GetChildAtIndex line the loop completes in a minute or so. I don't expect things to be instant trying to loop through so many internal objects but having the line above seems to cause it just to take so long that I'm not patient enough to see it finish.</font></div>
<div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">Thanks again for all the help troubleshooting this.</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">-Scott Knight</font></div>
<div><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Apr 17, 2014 at 6:12 PM, Greg Clayton <span dir="ltr"><<a href="mailto:gclayton@apple.com" target="_blank">gclayton@apple.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">For what its worth, I compiled the following example<br>
<br>
struct stuff {<br>
    union {<br>
        struct {<br>
            int a;<br>
            int b;<br>
        } ints;<br>
        struct {<br>
            char a;<br>
            char b;<br>
        } chars;<br>
    };<br>
};<br>
int main (int argc, char const *argv[], char const *envp[])<br>
{<br>
    stuff s;<br>
    s.ints.a = 11;<br>
    s.ints.b = 22;<br>
    return 0;<br>
}<br>
<br>
And it all worked fine:<br>
<br>
>>> s = lldb.value(lldb.frame.FindVariable('s'))<br>
>>> print s.ints.b<br>
(int) b = 22<br>
>>> print s.ints.a<br>
(int) a = 11<br>
>>> print s.chars.a<br>
(char) a = '\v'<br>
>>> print s.chars.b<br>
(char) b = '\0'<br>
>>> print hex(s.chars.a)<br>
0xb<br>
<br>
<br>
What is the type of rvalue? If you can come up with a simple example on what isn't working and send it my way I can fix anything that is broken.<br>
<br>
Greg<br>
<br>
<br>
On Apr 17, 2014, at 3:02 PM, Greg Clayton <<a href="mailto:gclayton@apple.com">gclayton@apple.com</a>> wrote:<br>
<br>
> It is either a bug in the lldb.value code (which is in LLDB.framework/Resources/Python/lldb/__init__.py) or it could be a bug in LLDB where we aren't able to access a variable through an anonymous union.<br>
><br>
> You might be able to get away with:<br>
><br>
> rvalue[0].as.basic.flags<br>
><br>
> Let me know if that works? If it doesn't, you can probably modify the "class value" in the "lldb/__init__.py" to "do the right thing. Also when digging up child values by name in the []<br>

><br>
> You might also be able to do:<br>
><br>
>  rvalue = page.start[0][0]<br>
><br>
> then the rvalue should work for you?<br>
><br>
> If neither do, we can probably fix the name lookup which is currently this:<br>
><br>
>    def __getattr__(self, name):<br>
>        child_sbvalue = self.sbvalue.GetChildMemberWithName (name)<br>
>        if child_sbvalue and child_sbvalue.IsValid():<br>
>            return value(child_sbvalue)<br>
>        raise AttributeError("Attribute '%s' is not defined" % name)<br>
><br>
> If could be modified to do:<br>
><br>
><br>
>    def __getattr__(self, name):<br>
>        child_sbvalue = self.sbvalue.GetChildMemberWithName (name)<br>
>        if child_sbvalue and child_sbvalue.IsValid():<br>
>            return value(child_sbvalue)<br>
>        n = self.sbvalue.GetNumChildren()<br>
>        for i in range(n):<br>
>            child_sbvalue = self.sbvalue.GetChildAtIndex(i)<br>
>            child_name = child_sbvalue.GetName()<br>
>            if child_name == None or child_name == '':<br>
>                child_value = value(child_sbvalue)<br>
>               child_child_sbvalue = child_value.__getattr__(name)<br>
>                if child_sbvalue and child_sbvalue.IsValid():<br>
>                    return child_value<br>
>        raise AttributeError("Attribute '%s' is not defined" % name)<br>
><br>
><br>
> This extra code will check any children that don't have names and recurse down into them to find the correct name...<br>
><br>
> Greg<br>
><br>
> On Apr 17, 2014, at 2:26 PM, Scott Knight <<a href="mailto:knightsc@gmail.com">knightsc@gmail.com</a>> wrote:<br>
><br>
>> One last thing I can't seem to figure out. I have this<br>
>><br>
>> self.ruby_current_vm = lldb.value(lldb.target.FindFirstGlobalVariable('ruby_current_vm'))<br>
>> self.heaps_used = self.ruby_current_vm.objspace.heap_pages.used<br>
>><br>
>> for i in xrange(self.heaps_used):<br>
>>  page = self.ruby_current_vm.objspace.heap_pages.sorted[i]<br>
>><br>
>>  for j in xrange(page.limit):<br>
>>    rvalue = page.start[0]<br>
>><br>
>> But I can't seem to access rvalue fields correctly. I would have expected based on the output below that I could do rvalue.as.basic.flags but I get this error<br>
>><br>
>>>>> rvalue.as.basic.flags<br>
>>  File "<console>", line 1<br>
>>    rvalue.as.basic.flags<br>
>>            ^<br>
>> SyntaxError: invalid syntax<br>
>><br>
>> Below is the output from printing the whole rvalue variable. It has an anonymous union as. I can do<br>
>><br>
>> real_rvalue = lldb.value(rvalue.__dict__['sbvalue'].GetChildAtIndex[0]) and then I seem to be able to do<br>
>><br>
>> real_rvalue.basic.flags but add that extra line inside the loop above kills the speed and things start getting slower and slower again.<br>
>><br>
>> Thanks,<br>
>> Scott Knight<br>
>><br>
>> (RVALUE) [0] = {<br>
>>  as = {<br>
>>    free = {<br>
>>      flags = 98<br>
>>      next = 0x00007f9a0107bfa0<br>
>>    }<br>
>>    basic = (flags = 98, klass = 140299418976160)<br>
>>    object = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      as = {<br>
>>        heap = {<br>
>>          numiv = 140299418632320<br>
>>          ivptr = 0x00007f9a00c274d0<br>
>>          iv_index_tbl = 0x00007f9a00c27530<br>
>>        }<br>
>>        ary = ([0] = 140299418632320, [1] = 140299414435024, [2] = 140299414435120)<br>
>>      }<br>
>>    }<br>
>>    klass = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      super = 140299418632320<br>
>>      ptr = 0x00007f9a00c274d0<br>
>>      m_tbl_wrapper = 0x00007f9a00c27530<br>
>>    }<br>
>>    flonum = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      float_value = 6.93171228777286E-310<br>
>>    }<br>
>>    string = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      as = {<br>
>>        heap = {<br>
>>          len = 140299418632320<br>
>>          ptr = 0x00007f9a00c274d0 ""<br>
>>          aux = (capa = 140299414435120, shared = 140299414435120)<br>
>>        }<br>
>>        ary = "\x80\x80\x02\x01\x9a\x7f"<br>
>>      }<br>
>>    }<br>
>>    array = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      as = {<br>
>>        heap = {<br>
>>          len = 140299418632320<br>
>>          aux = (capa = 140299414435024, shared = 140299414435024)<br>
>>          ptr = 0x00007f9a00c27530<br>
>>        }<br>
>>        ary = ([0] = 140299418632320, [1] = 140299414435024, [2] = 140299414435120)<br>
>>      }<br>
>>    }<br>
>>    regexp = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      ptr = 0x00007f9a01028080<br>
>>      src = 140299414435024<br>
>>      usecnt = 140299414435120<br>
>>    }<br>
>>    hash = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      ntbl = 0x00007f9a01028080<br>
>>      iter_lev = 12743888<br>
>>      ifnone = 140299414435120<br>
>>    }<br>
>>    data = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      dmark = 0x00007f9a01028080<br>
>>      dfree = 0x00007f9a00c274d0<br>
>>      data = 0x00007f9a00c27530<br>
>>    }<br>
>>    typeddata = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      type = 0x00007f9a01028080<br>
>>      typed_flag = 140299414435024<br>
>>      data = 0x00007f9a00c27530<br>
>>    }<br>
>>    rstruct = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      as = {<br>
>>        heap = {<br>
>>          len = 140299418632320<br>
>>          ptr = 0x00007f9a00c274d0<br>
>>        }<br>
>>        ary = ([0] = 140299418632320, [1] = 140299414435024, [2] = 140299414435120)<br>
>>      }<br>
>>    }<br>
>>    bignum = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      as = {<br>
>>        heap = {<br>
>>          len = 140299418632320<br>
>>          digits = 0x00007f9a00c274d0<br>
>>        }<br>
>>        ary = ([0] = 16941184, [1] = 32666, [2] = 12743888, [3] = 32666, [4] = 12743984, [5] = 32666)<br>
>>      }<br>
>>    }<br>
>>    file = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      fptr = 0x00007f9a01028080<br>
>>    }<br>
>>    node = {<br>
>>      flags = 98<br>
>>      nd_reserved = 140299418976160<br>
>>      u1 = {<br>
>>        node = 0x00007f9a01028080<br>
>>        id = 140299418632320<br>
>>        value = 140299418632320<br>
>>        cfunc = 0x00007f9a01028080<br>
>>        tbl = 0x00007f9a01028080<br>
>>      }<br>
>>      u2 = {<br>
>>        node = 0x00007f9a00c274d0<br>
>>        id = 140299414435024<br>
>>        argc = 140299414435024<br>
>>        value = 140299414435024<br>
>>      }<br>
>>      u3 = {<br>
>>        node = 0x00007f9a00c27530<br>
>>        id = 140299414435120<br>
>>        state = 140299414435120<br>
>>        entry = 0x00007f9a00c27530<br>
>>        args = 0x00007f9a00c27530<br>
>>        cnt = 140299414435120<br>
>>        value = 140299414435120<br>
>>      }<br>
>>    }<br>
>>    match = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      str = 140299418632320<br>
>>      rmatch = 0x00007f9a00c274d0<br>
>>      regexp = 140299414435120<br>
>>    }<br>
>>    rational = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      num = 140299418632320<br>
>>      den = 140299414435024<br>
>>    }<br>
>>    complex = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      real = 140299418632320<br>
>>      imag = 140299414435024<br>
>>    }<br>
>>    values = {<br>
>>      basic = (flags = 98, klass = 140299418976160)<br>
>>      v1 = 140299418632320<br>
>>      v2 = 140299414435024<br>
>>      v3 = 140299414435120<br>
>>    }<br>
>>  }<br>
>> }<br>
>><br>
>><br>
>> On Thu, Apr 17, 2014 at 2:27 PM, Greg Clayton <<a href="mailto:gclayton@apple.com">gclayton@apple.com</a>> wrote:<br>
>><br>
>> SBValue<br>
>> SBTarget::FindFirstGlobalVariable (const char* name);<br>
>><br>
>> This doesn't support the "GetValueForVariablePath()", so you will need to do:<br>
>><br>
>> ruby_current_vm = lldb.target.FindFirstGlobalVariable('ruby_current_vm');<br>
>><br>
>> heaps_used = ruby_current_vm.GetValueForExpressionPath('->objspace->heap_pages.used').GetValueAsUnsigned(0)<br>
>><br>
>> You can also use a very handy wrapper utility class called lldb.value:<br>
>><br>
>> ruby_current_vm = lldb.value(lldb.target.FindFirstGlobalVariable('ruby_current_vm'))<br>
>><br>
>> Now "ruby_current_vm" behaves like a C structure would, except you can't use "->" to refer to a child of a pointer you need to use ".". So you should be able to do:<br>
>><br>
>> heaps_used = ruby_current_vm.objspace.heap_pages.used<br>
>><br>
>> for i in xrange(heaps_used):<br>
>>    page = ruby_current_vm.objspace.heap_pages.sorted[i]<br>
>><br>
>> You had a derefernce on "page" before, but, you can use page is a lldb.value, so you can just do "page.foo.bar" if you need anything inside of it.<br>
>><br>
>> Greg<br>
>><br>
>> On Apr 17, 2014, at 11:09 AM, Scott Knight <<a href="mailto:knightsc@gmail.com">knightsc@gmail.com</a>> wrote:<br>
>><br>
>>> Thanks for the information Greg. I have a quick followup. I'm using the version of lldb that comes with XCode 5.1.1<br>
>>><br>
>>> Launching it like this<br>
>>><br>
>>> Scotts-MacBook-Pro:~ scottknight$ /Applications/Xcode.app/Contents/Developer/usr/bin/lldb -p 13892<br>
>>> Attaching to process with:<br>
>>>    process attach -p 13892<br>
>>> Process 13892 stopped<br>
>>> Executable module set to "/Users/scottknight/.rbenv/versions/2.1.1/bin/ruby".<br>
>>> Architecture set to: x86_64-apple-macosx.<br>
>>><br>
>>> When I tried using GetValueForVariablePath I got 'No value' back. See the output below.<br>
>>><br>
>>> (lldb) v<br>
>>> lldb-310.2.37<br>
>>> (lldb) script<br>
>>> Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.<br>
>>>>>> print lldb.frame.EvaluateExpression('ruby_current_vm')<br>
>>> (rb_vm_t *) $1 = 0x00007f9a01003000<br>
>>>>>> print lldb.frame.GetValueForVariablePath('ruby_current_vm')<br>
>>> No value<br>
>>><br>
>>> Since ruby_current_vm is a global variable is there something different I would need to do to access it?<br>
>>><br>
>>> Thanks,<br>
>>> Scott Knight<br>
>>><br>
>>><br>
>>> On Thu, Apr 17, 2014 at 1:45 PM, Greg Clayton <<a href="mailto:gclayton@apple.com">gclayton@apple.com</a>> wrote:<br>
>>> Running expressions has all sorts of side effects like storing data in the inferior program and it also involves running the clang expression parser which can be expensive.<br>
>>><br>
>>> You can, from a frame, get a SBValue for a variable without using the expression parser:<br>
>>><br>
>>>    lldb::SBValue<br>
>>>    SBFrame.GetValueForVariablePath (const char *var_path);<br>
>>><br>
>>> So you can change your code to this:<br>
>>><br>
>>> heaps_used = lldb.frame.GetValueForVariablePath('ruby_current_vm->objspace->heap_pages.used').GetValueAsUnsigned(0)<br>
>>><br>
>>> for i in xrange(heaps_used):<br>
>>>    page = lldb.frame.GetValueForVariablePath('*ruby_current_vm->objspace->heap_pages.sorted[%i]' % i)<br>
>>><br>
>>> The GetValueForVariablePath() will find the variable and not create a temporary each time. It also doesn't use the expression parser at all so it won't call any code. The objects you access must be available in the hierarchy of the struct or class and the struct or class can't override the "->" operator. Other than that, the GetValueForVariablePath() knows how to access members ("ruby_current_vm->objspace->heap_pages.sorted"), dereference pointers using the array syntax ("my_ptr[12]"), deref a pointer ("*this->other_ptr"), and take the address of something ("&ruby_current_vm->objspace->heap_pages.sorted[12]").<br>

>>><br>
>>> So give the GetValueForVariablePath a try. The SBValue returned is something that represents the live variable value, not a const result like you get back from expression. SBValue you get back is tied to the frame from which you got it, so it will continue to evaluate correctly and its value will change if you step between calling functions with it. If the frame it came from goes away (step out), then it won't return any valid values again as it will detect the frame is gone and stop answering any questions. So you should always fetch a fresh value from the frame each time you want to use it.<br>

>>><br>
>>> Greg<br>
>>><br>
>>><br>
>>> On Apr 17, 2014, at 7:57 AM, Scott Knight <<a href="mailto:knightsc@gmail.com">knightsc@gmail.com</a>> wrote:<br>
>>><br>
>>>> I was recently using lldb to connect to a debug build of ruby to inspect the heap. In order to do this I was doing something like this<br>
>>>><br>
>>>> -----------<br>
>>>> heaps_used = lldb.frame.EvaluateExpression('ruby_current_vm->objspace->heap_pages.used').GetValueAsUnsigned(0)<br>
>>>><br>
>>>> for i in xrange(heaps_used):<br>
>>>>    page = lldb.frame.EvaluateExpression('*ruby_current_vm->objspace->heap_pages.sorted[%i]' % i)<br>
>>>> -----------<br>
>>>><br>
>>>> What I noticed was that for each EvaluateExpression a temporary $0, $1, $2, etc.. variable is created. If I ended up calling my python code multiple times more and more variables seemed to pile up and every EvaluateExpression call seemed to take longer and longer.<br>

>>>><br>
>>>> I tried calling EvaluateExpression how I would call expr from the lldb command line setting my own variable, so something like<br>
>>>><br>
>>>> lldb.frame.EvaluateExpression('int $test = 5')<br>
>>>><br>
>>>> But that seemed to error out. So is there some other way in the API that is better for accessing global variables that won't slow down. Is this something actually wrong with the debugger? I can create an actual test case similar to the test suite in lldb if that would be helpful.<br>

>>>><br>
>>>> Thanks,<br>
>>>> Scott Knight<br>
>>>><br>
>>>> _______________________________________________<br>
>>>> lldb-dev mailing list<br>
>>>> <a href="mailto:lldb-dev@cs.uiuc.edu">lldb-dev@cs.uiuc.edu</a><br>
>>>> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev</a><br>
>>><br>
>>><br>
>><br>
>><br>
><br>
> _______________________________________________<br>
> lldb-dev mailing list<br>
> <a href="mailto:lldb-dev@cs.uiuc.edu">lldb-dev@cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev</a><br>
<br>
</blockquote></div><br></div>