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.
You might be able to get away with:
rvalue[0].as.basic.flags
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 []
You might also be able to do:
rvalue = page.start[0][0]
then the rvalue should work for you?
If neither do, we can probably fix the name lookup which is currently this:
def __getattr__(self, name):
child_sbvalue = self.sbvalue.GetChildMemberWithName (name)
if child_sbvalue and child_sbvalue.IsValid():
return value(child_sbvalue)
raise AttributeError("Attribute '%s' is not defined" % name)
If could be modified to do:
def __getattr__(self, name):
child_sbvalue = self.sbvalue.GetChildMemberWithName (name)
if child_sbvalue and child_sbvalue.IsValid():
return value(child_sbvalue)
n = self.sbvalue.GetNumChildren()
for i in range(n):
child_sbvalue = self.sbvalue.GetChildAtIndex(i)
child_name = child_sbvalue.GetName()
if child_name == None or child_name == '':
child_value = value(child_sbvalue)
child_child_sbvalue = child_value.__getattr__(name)
if child_sbvalue and child_sbvalue.IsValid():
return child_value
raise AttributeError("Attribute '%s' is not defined" % name)
This extra code will check any children that don't have names and recurse down
into them to find the correct name...
Greg
On Apr 17, 2014, at 2:26 PM, Scott Knight <[email protected]> wrote:
> One last thing I can't seem to figure out. I have this
>
> self.ruby_current_vm =
> lldb.value(lldb.target.FindFirstGlobalVariable('ruby_current_vm'))
> self.heaps_used = self.ruby_current_vm.objspace.heap_pages.used
>
> for i in xrange(self.heaps_used):
> page = self.ruby_current_vm.objspace.heap_pages.sorted[i]
>
> for j in xrange(page.limit):
> rvalue = page.start[0]
>
> 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
>
> >>> rvalue.as.basic.flags
> File "<console>", line 1
> rvalue.as.basic.flags
> ^
> SyntaxError: invalid syntax
>
> Below is the output from printing the whole rvalue variable. It has an
> anonymous union as. I can do
>
> real_rvalue = lldb.value(rvalue.__dict__['sbvalue'].GetChildAtIndex[0]) and
> then I seem to be able to do
>
> real_rvalue.basic.flags but add that extra line inside the loop above kills
> the speed and things start getting slower and slower again.
>
> Thanks,
> Scott Knight
>
> (RVALUE) [0] = {
> as = {
> free = {
> flags = 98
> next = 0x00007f9a0107bfa0
> }
> basic = (flags = 98, klass = 140299418976160)
> object = {
> basic = (flags = 98, klass = 140299418976160)
> as = {
> heap = {
> numiv = 140299418632320
> ivptr = 0x00007f9a00c274d0
> iv_index_tbl = 0x00007f9a00c27530
> }
> ary = ([0] = 140299418632320, [1] = 140299414435024, [2] =
> 140299414435120)
> }
> }
> klass = {
> basic = (flags = 98, klass = 140299418976160)
> super = 140299418632320
> ptr = 0x00007f9a00c274d0
> m_tbl_wrapper = 0x00007f9a00c27530
> }
> flonum = {
> basic = (flags = 98, klass = 140299418976160)
> float_value = 6.93171228777286E-310
> }
> string = {
> basic = (flags = 98, klass = 140299418976160)
> as = {
> heap = {
> len = 140299418632320
> ptr = 0x00007f9a00c274d0 ""
> aux = (capa = 140299414435120, shared = 140299414435120)
> }
> ary = "\x80\x80\x02\x01\x9a\x7f"
> }
> }
> array = {
> basic = (flags = 98, klass = 140299418976160)
> as = {
> heap = {
> len = 140299418632320
> aux = (capa = 140299414435024, shared = 140299414435024)
> ptr = 0x00007f9a00c27530
> }
> ary = ([0] = 140299418632320, [1] = 140299414435024, [2] =
> 140299414435120)
> }
> }
> regexp = {
> basic = (flags = 98, klass = 140299418976160)
> ptr = 0x00007f9a01028080
> src = 140299414435024
> usecnt = 140299414435120
> }
> hash = {
> basic = (flags = 98, klass = 140299418976160)
> ntbl = 0x00007f9a01028080
> iter_lev = 12743888
> ifnone = 140299414435120
> }
> data = {
> basic = (flags = 98, klass = 140299418976160)
> dmark = 0x00007f9a01028080
> dfree = 0x00007f9a00c274d0
> data = 0x00007f9a00c27530
> }
> typeddata = {
> basic = (flags = 98, klass = 140299418976160)
> type = 0x00007f9a01028080
> typed_flag = 140299414435024
> data = 0x00007f9a00c27530
> }
> rstruct = {
> basic = (flags = 98, klass = 140299418976160)
> as = {
> heap = {
> len = 140299418632320
> ptr = 0x00007f9a00c274d0
> }
> ary = ([0] = 140299418632320, [1] = 140299414435024, [2] =
> 140299414435120)
> }
> }
> bignum = {
> basic = (flags = 98, klass = 140299418976160)
> as = {
> heap = {
> len = 140299418632320
> digits = 0x00007f9a00c274d0
> }
> ary = ([0] = 16941184, [1] = 32666, [2] = 12743888, [3] = 32666, [4]
> = 12743984, [5] = 32666)
> }
> }
> file = {
> basic = (flags = 98, klass = 140299418976160)
> fptr = 0x00007f9a01028080
> }
> node = {
> flags = 98
> nd_reserved = 140299418976160
> u1 = {
> node = 0x00007f9a01028080
> id = 140299418632320
> value = 140299418632320
> cfunc = 0x00007f9a01028080
> tbl = 0x00007f9a01028080
> }
> u2 = {
> node = 0x00007f9a00c274d0
> id = 140299414435024
> argc = 140299414435024
> value = 140299414435024
> }
> u3 = {
> node = 0x00007f9a00c27530
> id = 140299414435120
> state = 140299414435120
> entry = 0x00007f9a00c27530
> args = 0x00007f9a00c27530
> cnt = 140299414435120
> value = 140299414435120
> }
> }
> match = {
> basic = (flags = 98, klass = 140299418976160)
> str = 140299418632320
> rmatch = 0x00007f9a00c274d0
> regexp = 140299414435120
> }
> rational = {
> basic = (flags = 98, klass = 140299418976160)
> num = 140299418632320
> den = 140299414435024
> }
> complex = {
> basic = (flags = 98, klass = 140299418976160)
> real = 140299418632320
> imag = 140299414435024
> }
> values = {
> basic = (flags = 98, klass = 140299418976160)
> v1 = 140299418632320
> v2 = 140299414435024
> v3 = 140299414435120
> }
> }
> }
>
>
> On Thu, Apr 17, 2014 at 2:27 PM, Greg Clayton <[email protected]> wrote:
>
> SBValue
> SBTarget::FindFirstGlobalVariable (const char* name);
>
> This doesn't support the "GetValueForVariablePath()", so you will need to do:
>
> ruby_current_vm = lldb.target.FindFirstGlobalVariable('ruby_current_vm');
>
> heaps_used =
> ruby_current_vm.GetValueForExpressionPath('->objspace->heap_pages.used').GetValueAsUnsigned(0)
>
> You can also use a very handy wrapper utility class called lldb.value:
>
> ruby_current_vm =
> lldb.value(lldb.target.FindFirstGlobalVariable('ruby_current_vm'))
>
> 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:
>
> heaps_used = ruby_current_vm.objspace.heap_pages.used
>
> for i in xrange(heaps_used):
> page = ruby_current_vm.objspace.heap_pages.sorted[i]
>
> 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.
>
> Greg
>
> On Apr 17, 2014, at 11:09 AM, Scott Knight <[email protected]> wrote:
>
> > Thanks for the information Greg. I have a quick followup. I'm using the
> > version of lldb that comes with XCode 5.1.1
> >
> > Launching it like this
> >
> > Scotts-MacBook-Pro:~ scottknight$
> > /Applications/Xcode.app/Contents/Developer/usr/bin/lldb -p 13892
> > Attaching to process with:
> > process attach -p 13892
> > Process 13892 stopped
> > Executable module set to
> > "/Users/scottknight/.rbenv/versions/2.1.1/bin/ruby".
> > Architecture set to: x86_64-apple-macosx.
> >
> > When I tried using GetValueForVariablePath I got 'No value' back. See the
> > output below.
> >
> > (lldb) v
> > lldb-310.2.37
> > (lldb) script
> > Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
> > >>> print lldb.frame.EvaluateExpression('ruby_current_vm')
> > (rb_vm_t *) $1 = 0x00007f9a01003000
> > >>> print lldb.frame.GetValueForVariablePath('ruby_current_vm')
> > No value
> >
> > Since ruby_current_vm is a global variable is there something different I
> > would need to do to access it?
> >
> > Thanks,
> > Scott Knight
> >
> >
> > On Thu, Apr 17, 2014 at 1:45 PM, Greg Clayton <[email protected]> wrote:
> > 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.
> >
> > You can, from a frame, get a SBValue for a variable without using the
> > expression parser:
> >
> > lldb::SBValue
> > SBFrame.GetValueForVariablePath (const char *var_path);
> >
> > So you can change your code to this:
> >
> > heaps_used =
> > lldb.frame.GetValueForVariablePath('ruby_current_vm->objspace->heap_pages.used').GetValueAsUnsigned(0)
> >
> > for i in xrange(heaps_used):
> > page =
> > lldb.frame.GetValueForVariablePath('*ruby_current_vm->objspace->heap_pages.sorted[%i]'
> > % i)
> >
> > 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]").
> >
> > 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.
> >
> > Greg
> >
> >
> > On Apr 17, 2014, at 7:57 AM, Scott Knight <[email protected]> wrote:
> >
> > > 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
> > >
> > > -----------
> > > heaps_used =
> > > lldb.frame.EvaluateExpression('ruby_current_vm->objspace->heap_pages.used').GetValueAsUnsigned(0)
> > >
> > > for i in xrange(heaps_used):
> > > page =
> > > lldb.frame.EvaluateExpression('*ruby_current_vm->objspace->heap_pages.sorted[%i]'
> > > % i)
> > > -----------
> > >
> > > 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.
> > >
> > > I tried calling EvaluateExpression how I would call expr from the lldb
> > > command line setting my own variable, so something like
> > >
> > > lldb.frame.EvaluateExpression('int $test = 5')
> > >
> > > 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.
> > >
> > > Thanks,
> > > Scott Knight
> > >
> > > _______________________________________________
> > > lldb-dev mailing list
> > > [email protected]
> > > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev
> >
> >
>
>
_______________________________________________
lldb-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev