run after process stop using python API

I’m trying to use the ‘run’ command from the python API when my process has stopped at a breakpoint, but it appears to hang. Script attached.

i.HandleCommand(‘b main’, res)

i.HandleCommand(‘r’, res) → runs to breakpoint correctly

i.HandleCommand(‘r’, res) → appears to hang

This seems like a bug, but I thought I would ask in case the interpreter was waiting for some kind of input I wasn’t providing… I’m running on Linux, and haven’t had a chance to try OS X yet.

Ben

test.py (256 Bytes)

$ ./lldb /bin/ls
Current executable set to '/bin/ls' (x86_64).
(lldb) b malloc
Breakpoint 1: 2 locations.
(lldb) r
Process 48448 launched: '/bin/ls' (x86_64)
Process 48448 stopped
* thread #1: tid = 0x58fee, 0x00007fff906cd8f9 libsystem_malloc.dylib`malloc, stop reason = breakpoint 1.2
    frame #0: 0x00007fff906cd8f9 libsystem_malloc.dylib`malloc
libsystem_malloc.dylib`malloc:
-> 0x7fff906cd8f9: pushq %rbp
   0x7fff906cd8fa: movq %rsp, %rbp
   0x7fff906cd8fd: pushq %rbx
   0x7fff906cd8fe: pushq %rax
(lldb) r
There is a running process, kill it and restart?: [Y/n] <— this is where you are hung waiting for input

You probably want to say i.HandleCommand(“c”,res)

OTOH, I wonder if we could do any better w.r.t. handling commands that require input - I think in our test suite, to do that kind of thing, we use pexpect to read/write from/to LLDB’s stdin/stdout

And with all of that said, if you are trying to do any serious instrumentation of your process, you might want to consider using the LLDB event model instead of HandleCommand() scripting.
An example of how you would do that in Python is in our source base at examples/python/process_events.py and (for the C++ way) in the lldb-perf project

Enrico Granata
:envelope_with_arrow: egranata@.com
:phone: 27683

'run' is a GDB alias for process launch. If a process is already running, the command interpreter may be waiting for confirmation from the user that it's OK to restart the process (unless you turned off the prompt setting beforehand)... You probably want to issue a "continue" command to restart the process.

Cheers,
Dan

How do I turn off the prompt setting?

Also, continue isn’t what I want – I really do want to re-run the program from the start.

Ben

$ ./lldb /bin/ls
Current executable set to '/bin/ls' (x86_64).
(lldb) sett set auto-confirm true
(lldb) b malloc
Breakpoint 1: 2 locations.
(lldb) r
Process 48551 launched: '/bin/ls' (x86_64)
Process 48551 stopped
* thread #1: tid = 0x5edda, 0x00007fff906cd8f9 libsystem_malloc.dylib`malloc, stop reason = breakpoint 1.2
    frame #0: 0x00007fff906cd8f9 libsystem_malloc.dylib`malloc
libsystem_malloc.dylib`malloc:
-> 0x7fff906cd8f9: pushq %rbp
   0x7fff906cd8fa: movq %rsp, %rbp
   0x7fff906cd8fd: pushq %rbx
   0x7fff906cd8fe: pushq %rax
(lldb) r
Process 48554 launched: '/bin/ls' (x86_64)
Process 48554 stopped
* thread #1: tid = 0x5edf2, 0x00007fff906cd8f9 libsystem_malloc.dylib`malloc, stop reason = breakpoint 1.2
    frame #0: 0x00007fff906cd8f9 libsystem_malloc.dylib`malloc
libsystem_malloc.dylib`malloc:
-> 0x7fff906cd8f9: pushq %rbp
   0x7fff906cd8fa: movq %rsp, %rbp
   0x7fff906cd8fd: pushq %rbx
   0x7fff906cd8fe: pushq %rax

You want to set the auto-confirm lldb setting to true before you issue the second run

What exactly are you trying to achieve, if you can discuss it?

Enrico Granata
:envelope_with_arrow: egranata@.com
:phone: 27683

i.HandleCommand("settings set auto-confirm true")

I would really suggest using the async API. To see how to use the actual API to control your target, checkout the following example:

svn cat http://llvm.org/svn/llvm-project/lldb/trunk/examples/python/process_events.py

The example shows how to create a target and then debug it and us the API to wait for process state changed events and allows you to then control the process.

The main problem with your example below is that:

i.HandleCommand('r', res)

"r" can take an arbitrary amount of time. It will return, but your process might be running. It might be stopped. You have no idea what your process is doing.

Using the API correctly to wait for events will give you much more accurate control over your process, and this is why we made process_events.py.

Greg Clayton

Hi Greg,

In my application code I am using the async mode and I have been following process_events.py, so hopefully I'm doing it correctly. This was just a simple test program to show the issue I was having.

Thanks for the suggestions,

Ben

Just being able to re-run the target at any (reasonable) point. I’m working on a frontend for lldb using the python api, and I’m using the command interpreter to deal with user input.

Thanks,

Ben

Hi Ben,

The problem you seem to be having is not taking into account the
output of the debugger.
When you send the “run” command, it pushes an InputReader (I think)
and asks you if you're sure you want to continue.
If you take this into account, you can print that message on your
user's console, and the DispatchInput() with the reply. Could you try
that and see if it works?
If it doesn't work, you may find it necessary to do something like the
driver does, where you give the debugger an stdin and stdout and use
those for all input/output from/to the debugger itself.

Your UI over lldb should always try to use the SB* API, and never
HandleCommand (except for direct user input, but even then,
DispatchInput or the debugger's stdin should be possible to use, so
you don't need more than one input path).

Regards,

  Filipe

Is there documentation for DispatchInput somewhere? There are no comments in SBDebugger.h about it, and none of the examples seem to use it. What is the difference between DispatchInput and HandleCommand?

Ben

DispatchInput is for you to give input into the debugger which will be fed to the top level InputReader.

LLDB has input readers that funnel one stdin into which ever input reader is on the top. LLDB has many input readers:
- the command interpreter
- the stdin for the process
- the embedded python script interpreter
- multi-line code expressions when you type "expression<RETURN>"
- multi-line python expressions for breakpoints and such

By default the command interpreter is the one and only input reader.

(lldb)

The input read stack looks like:
1 - command interpreter

If you then type "script":

(lldb) script
Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.

Now the input read stack looks like:
1 - python interactive interpreter
2 - command interpreter

Any data passed into DispatchInput() will be passed to the top level interpreter until it decides it should be removed from the stack (by typing "quit()" in the python interactive interpreter).

So think of DispatchInput as supplying stdin to LLDB and LLDB will route that information as needed to the correct interpreter.

HandleCommand always goes to the command interpreter, no matter what input reader is being used.

Greg Clayton

Two questions:

1. If the default is to have an input reader for the command interpreter, can I just call DispatchInput to run a command? That doesn't seem to work for me.
2. If 'run' pushes a new InputReader, how should my python code be notified of that? There is no event on the debugger's default listener.

Ben

Hi Ben,

Two questions:

1. If the default is to have an input reader for the command interpreter, can I just call DispatchInput to run a command? That doesn't seem to work for me.

I find it weird that it doesn't, but while taking a look at the
SublimeLLDB plugin*, I see that I actually used the SBDebugger's
input/output file handles. Maybe I found this same problem (I did the
plugin about a year ago).

* The code quality is not that good, but if you find it handy, be my
guest and check out how I used LLDB.framework. I'm also not sure if
the code has bitrotted or not.

2. If 'run' pushes a new InputReader, how should my python code be notified of that? There is no event on the debugger's default listener.

Ah, yes. You would expect, but there's no API for that. There is one
to check if a given InputReader is the top one, which may help you,
though. Otherwise, a patch would be needed for InputReader-related
events.

Regards,

  Filipe