The logic is a bit wrong in my script, it should first print out the variables
we have already found, followed by the one we are currently processing. The
fixed script is attached:
#!/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
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]
print 'is shadowed by:'
print block, block_var
# 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()
And the output is now correct:
(lldb) check-shadow
Block: {id: 94} [0x100000f7b-0x100000f8b) (int) v = 2
is shadowed by:
Block: {id: 46} [0x100000f70-0x100000f8d) (int) v = 1
> On Jun 22, 2016, at 1:57 PM, Greg Clayton via lldb-dev
> <[email protected]> wrote:
>
> 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:
>
> <lldbshadow.py>
>
>
> 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
>> <[email protected]> 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: [email protected]
>> Web: romania.ni.com
>>
>> Vanzari si suport tehnic:
>> Telefon gratuit : 0800 070071
>> E-mail vanzari: [email protected]
>> E-mail suport tehnic: [email protected]
>> _______________________________________________
>> lldb-dev mailing list
>> [email protected]
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
>
> _______________________________________________
> lldb-dev mailing list
> [email protected]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
_______________________________________________
lldb-dev mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev