Debugging prebuilt frameworks

Tomas Camin
3 min readJun 1, 2018

--

This is a short resume of how I solved a weird need we had and discovered the hidden powers of lldb’s advanced commands.

When talking about frameworks in iOS/Mac development one usually thinks about a set of source code files that get built in either a static or dynamic library eventually embedding some additional resources. There are a lot of well known tools like CocoaPods and Carthage that do that for you, so nothing new here.

Recently we’ve been facing something that might be seen as the other way around: in our project there was a framework, we had the source files that generated that framework in another location (outside of our project) and we wanted to be able to step-into the framework classes using the debugger.

Why on earth is that?

To optimize build times of our project we have a particular flow where we build frameworks and commit those in our repo instead of the source files. While this has some drawback that might be worth discussing in another post, we’re really happy with the outcome because we cutted down build times down by more than a third, from about 7 minutes to approximately 2 minutes. Additionally splitting our app in frameworks forced us to to rethink the whole architecture clearly isolating our dependencies, a nice bonus!

The frameworks we build ship with DWARF debug informations that can be parsed and converted to something human readable by using dwarfdump. The tool is really super fun to use and the amount of things that can be extracted is mind-blowing. The DWARF debug informations are structured in sections, one for every compilation unit, and by invoking dwarfdump --debug-info you will get all the informations stored in the .debug_info sections. These contain, among other things, the match between symbols and the precise location in the source code file like shown in the screenshot below.

example output of dwarfdump

Notice that paths to source files are absolute, meaning that the file might even not exists (think of the case where the framework was built on a different machine).

Luckily for us we‘re building frameworks on different machines but always from the same path /tmp/SubitoFrameworksBuilder and thanks to this assumption it’s just a matter of remapping paths. Can this be done? Yes, and it turns out that this is really easy using lldb’s following command:

settings set target.source-map '<path_at_compilation_time>' '<current_source_code_path>'

This is kind of tedious to write at every launch of the debugger, but the good news is that there is a way to automatically execute this every time we launch our app by adding the above line to ~/.lldbinit-Xcode. It would be nice to be able to do this per project and not per user but unfortunately there’s an open radar sitting there for some time.

Each line in ~/.lldbinit-Xcode will be execute by Xcode allowing you to define aliases and custom commands. It’s worth checking out something really powerful that has been published by Facebook.

So to recap: with a single lldb command we’re now able to use the debugger with our prebuilt frameworks, having source code files somewhere around on our filesystem.

😎

--

--