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 <[email protected]>:
> 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 <[email protected]> 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 <[email protected]>:
>>> 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, [email protected] 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 <[email protected]> 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
>>>>>> <[email protected]> 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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev