[lldb-dev] Variable shadowing

Greg Clayton via lldb-dev lldb-dev at lists.llvm.org
Wed Jun 22 13:57:04 PDT 2016


You can currently do this by checking for other variables to see if any names match.

In python when stopped in the function below you can do use the API:


(lldb) script
Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
>>> frame_vars = lldb.frame.GetVariables(True, True, True, True)
>>> print frame_vars
(int) v = 1
(int) v = 2

frame_vars is a list of all variables in the current stack frame. They are ordered correctly so you see your first "v" first and the second one next.

Lets grab the exact lexical block from the current frame:

>>> block = lldb.frame.GetBlock()

This is the block from line 4 - 7 in your source code.

>>> print block.GetVariables(lldb.frame, True, True, True, 0)
(int) v = 2

Note that if we ask the block for its variables, it will only have the variables contained in that block. Now you can ask "block" for its parent block:

>>> print block.GetParent().GetVariables(lldb.frame, True, True, True, 0)
(int) v = 1


So with all of this you could create a new python command:


#!/usr/bin/python

import lldb
import shlex

@lldb.command("check-shadow")
def check_shadow_command(debugger, command, result, dict):
    target = debugger.GetSelectedTarget()
    if not target:
        print >>result, "invalid target"
        return
    process = target.GetProcess()
    if not process:
        print >>result, "invalid process"
        return
    thread = process.GetSelectedThread()
    if not thread:
        print >>result, "invalid thread"
        return
    frame = thread.GetSelectedFrame()
    if not frame:
        print >>result, "invalid frame"
        return
    # Parse command line args
    command_args = shlex.split(command)
    # TODO: add support for using arguments that are passed to this command...
    
    # Make a dictionary of variable name to "SBBlock and SBValue"
    var_dict = {}
    
    # Get the deepest most block from the current frame
    block = frame.GetBlock()
    # Iterate through the block and all of its parents
    while block.IsValid():
        # Get block variables from the current block only
        block_vars = block.GetVariables(frame, True, True, True, 0)
        # Iterate through all variables in the current block
        for block_var in block_vars:
            # Get the variable name and see if we already have a variable by this name?
            block_var_name = block_var.GetName()
            if block_var_name in var_dict:
                # We already have seen a variable with this name, so it is shadowed
                print block, block_var
                print 'is shadowed by:'
                shadow_block_and_vars = var_dict[block_var_name]
                for shadow_block_and_var in shadow_block_and_vars:
                    print shadow_block_and_var[0], shadow_block_and_var[1]
            # Since we can have multiple shadowed variables, we our variable
            # name dictionary to have an array or "block + variable" pairs so
            # We can correctly print out all shadowed variables and whow which
            # blocks they come from
            if block_var_name in var_dict:
                var_dict[block_var_name].append([block, block_var])
            else:
                var_dict[block_var_name] = [[block, block_var]]
        # Get the parent block and continue 
        block = block.GetParent()
    



I have attached this as a script that you can import:

-------------- next part --------------
A non-text attachment was scrubbed...
Name: lldbshadow.py
Type: text/x-python-script
Size: 2321 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20160622/0e8cc24d/attachment.bin>
-------------- next part --------------



Then you can run this:


% lldb a.out 
(lldb) command script import /tmp/lldbshadow.py
(lldb) target create "a.out"
(lldb) b main.cpp:6
(lldb) run
Process 423 stopped
* thread #1: tid = 0x46a88f, 0x0000000100000f82 a.out foo() + 18, stop reason = breakpoint 1.1, queue = com.apple.main-thread
    frame #0: 0x0000000100000f82 a.out foo() + 18 at main.cpp:6
   3   	    int v = 1;
   4   	    {
   5   	        int v = 2;
-> 6   	        ++v;
   7   	    }
   8   	}
   9   	

(lldb) check-shadow
Block: {id: 46} [0x100000f70-0x100000f8d) (int) v = 1
is shadowed by:
Block: {id: 94} [0x100000f7b-0x100000f8b) (int) v = 2

So yes it is possible, and I have attached an example. Adding a function to SBValue might not make sense because SBValue objects are used to represent registers and many other things other than local variables, and there is no language agnostic rule we could use to implement this correctly at the generic API level.

Greg Clayton

> On Jun 22, 2016, at 9:43 AM, Bogdan Hopulele via lldb-dev <lldb-dev at lists.llvm.org> wrote:
> 
> Hi all,
> 
> I’m using lldb 3.9 through the C++ API and I’m trying to determine if a local variable is shadowed or not with no luck.
> For the code below:
>  
> 1.       Is there an API call, that I somehow missed, that can tell me that (v = 2) shadows (v = 1)?
> 2.       Can I rely on their order in the SBValueList object?
> 3.       Would you guys think it would be worth adding bool SBValue::IsShadowed() const ?
>  
>  
> 1 void foo()
> 2 {
>       3     int v = 1;
>       4     {
>       5           int v = 2;
> -->   6           ++v;
>       7     }
> 8 }
>  
> Thank,
> Bogdan
> National Instruments Romania S.R.L.
> ------------------------------------------------------
> B-dul 21 Decembrie 1989, nr. 77, A2
> Cluj-Napoca 400604, Romania
> C.I.F.: RO17961616 | O.R.C.: J12/3337/2005
> Telefon: +40 264 406428 | Fax: +40 264 406429
> E-mail: office.cluj at ni.com 
> Web: romania.ni.com 
> 
> Vanzari si suport tehnic:
> Telefon gratuit : 0800 070071
> E-mail vanzari: ni.romania at ni.com
> E-mail suport tehnic: techsupport at ni.com _______________________________________________
> lldb-dev mailing list
> lldb-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev



More information about the lldb-dev mailing list