I updated my code and removed the call to AddListener and as I can tell nothing changed. It is still behaving "strange". It also didn't work with the python example. I couldn't step over the next instruction, so I am getting similar behavior like the c++ code.
The strange thing is that at the first try it worked (c++ code): * thread #1: tid = 4502, 0x0000000000400953 main`main + 35 at main.cpp:7, name = 'main', stop reason = breakpoint 1.1 frame #0: 0x0000000000400953 main`main + 35 at main.cpp:7 4 5 int main() { 6 -> 7 std::cout << "Hello World" << std::endl; 8 9 int i = 0; 10 std::cin >> i; 0x7f022c000930 Event: broadcaster = 0x56348a831fa8 (lldb.process), type = 0x00000001 (state-changed), data = { process = 0x56348a831f70 (pid = 4502), state = stopped} ---------- * thread #1: tid = 4502, 0x0000000000400953 main`main + 35 at main.cpp:7, name = 'main', stop reason = breakpoint 1.1 frame #0: 0x0000000000400953 main`main + 35 at main.cpp:7 4 5 int main() { 6 -> 7 std::cout << "Hello World" << std::endl; 8 9 int i = 0; 10 std::cin >> i; 0x7f022c003db0 Event: broadcaster = 0x56348a831fa8 (lldb.process), type = 0x00000001 (state-changed), data = { process = 0x56348a831f70 (pid = 4502), state = stopped} Stopped at breakpoint ---------- Hello World ---------- * thread #1: tid = 4502, 0x0000000000400978 main`main + 72 at main.cpp:9, name = 'main', stop reason = step over frame #0: 0x0000000000400978 main`main + 72 at main.cpp:9 6 7 std::cout << "Hello World" << std::endl; 8 -> 9 int i = 0; 10 std::cin >> i; 11 12 if (i == 1) { 0x7f022c001680 Event: broadcaster = 0x56348a831fa8 (lldb.process), type = 0x00000001 (state-changed), data = { process = 0x56348a831f70 (pid = 4502), state = stopped} Stopped at step ---------- But every try afterwards didn't work: * thread #1: tid = 5122, 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 0x7f8f98000930 Event: broadcaster = 0x5568372e7fa8 (lldb.process), type = 0x00000001 (state-changed), data = { process = 0x5568372e7f70 (pid = 5122), state = stopped} ---------- * thread #1: tid = 5122, 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 0x7f8f98001640 Event: broadcaster = 0x5568372e7fa8 (lldb.process), type = 0x00000001 (state-changed), data = { process = 0x5568372e7f70 (pid = 5122), state = stopped} Stopped at breakpoint ---------- Hello World ---------- To be honest, I am not sure if this is a bug in linux or lldb? I will try to compile lldb/llvm/clang from upstream. Do you have any idea what might cause this? 2016-02-25 1:05 GMT+01:00 Greg Clayton <gclay...@apple.com>: > 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