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 > <lldb-dev@lists.llvm.org> 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 >> <lldb-dev@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.c...@ni.com >> Web: romania.ni.com >> >> Vanzari si suport tehnic: >> Telefon gratuit : 0800 070071 >> E-mail vanzari: ni.roma...@ni.com >> E-mail suport tehnic: techsupp...@ni.com >> _______________________________________________ >> lldb-dev mailing list >> lldb-dev@lists.llvm.org >> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev > > _______________________________________________ > lldb-dev mailing list > lldb-dev@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
_______________________________________________ lldb-dev mailing list lldb-dev@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev