Hi Jason, Thanks a lot for your elaborate answer!
Cheers, Björn 29 okt 2010 kl. 23.23 skrev Jason Molenda: > Hi Björn, > > Partially it was due to the restrictions of following the libunwind API, > partially due to our implementation of libunwind (modified to implement the > libunwind-remote API), and partially due to the fact that we paid real costs > by having libunwind and lldb not share information or trust each other. > There were fundamental performance issues with the way the libunwind API > works. > > The libunwind-remote implementation was an excellent test bed to try creating > an adaptive backtracer which can switch between eh_frame CFI, assembly > language prologue inspection, and architectural defaults. But by the time we > had a functioning unwinder, looking at the compromises imposed by the API and > the changes needed to the implementation, there wasn't any clear benefit to > sticking with that source base. Originally we had a few groups inside Apple > who wanted to have a libunwind-remote API for their program but by the time > it was finished, they were all moving their interest to using lldb to provide > this service. > > The libunwind-remote API was designed to only follow eh_frame information and > to have the library built separately for each architecture supported. We > wanted to have multiple unwind schemes in play and we wanted to have a single > library for all of them. Already the libunwind-remote API has half a dozen or > so API extensions, including the instruction_length() callback which > necessitates the driver program include a disassembler on > variable-length-instruction architectures (read: x86). The > EnhancedDisassembly library from llvm is a great source for this but it's > still a rather large burden for users of the library. Another simple example > of an API problem, the libunwind-remote API makes no allowance for a > debugger's inferior function calls where the register contents are stored in > the debugger's memory space instead of the inferior program's memory space. > > libunwind and lldb don't share any of their knowledge between themselves - so > for instance both may read and parse an eh_frame table from an executable. > For assembly language inspection it's critical that we know the start address > of a function. The libunwind-remote includes the find_proc_info() call which > it could use but on a stripped program (which may only have one visible > linker symbol), the program that implements find_proc_info() naively will say > "Oh yes, this is 2 megabytes into this symbol I saw, it's all one function". > If eh_frame information is in the binary, a smarter approach is to grab the > function start/end addresses from eh_frame - but a typical program using > libunwind-remote isn't going to do that. So libunwind-remote tries to find > the information on its own, if possible - it doesn't trust the driver program. > > (You might ask why we're not just using the eh_frame -- a rule of thumb we've > come up with is to not trust eh_frame information if it's on the currently > executing frame; it is only guaranteed to be valid at call sites and where an > exception can be thrown. The compiler emits some information so that it > *tends* to be valid at other locations as well but we've seen cases where it > isn't and it confuses the debugger.) > > The final issue was performance. The libunwind API assumes that you unwind > every frame in its entirety - you step the "cursor" - and have full register > context available at that point. On Mac OS X it is typical to see > applications with a dozen threads and when execution stops in a GUI debugger, > the first thing it does is backtrace all the threads so it can show function > names. The speed of this backtrace is critical. The native unwinder allows > us to do a "fast backtrace" if it can; the fast backtrace only knows how to > restore a couple of registers (rip, rbp on x86-64) - if we need to retrieve > additional registers, it knows how to do a "full" unwind which may involve > reading the eh_frame information for that ObjectFile (which is phenomenally > slow). libunwind-remote reads/parses the eh_frame for every shared library > mentioned in a stack on startup so the first unwind is very slow. I spent a > good amount of time trying to optimize things but it was hard to do with that > design. > > As an aside, there were some issues with libunwind-remote that were solvable > but would have been a good amount of work to do. For instance, writing a > register value in the middle of the stack requires that libunwind-remote > track not just register values, but where those registers were retrieved > from. (in memory? In the same register or a different one? In the > debugger's address space in the case of an inferior function call?) There > was also the problem that libunwind was designed with an assert style of > error handling because following the eh_frame chain for an exception throw is > reliable and safe... unwinding a stack during a debug session is neither > reliable nor safe. I pulled out most of the asserts but some remain and they > take down lldb every time it goes wrong on an unwind. > > > The native unwinder is coming along - I'm still working on a few bugs but I > expect we'll switch over to using it as the default unwinder very soon. I > like the approach of having UnwindPlans contributed from different sources > (eh_frame information, DWARF CFI, assembly language prologue inspection, > architectural defaults, etc) that all feed into the unwinder. I'd like to > see multiple UnwindPlans for attempting to unwind from frame 0 when we have > no known start address. The "follow the rbp chain" technique often works but > it'd be cool if we could see that this method gives us an invalid saved-rip > and try a fallback UnwindPlan, maybe one that assumes the saved rip can be > found via rsp and assume the stack hasn't been modified so far during the > lifetime of the function. > > > In the end we could have accomplished many of these things while continuing > to use libunwind but it was clear we were imposing an unnecessary set of > restrictions on ourselves and building the unwinder into lldb as an integral > subsystem was going to be a lot easier to enhanced/maintaing long term. > > > J > > On Oct 29, 2010, at 1:43 AM, Björn Töpel wrote: > >> Hi, >> >> What's the rationale for creating/using a native LLDB unwinder, instead of >> the Apple libunwind based unwinder? >> >> It's my understanding that the libunwind unwinder is still enabled in LLDB. >> >> >> >> Atb, >> Björn >> _______________________________________________ >> lldb-dev mailing list >> [email protected] >> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev > _______________________________________________ lldb-dev mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev
