Not sure. First off, you don't need to do: process.GetBroadcaster().AddListener(...)
The debugger's listener is already listening to all the events. If you don't specify a listener during launch the process will use the debugger's listener automatically. If you end up making your own process listener, you would actually tell your listener to listen to a broadcaster: SBListener listener("process-listener"); launch_info.SetListener (listener); SBProcess process = target.Launch(launch_info, error); Everything else looks good. What happens if you try running using the process_events.py python script? You might need to specify the PYTHONPATH environment variable to point to your lldb.so % PYTHONPATH=/path/to/lldb/build/directory python lldb/examples/python/process_events.py --breakpoint main.c:12 -- ./a.out arg1 arg2 Does this work if you replace a.out with the path and args for your program? If it does, I would start porting the code from process_events.py and seeing what works and what doesn't. The process_events.py will call "process.Continue()" after it stops. Feel free to edit and play with this script. > On Feb 24, 2016, at 3:45 PM, Paul Peet <paulpee...@gmail.com> wrote: > > I am still getting "non determinism". > > This is my current code: > > SBListener listener = debugger.GetListener(); > process.GetBroadcaster().AddListener(listener, > SBProcess::eBroadcastBitStateChanged | > SBProcess::eBroadcastBitSTDOUT); > > if(!process.IsValid() || !error.Success()) { > return 1; > } > > error = process.Continue(); > if(!error.Success()) { > return 1; > } > > while(true) { > SBEvent event; > > if(listener.WaitForEvent(6, event)) { > if(!event.IsValid()) { > break; > } > > const uint32_t event_type = event.GetType(); > > if (!SBProcess::EventIsProcessEvent(event)) { > continue; > } > > if(event_type == SBProcess::eBroadcastBitStateChanged) { > const StateType state = SBProcess::GetStateFromEvent(event); > > switch(state) { > default: > continue; > case eStateStopped: { > SBThread thread = process.GetThreadAtIndex(0); > SBStream stream; > > thread.GetStatus(stream); > event.GetDescription(stream); > > std::cout << stream.GetData() << std::endl; > > auto threadStopReason = thread.GetStopReason(); > if(threadStopReason == eStopReasonBreakpoint) { > uint64_t bpId = thread.GetStopReasonDataAtIndex(0); > > if(bpId == static_cast<uint64_t>(bp1.GetID())) { > std::cout << "Stopped at breakpoint" << std::endl; > thread.StepOver(); > } > } else if (threadStopReason == eStopReasonPlanComplete) { > std::cout << "Stopped at step" << std::endl; > } > > break; > } > } > } else if (SBProcess::eBroadcastBitSTDOUT) { > char buffer[1024]; > size_t num_bytes = 0; > do > { > num_bytes = process.GetSTDOUT(buffer, sizeof(buffer)); > if (num_bytes > 0) > printf("%*s", (int)num_bytes, buffer); > } while (num_bytes == sizeof(buffer)); > } > > std::cout << "----------" << std::endl; > } else { > break; > } > } > > It worked at the first try but then I got some strange console output. > It's not stepping over the instruction anymore. Also the rip is > basically the same and it's not displaying proper source information > like it did at the first try. > > Current output: > > * thread #1: tid = 2535, 0x0000000000400830 main`_start, name = 'main' > frame #0: 0x0000000000400830 main`_start > main`_start: > 0x400830 <+0>: xorl %ebp, %ebp > 0x400832 <+2>: movq %rdx, %r9 > 0x400835 <+5>: popq %rsi > 0x400836 <+6>: movq %rsp, %rdx > 0x7ffaac000930 Event: broadcaster = 0xcdefa8 (lldb.process), type = > 0x00000001 (state-changed), data = { process = 0xcdef70 (pid = 2535), > state = stopped} > ---------- > * thread #1: tid = 2535, 0x0000000000400830 main`_start, name = > 'main', stop reason = breakpoint 1.1 > frame #0: 0x0000000000400830 main`_start > main`_start: > 0x400830 <+0>: xorl %ebp, %ebp > 0x400832 <+2>: movq %rdx, %r9 > 0x400835 <+5>: popq %rsi > 0x400836 <+6>: movq %rsp, %rdx > 0x7ffaac001640 Event: broadcaster = 0xcdefa8 (lldb.process), type = > 0x00000001 (state-changed), data = { process = 0xcdef70 (pid = 2535), > state = stopped} > Stopped at breakpoint > ---------- > Hello World > ---------- > > It is basically missing the "Stepped at step" part which means lldb > isn't emitting the PlanCompleteEvent. > > Is it a problem on my system? (Linux?). > > 2016-02-24 19:49 GMT+01:00 Greg Clayton <gclay...@apple.com>: >> Here is the fixed code: >> >> SBListener listener = debugger.GetListener(); >> >> SBLaunchInfo launch_info(args); >> launch_info.SetEnvironmentEntries(env, true); >> launch_info.SetWorkingDirectory("/home/dev/helloWorld"); >> >> SBProcess process = target.Launch(launch_info, error); >> >> process.GetBroadcaster().AddListener(listener, >> SBProcess::eBroadcastBitStateChanged | SBProcess::eBroadcastBitSTDOUT); >> >> while(true) >> { >> SBEvent event; >> >> if(listener.WaitForEvent(6, event)) >> { >> if(!event.IsValid()) >> break; >> >> const uint32_t event_type = event.GetType(); >> >> if (SBProcess::EventIsProcessEvent (event)) >> { >> switch (event_type) >> { >> case SBProcess::eBroadcastBitStateChanged: >> { >> const StateType state = >> SBProcess.GetStateFromEvent(event); >> switch (state) >> { >> case eStateStopped: >> { >> const uint32_t num_threads = >> process.GetNumThreads(); >> SBThread thread = process.GetThreadAtIndex(0); >> SBStream stream; >> thread.GetStatus(stream); >> event.GetDescription(stream); >> std::cout << stream.GetData() << std::endl; >> auto threadStopReason = thread.GetStopReason(); >> if (threadStopReason == eStopReasonBreakpoint) >> { >> uint64_t bpId = >> thread.GetStopReasonDataAtIndex(0); >> >> if(bpId == static_cast<uint64_t>(bp1.GetID())) >> { >> std::cout << "Stopped at breakpoint" << >> std::endl; >> thread.StepOver(); >> } >> } >> else if (threadStopReason == >> eStopReasonPlanComplete) >> { >> std::cout << "Stopped at step" << std::endl; >> } >> } >> break; >> } >> } >> break; >> case SBProcess::eBroadcastBitSTDOUT: >> { >> char buffer[1024]; >> size_t num_bytes = 0; >> do >> { >> num_bytes = process.GetSTDOUT(buffer, sizeof(buffer)); >> // Print exactly num_bytes bytes of the string data >> in buffer >> if (num_bytes > 0) >> printf("%*s", (int)num_bytes, buffer); >> } while (num_bytes == sizeof(buffer); >> } >> break; >> } >> } >> } >> >> Your main issue was you were grabbing threads even when you weren't stopped, >> possibly when you were getting process STDOUT... >> >> The main differences in the code above are: >> 1 - use SBLaunchInfo to launch >> 1 - Only try to grab stuff from the process and threads when you are stopped >> (only do process.GetThreadAtIndex(...) when you are stopped, not for every >> event. What would process return if the process is running for >> process.GetThreadAtIndex(0)? Sometimes an invalid thread, sometimes a valid >> thread that might be in the middle of a step. When you are stopped, you are >> guaranteed to get good results. So make sure you are stopped before you ask >> for threads, frames, variables, etc... >> 2 - Make sure the event is a process event with >> SBProcess::EventIsProcessEvent() as you might get other events if you use >> the debugger's listener (target events, thread events, etc) >> 3 - Switch off of the event type so you know what kind of event you are >> getting. >> >> Let me know if this fixes things. >> >> Greg Clayton >> >> >>> On Feb 23, 2016, at 7:10 PM, paulpee...@gmail.com wrote: >>> >>> >>> Thank you very much for that detailed description on explaining the >>> 'basics'. >>> >>> I got it working so far but there is a small issue with the code I am >>> currently running. When the main loop (there is only one) receives a >>> breakpoint event and I am trying to get the thread description (After the >>> breakpoint I issue the thread.StepOver command to the next line of code), >>> the result is not 'deterministic' in terms of it is always showing me >>> different current instruction location. Sometimes it's still on the same >>> breakpoint line and sometimes it's on the proper next line. How is it that >>> the thread is still changing even if the stopped state event got hit? >>> >>> The code: >>> http://pastebin.com/0arNea9m >>> >>> Sorry about pastebin, I am sending this from my phone and apparently it >>> discards the code style while copy and paste. >>> >>>> On 23 Feb 2016, at 23:40, Greg Clayton <gclay...@apple.com> 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