This is a very useful read! I am also building a IDE debugger using lldb, and I found the initial attach/launch API and eventing system has a lot quirks. After getting to stopped state, querying info is relative trivial. Thanks again.
Sent from my iPad > On Feb 23, 2016, at 2:40 PM, Greg Clayton via lldb-dev > <lldb-dev@lists.llvm.org> wrote: > > I need to spend some time writing this up, but until then here is some info. > > We created a python script that uses the LLDB public API to grab async events > so people can see how to do things: > > svn cat > http://llvm.org/svn/llvm-project/lldb/trunk/examples/python/process_events.py > > If you look in here you will see the correct way to do things. > > I will answer you questions inlined into your email below and then add some > extra tips at the end: > >> On Feb 20, 2016, at 3:04 PM, Paul Peet via lldb-dev >> <lldb-dev@lists.llvm.org> wrote: >> >> Hello, >> >> I am currently working on an IDE for C++ and I would like to integrate lldb >> as a debugger using the C++ API but it has been difficult for me to >> understand the architecture because there is no documentation available >> (except doxygen which isn't helpful at all). >> I am at the point understanding the Event system? How are Events created? > > You need to be able to listen for events from your debug session. In order to > do this, SBBroadcaster objects can broadcast events as SBEvent objects. You > need to listen for events using a SBListener. Each SBBroadcaster will > broadcast events where each different kind of event is represented by one bit > in a 32 bit uint32_t. > >> How can I use SBListener and SBBroadcaster? (What's the function of >> SBBroadvaster). > > Yes you can. You might want to use a SBBroadcaster to send events to your > main event loop in the debugger: > > using namespace lldb; > SBBroadcaster gui_event_broadcaster("gui-events"); > > // Define the event bits we will use for gui_event_broadcaster > enum > { > eGUIEventBitLaunch = (1u << 0), > eGUIEventBitKill = (1u << 1), > eGUIEventBitStepOver = (1u << 2), > eGUIEventBitStepOut = (1u << 3), > eGUIEventBitStepInto = (1u << 4), > eGUIEventBitContinue = (1u << 5), > eGUIEventBitHalt = (1u << 6), > eGUIEventBitQuit = (1u << 7), > eGUIEventAll = UINT32_MAX > }; > > SBListener run_loop_listener("run-loop-listener"); > // Listen for any event from gui_event_broadcaster by listening to all event > bits > run_loop_listener.StartListeningForEvents(gui_event_broadcaster, > eGUIEventAll); > > You can then run an event loop on a thread: > > void > RunLoop() > { > SBEvent event; > bool done = false > while (!done) > { > if (listener.WaitForEvent(UINT32_MAX, event)) > { > const uint32_t event_type = event.GetType(); > if (event.BroadcasterMatchesRef(gui_event_broadcaster)) > { > switch (event_type) > { > case eGUIEventBitLaunch: > case eGUIEventBitKill: > case eGUIEventBitQuit: > } > } > } > } > } > > > Then on another thread, you can broadcast events. Lets say the user clicked > the "kill" button in your IDE, you could broadcast an event: > > gui_event_broadcaster.BroadcastEventByType(eGUIEventBitKill); > > Then the event loop would receive the event, as long as it is listening for > these events. So you can use SBBroadcaster and SBListener yourself, but many > objects (like SBTarget, SBProcess and SBThread) are already broadcasters and > will broadcast events to you and you can sign up to listen to the events they > send out. I would recommend starting with SBProcess, and you will see how to > listen to events by looking at the python code. > > >> >> My current code looks something like this: >> >> SBListener listener; >> SBProcess process = target.Launch(listener, args, env, nullptr, nullptr, >> nullptr, "/home/cynecx/dev/helloWorld", >> 0, true, error); >> >> process.Continue(); >> >> StateType state = process.GetState(); // is stopped >> >> SBEvent event; >> >> while(true) { >> if(listener.WaitForEvent(0xFFFFFFFF, event)) { >> // This branch is never hit >> SBStream stream; >> event.GetDescription(stream); >> std::cout << stream.GetData() << std::endl; >> } else { >> break; >> } >> } >> >> It would help developers (IDE) a lot if there might be some >> tutorials/documentation on how to use the API. > > I agree. We will try to get this up on the web at some point in the near > future. > > Some more pointers: > > - When launching, use a SBLaunchInfo: > > const char *argv[] = { "/bin/ls", "-l", "-A", "-F", nullptr }; > SBLaunchInfo launch_info(argv); > launch_info.SetWorkingDirectory("/tmp"); > SBError error; > SBProcess process = target.Launch (launch_info, error); > > This will allow you to fill in a SBLaunchInfo from your IDE and possibly keep > it around for re-use on next launch. > > - When attaching, use a SBAttachInfo. Same reason as launch info. > > pid_t pid = 123; > SBAttachInfo attach_info(pid) > > or > > const bool wait_for = true; > SBAttachInfo attach_info("my_program", wait_for); > > Then do: > > SBProcess process = target.Attach (attach_info, error); > > - I would recommend having one thread that is the main LLDB event loop and > have this event loop also do process control. You can usually use the > SBDebugger's listener as it will be hooked up by default to the process if > you don't specify a listener: > > SBListener listener = debugger.GetListener(); > SBEvent event; > const uint32_t infinite_timeout = UINT32_MAX; > StateType process_state = eStateInvalid; > while (!done) > { > if (listener.WaitForEvent(infinite_timeout, event)) > { > if (SBProcess::EventIsProcessEvent (event)) > { > process_state = SBProcess::GetStateFromEvent (event); > switch (process_state) > { > case eStateStopped: > case eStateRunning: > case eStateExited: > case eStateDetached: > .... > } > } > else if (event.BroadcasterMatchesRef(gui_event_broadcaster)) > { > switch (event_type) > { > case eGUIEventBitLaunch: > case eGUIEventBitKill: > case eGUIEventBitStepOver: > case eGUIEventBitStepOut: > case eGUIEventBitStepInto: > case eGUIEventBitContinue: > case eGUIEventBitHalt: > case eGUIEventBitQuit: > } > } > } > } > > Why do all process control on one thread? Because you don't want one thread > telling the process to run and another telling the process to stop. So the > easiest way to do this ensure only one thread actually controls the process. > Since the event loop the place that will know if the process is stopped, it > is the perfect place to also do the process control. > > What we did in Xcode was we keep a stack of process control requests. So lets > say we are currently stopped and the user presses the step over button 3 > times really quickly. We might receive 10 eGUIEventBitStepOver events, and > make a dequeue of process control requests: > > eGUIEventBitStepOver > eGUIEventBitStepOver > eGUIEventBitStepOver > > Now in the event handler for eGUIEventBitStepOver in your event loop you can > do: > > switch (event_type) > { > case eGUIEventBitStepOver: > if (process_state == eStateStopped) > process.GetSelectedThread().StepOver(); > else > process_control_dequeue.push_back(eGUIEventBitStepOver); > break; > } > > So this means, if nothing else is going on, then you can issue the step over > right away, else you need to wait until the process is stopped. Then when > responding to the process stopped event: > > > process_state = SBProcess::GetStateFromEvent (event); > switch (process_state) > { > case eStateStopped: > if (SBProcess::GetRestartedFromEvent(event) == false) > { > UpdateGUI(); // Update your IDE so we see where we just stopped > if (!process_control_dequeue.empty()) > { > // pop the next process control event off of the > process_control_dequeue > // and make the process resume/step/stop/continue > } > } > break; > > In Xcode we also did something a bit fancy: if the user ever presses the halt > or kill button, we clear the process_control_dequeue. Why? Because most often > someone is stepping faster than the debugger can keep up with and as the GUI > is updating and showing them where their program is going, they say "yikes! > Stop the program now". So any halt, kill or detach will clear any > steps/continues that might have been saved up... > > Hope this helps. For now, just keep asking questions on this list and we will > help you out as much as possible. > > Greg Clayton > > _______________________________________________ > 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