I am trying to do something small, but the documents suggest that this be possible. LLDB may still be too new, but I get a lot of crashes / deadlocks on the debugger, and even when that doesn't happen, it seems like it doesn't work as I expected.
I am trying to build a debugging shell around all selector calls in order to extract a message call graph inside a specific piece of code. (I could explain why if you really want to know, but this is not particularly relevant to the debugger problem.)
I start with the Xcode breakpoint at the line where I want to start tracking things (for bonus points, this happens in the secondary stream, but before you ask, no, nothing in any other stream makes any calls to this object or anything in its subgraph of properties):
[myObject startProcessing]
The breakpoint trigger, and I run "bt", just to retrieve:
* thread
Then I do something a little evil: I put a breakpoint in objc_msgSend, right in the statement, where it calls the real object selector. objc_msgSend looks like this:
libobjc.A.dylib`objc_msgSend: ...(instructions)... 0x37babfa4: bx r12 ...(more instructions)...
(Actually, there are two calls to bx, but let everything be simplified). I run:
breakpoint set -a 0x37babfa4 -t 0x2203
(TID is enabled because I have enough trouble tracking this single thread, and I donβt need useless things to interfere.)
Here where the script comes. The setup described above works exactly as I would like. If I resume execution before the breakpoint is triggered, I can run:
frame select 0 thread step-inst -m this-thread 5 frame info continue
and the effect will be that the debugger:
- moves to frame objc_msgSend
- according to one instruction, moving it into the frame of the object selector, indicating
- displays relevant data (object type, selector)
- resumes execution
at this point, I can continue to paste these four commands over and over and copy the output until I hate myself.
If, on the other hand, I run:
breakpoint command add -s command
and insert the same commands, everything breaks. It does not advance to the object selection frame. It does not show frame details or, at least, not correct ones - depending on various settings (see below), it may or may not show "objc_msgSend" as the current function. It does not resume execution.
In this case, if I could get this example to work, I would be mostly happy. But for even more bonuses, I also tried this with python, which I would prefer, because it would allow much more complex logging:
breakpoint command add -s python > thread = frame.GetThread() > thread.StepInstruction(1) > newFrame = thread.GetFrameAtIndex(0) > print " " * thread.GetNumFrames() + newFrame.GetFunctionName() > process = thread.GetProcess() > process.Continue() > DONE
Nothing good again. Again, depending on the tiny details, it may or may not print something (usually objc_msgSend), but it never prints the right thing. He never executes a command ahead. It never resumes execution afterwards.
And again, the python version works fine if I do it manually: if I wait until a breakpoint is reached, run the "script" and enter the same lines, it works as expected. Some parts will work independently of each other, for example. if I delete everything except the parts that receive the process and invoke the process. Continue () and start them automatically, which βworksβ (which means that the lldb request is blinking fast because it pauses and resumes execution. I usually regret it because it becomes unresponsive and crashes.)
So: Any ideas? Is the technology Not Ready Yet, or have I just missed some clever part of the puzzle that will fix everything? Or should I completely refuse and just live with the fact that there are some parts of objects that I will never understand? ...