C++ API question

Hello,

Now that my build problems are fixed I have started to do a little more than extracting symbols from OSX applications and I have a strange situation.
I create a target, add a symbolic breakpoint on ‘main’, launch the process and then inspect the threads + their stack frames. What troubles me is that I correctly find 1 thread but it always says there is 0 frames, meanwhile calling the method lldb::SBThread::GetStatus(…) and displaying its results correctly shows me what I’m expecting (a stack frame with the breakpoint on my main function). I have tried to step in lldb code and from what I understand GetNumFrames & all return 0 because it says the process is still running as it is unable to get some lock/mutex.

When I enable logs for API here is what I get:

1369872253.995728 SBProcess(0x1250bec00)::GetNumThreads () => 1
1369872253.995767 SBProcess(0x1250bec00)::Stop () => SBError (0x105602010): success
1369872253.995790 SBProcess(0x1250bec00)::GetThreadAtIndex (index=0) => SBThread(0x110b313d0)
1369872253.995807 SBThread(0x110b313d0)::GetNumFrames() => error: process is running
1369872253.995816 SBThread(0x110b313d0)::GetNumFrames () => 0
1369872253.995826 SBThread(0x110b313d0)::GetStopReason() => error: process is running
1369872253.995833 SBThread(0x110b313d0)::GetStopReason () => invalid
1369872253.999252 SBThread(0x110b313d0)::GetName() => error: process is running
1369872253.999277 SBThread(0x110b313d0)::GetName () => NULL

I am clearly missing something here but what?

S.

Are you pulling events from the process you've launched? Various reactions to Process level events get triggered by the event getting pulled from the event queue. One of these is updating the "public" state of the process in lldb to the state of the event you've just handled.

So if you just leave events on the event queue, then the "public" state of the process won't get updated and you will see the sort of behavior you are describing. Instead, you should structure your process handling in a little event loop that reads events from the process and then reacts to each change of state recorded in that event. Then everything will be sync'ed up when you go to handle the event.

Jim

Are you in synchronous mode?
If not, or if you are not sure what the question even means, you most probably are not.
The way LLDB works is an event system. You tell your process to run and that spawns a series of events. Events that you have to consume.
You tell your process to stop, and when it stops, you get an event that tells you so.
Anything until then, process is NOT stopped, and that’s why you get errors saying “process is running”, because you have yet to see the stop event and consume it.
If you want an example of how to setup an automated interaction with LLDB, part of your checkout should be an LLDBPerf project
Look around in TestCase.cpp there (http://llvm.org/svn/llvm-project/lldb/trunk/tools/lldb-perf/lib/TestCase.cpp) - the Loop() method implements a state machine that correctly consumes the events - that might be a good starting point.
To keep it really simple if you’re just prototyping, SBDebugger::SetAsync(false) will set LLDB in synchronous mode. In this mode of operation, the API calls consume the events before returning, and relieve you of that duty - I am not sure how complete and reliable the synchronous mode is, since we do not use it.

Are you in synchronous mode?
If not, or if you are not sure what the question even means, you most probably are not.
The way LLDB works is an event system. You tell your process to run and that spawns a series of events. Events that you have to consume.
You tell your process to stop, and when it stops, you get an event that tells you so.
Anything until then, process is NOT stopped, and that's why you get errors saying "process is running", because you have yet to see the stop event and consume it.
If you want an example of how to setup an automated interaction with LLDB, part of your checkout should be an LLDBPerf project
Look around in TestCase.cpp there (http://llvm.org/svn/llvm-project/lldb/trunk/tools/lldb-perf/lib/TestCase.cpp) - the Loop() method implements a state machine that correctly consumes the events - that might be a good starting point.
To keep it really simple if you're just prototyping, SBDebugger::SetAsync(false) will set LLDB in synchronous mode. In this mode of operation, the API calls consume the events before returning, and relieve you of that duty - I am not sure how complete and reliable the synchronous mode is, since we do not use it.

I wouldn't spend any time playing with the synchronous mode, since the process has other interesting events (in particular I/O when you are debugging remotely) that you will want to receive, and you'll need to be consuming events to get that.

Jim

Indeed, I didn't know there was a Sync/Async switch and now it makes sense. I wanted to experiment before writing the full event system. I'll do that now.
Can I handle the event loop from any thread or is there something special I should be aware of concerning the API and threading?

Thanks!

S.

lldb will create its own threads to handle the internal parts of the process handling, so you don't need to worry about colliding with them.

We don't support more than one "Listener" listening to events from a given process. We should be able to make that work in the future, but right now it just confuses us.

One listener can handle events from more than one process, if you want to do it that way, however. If you don't supply a listener when you create a process then all the events go to the Debugger's Listener - which you can get with SBDebugger.GetListener().

Or you can create each process with a dedicated listener, in which case you'll need to have a listening thread on your end for each process.

One other thing to consider is that each SBDebugger has one "console command interpreter". So if you want to make it seem like there is a one to one correspondence between "process" and "command interpreter" then you will need to make a new SBDebugger to handle each process. OTOH, if you want the console interpreter to be shared across multiple processes, you can make one SBDebugger and create multiple targets and processes in it.

Jim