Debugging In Xcode With LLDB

A Dataful Adventure

Christopher Webb
Journey Of One Thousand Apps
6 min readMay 31, 2017

--

Mistakes Were Made

Sometimes we make assumptions about things that aren’t true. That statement may seem obvious, and it is, it’s human nature. When writing software, it’s always good to question whether your assumptions are accurate. Many times you’ll find that on closer examination, things aren’t exactly as they first appeared.

🤔 Challenge Your Assumptions

When using Xcode, one of the ways we can question our assumptions is by using the debugger. A debugger is a tool that allows you inspect and manipulate your code execution with fine-grained control. Through debugging, you can gain a greater understanding of what your code is doing.

This post aims to give a brief overview of debugging in Xcode as well some of the tools that are available to help you. I intend to write a series of posts on the topic of debugging, and this is the first one. The subject of debugging is vast, and this post does not aim to provide a full overview. If there is something that you feel missing stay tuned for more posts in this series. Also, feel free to leave me a comment.

Crash Land Journeys

This might sound a bit strange, but for a second think of your code crashing as a journey. It starts off when you hit run, and it compiles. Along the way, it goes on methods and meets many properties. Ultimately, it succeeds in finding crash land. When you start debugging you only have a small piece of the picture. You have the beginning and destination but to know how you got there you need to retrace the steps of the journey. To help you along your trip, Apple has bestowed upon you a valuable item, the LLDB debugger.

The Console and LLDB

LLDB is a software debugger that Apple provides as the standard debugging tool in Xcode. LLDB is a powerful tool for breaking down applications into their components pieces. Its uses aren’t limited to the Xcode IDE, you can use LLDB to break down and examine applications even if you do not have access to their source code. Given the breadth of capabilities and variety uses, this post is meant more like a cursory overview, and I don’t want to get too out of scope by exploring these in detail — yet.

Call Stack

With LLDB we are able to inspect the call stacks as well as specific stack frames within the stacks. A call stack is a data structure that is created by your application to keep track of all its behavior.

The Data Structure

A stack data structure is simply a queue in which the last element added is the first element returned out of it (LIFO queue — Last In First Out.) This is much the same as in the physical world in that you would take a brick from the top of a stack of bricks (if you took from the bottom — i.e. the first brick added — it would all come crashing down.)

Stack Frames

Within call stacks are structures called stack frames. Stack frames contain information regarding the execution for which it was created. A lot of this information can become useful when you are debugging. The data ranges from the local variables to the memory address where it returns to upon completion.

Apple docs:

While a program is running, it stores information about what it’s doing in a data structure known as a call stack. Each time a method is called, the program pushes a new stack frame on top of the call stack, which contains the following: the arguments passed to the method, if any, the local variables of the method, if any, and the address to return to after the method call finishes.

Breakpoints

If you aren’t familiar with code breakpoints, allow me to give you a brief an incomplete introduction. In Xcode, breakpoints allow you interrupt the execution of your code at a particular point. This is useful in that it lets you examine the state of the application at a given moment in great detail.

Breakpoint Types

Symbolication Detour

Before we go further into breakpoints, let’s go over symbolication. Symbolication is the mapping memory addresses to more simple function names.

Back To Our Previously Scheduled Programming

When dealing with breakpoints, it’s important to understand that there is more than one type. Let’s briefly touch on some important types:

Xcode Line Breaks— The basic type of breakpoints and the easiest to use are the type that you can add in the side of the Xcode editor. This breakpoint will interrupt your code when that line is executed. This is perfect for situations where you have a pretty good idea of where things are going wrong.

Exception — Exception breakpoints are also commonly used type. Exception breakpoints interrupt your code when Xcode throws an exception rather than the error. If you’re not sure where things are going wrong, this is a great tool to see what happened immediately before crashing.

Conditional — Another way to use breakpoint is set conditions at which the application will interrupt its execution. This could be something as simple as a nil check for a property. This can be very helpful when you aren’t sure where a given value is coming from in your code.

Symbolic — Finally, there are symbolic breakpoints. These are slightly more tricky. A symbolic breakpoint is sort of like a predicate for filtering when to interrupt your code based on functionality. For instance, you can have a symbolic breakpoint for when an object is instantiated.

While there are multiple ways to go about implementing them, at their core, breakpoints are a simple concept. Apple has a pretty good definition for breakpoints:

A breakpoint is a mechanism to pause an app during execution at a predetermined location in order to inspect the state of variables and the app’s control flow. There are several different kinds of breakpoints, and they can be edited to add conditions, actions, and scripts. Although you can use the debugger to pause an app at any time, it’s helpful to set breakpoints before and even while your app is running so that you can pause it at known points where you have determined problems might be occuring.

Stepping Stones

One final aspect of debugging that I want to touch on in the post is what you can do to explore your code after you hit a breakpoint. You could say that there are a few steps you can take.

Stepping Over — When you ‘step over’ Xcode will run the current statement and stop at the next statement. If the statement is a function, it will execute in its entirety before stopping.

Stepping Into — When you step into Xcode will execute the current statement, however if that is a function Xcode will step into the execution of that function and then pause.

Wrap-Up

This is not my final word on the topic. There is so much more we can explore in this, I wouldn’t even call this post a complete introduction. This post is an introduction to the introduction. As I touched on earlier, LLDB allows us to explore worlds that would otherwise remain hidden and take apart code that we do not have access to. That’s where the fun starts!

--

--