So I would suggest not using "ci.HandleCommand()" if you can. There are better 
API calls for this that will return your the objects that you need. In the code 
below I have modified each HandleCommand and replaced it with the function you 
want to use...

> On Jul 18, 2014, at 4:10 AM, snare <[email protected]> wrote:
> 
> Hi,
> 
> I have a question about listeners and async mode. I'm building a debugger UI 
> on top of LLDB in Python, and basically what I want to do is instantiate an 
> SBDebugger, get its SBCommandInterpreter, loop on readline and feed the 
> commands to the command interpreter pretty much the same way that the regular 
> LLDB driver does. I’ve had a look at the driver code, but there’s quite a bit 
> I don’t understand about how the back end works. There is other stuff going 
> on in my tool that I won't go into that necessitates running it this way, 
> rather than as a script loaded into the regular LLDB driver (which is 
> actually how the existing version works).
> 
> From what I understand, the way to do this is to use async mode. I've had a 
> look at the process_events.py example, which makes sense, but I'm not sure 
> how to proceed with regard to listeners when letting SBCommandInterpreter do 
> the heavy lifting rather than calling Launch* with the API.
> 
> I was hoping to be able to do something like this:
> 
>    import lldb
>    import time
> 
>    debugger = lldb.SBDebugger.Create()
>    debugger.SetAsync(True)
>    ci = debugger.GetCommandInterpreter()
>    res = lldb.SBCommandReturnObject()
> 
>    # "inferior" is a test program that when called with "loop" as the first 
> param just does `while(1);`
>    print("starting inferior")
>    ci.HandleCommand("file tests/inferior", res)

filename = "tests/inferior"
triple = None
platform_name = None
add_dependent_modules = False
err = lldb.SBError()

target = debugger.CreateTarget (filename, triple, platform_name, 
add_dependent_modules, err);

if target:
    # Continue one with running
else:
    print err

>    ci.HandleCommand("run loop", res)


if target:
    # Continue one with running
    launch_info = lldb.SBLaunchInfo(["loop"])

    process = target.Launch (launch_info, err)
    if process:

    else:
        print err
else:
    print err

> 
>    # let the target run a bit and then get its status
>    print("sleeping 1 second")
>    time.sleep(1)

You don't need the sleep now, just start waiting for events and respond to them 
like the code in process_events.py


>    state = 
> debugger.StateAsCString(debugger.GetTargetAtIndex(0).process.GetState())
>    print("state (should be running): {}".format(state))

The above code should be one in your event loop when you receive an process 
state change event. You will do something when you get a running event and 
something else when you get a stopped event.

> 
> The state is always "stopped". After looking at `process_events.py` I figured 
> I need to set up a listener and consume the events, so I tried something like 
> this, with a listener running in a background thread (and a more realistic 
> example with accepting user commands rather than the contrived example above):
> 
>    import lldb
>    import os
>    import threading
> 
>    debugger = lldb.SBDebugger.Create()
>    debugger.SetAsync(True)
>    ci = debugger.GetCommandInterpreter()
> 
>    done = threading.Event()
> 
>    def run_listener():
>        event = lldb.SBEvent()
>        listener = debugger.GetListener()
>        while not done.is_set():
>            if listener.WaitForEvent(1, event):
>                print("Got a new LLDB event: {}".format(event))
>            else:
>                # print("Timed out waiting for LLDB event, trying again")
>                pass
> 
>    t = threading.Thread(target=run_listener)
>    t.start()
> 
>    try:
>        while True:
>            line = raw_input("> ")
>            res = lldb.SBCommandReturnObject()
>            ci.HandleCommand(line, res)
>            if res.Succeeded():
>                print(res.GetOutput().strip())
>            else:
>                print(res.GetError().strip())
>    except:
>        done.set()
>        t.join()
> 
> But running the listener like that causes HandleCommand() to block.

Why is it blocking? You should look at a sample or interrupt with a debugger 
and see why.

> I'm assuming my listener consuming the events means that the debugger never 
> receives them.

No, the debugger has a listener which is given many events and you consume 
these events.

> I do not really require handling the events from my code, I'm happy for the 
> debugger to handle that if it can do so and allow me to still perform other 
> operations asynchronously like inspecting the state/read memory/etc.

You should probably let the debugger handle everything including the command 
interpreter. Just call:

auto_handle_events = True
spawn_thread = False

debugger.RunCommandInterpreter (auto_handle_events, spawn_thread)

This will run everything for you just like the command line LLDB. If 
spawn_thread is false, then it will block until the command interpreter is 
exited, else if spawn_thread is true, the command interpreter will be run on 
another thread and it will return allowing you to do other things.

There currently isn't an option to just say "handle the events for me". The 
built in one exposed in SBDebugger::RunCommandInterpreter(...) will always 
print messages out to the stdout/stderr that you gave to the debugger:

    void
    SBDebugger::SetInputFileHandle (FILE *f, bool transfer_ownership);

    void
    SBDebugger::SetOutputFileHandle (FILE *f, bool transfer_ownership);

    void
    SBDebugger::SetErrorFileHandle (FILE *f, bool transfer_ownership);


So if you don't want it to do that and provide the feedback just like the 
command line tool, then you should be running your own event loop.

Greg
_______________________________________________
lldb-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev

Reply via email to