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

Reply via email to