Skip to content

Instantly share code, notes, and snippets.

@alanzeino
Last active September 6, 2025 01:41
Show Gist options
  • Save alanzeino/82713016fd6229ea43a8 to your computer and use it in GitHub Desktop.
Save alanzeino/82713016fd6229ea43a8 to your computer and use it in GitHub Desktop.
LLDB debugging with examples

LLDB Debugging Cheat Sheet

Commands

LLDB Commands

LLDB comes with a great set of commands for powerful debugging.

help

Your starting point for anything. Type help to get a list of all commands, plus any user installed ones. Type 'help <command-name> for more information on a command. Type help <command-name> <option> to get help for a specific option in a command too.

apropos

This is how you search in lldb for a command, or an option. apropos <search-term> should help you find what you're looking for.

breakpoint

Setting breakpoints in lldb is easy.

  • breakpoint set -l <line-number>; sets a breakpoint on a line in the current context.
  • breakpoint set --file <file-name> -l <line-number>; sets a breakpoint on a line on a given file.
  • breakpoint set --name <method-name>; sets a breakpoint on a given function name, globally. e.g., breakpoint set --name viewDidLoad or breakpoint set --name "-[UIView setFrame:]".
  • breakpoint set --selector <selector-name>; sets a breakpoint on a selector, globally. e.g., breakpoint set --selector dealloc.

expression

Expression can help you evaluate code! Helpful when you need to change some stuff, but can't recompile for some reason.

  • expr <return-type><expression>; e.g., expr (UIViewController *)[((UIViewController *)0x7f9492b70570).navigationController popViewControllerAnimated:YES]

By default, running an expression ignores breakpoints. You can force it to stop on any relevant breakpoints with --ignore-breakpoints.

  • expr --ignore-breakpoints false -- <expression>; e.g., expression --ignore-breakpoints false -- [self methodName]

You can even create new code and evaluate it inline.

  • expr for (int i = 0; i < 5; i++) { (void)NSLog(@"Meow"); }

Setting a global variable can help you keep around a reference to a given object, as long as it isn't deallocated from memory.

  • expr <type-name> $<variable-name> = <r-value>; e.g., expr UIWindow* $variable_name = 0x10d72852e.

Then you can use that variable to your hearts content. Omitting $ sets the scope for the variable only locally defined.

  • expr <type-name> <variable-name> = <r-value>; e.g., expr UIWindow* variable_name = 0x10d85832e.

thread

Manipulating the program counter with thread is super awesome.

If you spend all your time clicking step and step and step in xcode to get to a specific line, thread until can help you do this faster. thread until will continue all execution until that line, even if it is well inside several lines of conditional code.

  • thread until <line-number>; e.g., thread until 45

Even better, what if you want to skip the execution of a few lines? You could of course comment the lines out and recompile, but thread jump is faster.

  • thread jump -b <offset>; e.g., thread jump -b 2 will jump to two lines away, skipping those two lines in between.

Combine this with a breakpoint that continues after evaluation and suddenly you've permanently commented out two lines without even recompiling.

What if you want to just stop executing anything in a method you're in?

  • thread return

Need to know where you are in the stack?

  • thread backtrace

watchpoint

Need to know when a variable pointer changes? Use watchpoint set.

  • watchpoint set <variable-name>; e.g., watchpoint set _imageView.

Variable exists inside another object?

  • watchpoint set variable <object-name>-><variable-name>' e.g., watchpoint set variable self->personImageView.

frame

Print out a list of all variables in the current frame. Very useful when you don't like the way Xcode shows variables.

  • frame variable

Need to know where you are?

  • frame info

Chisel Commands

https://github.com/facebook/chisel

Chisel adds a number of awesome lldb commands that can help you debug like a master. Install it using the instructions provided and you can use the commands in LLDB just like the standard ones. If they sometimes done work, run command source ~/.lldbinit to load them again instead of closing and reopening Xcode.

pvc

Prints out a list of all view controllers currently displayed. Helpful when you need to start digging after pausing execution and you don't have the context you'd get from a breakpoint. Works by finding all displayed UIWindow instances, and starting from rootViewController.

  • pvc

pviews

Prints out a recursive description of all views and subviews.

  • pviews

fv

Helps you find a specific view currently on screen.

  • fv <search-term>; e.g., fv imageView.

fvc

Helps you find a specific view controller currently displayed.

  • fvc <search-term>; e.g., fvc requestviewcontroller.

presponder

Debug the responder chain for a control.

  • presponder <variable-name>; e.g., presponder _nameTextField.

bmessage

Same thing as breakpoint set --selector. A little smarter in that it goes up the superclass hierarchy if it doesn't find the selector, and sets the breakpoint when it does even if it's in a superclass.

  • bmessage <expression>; e.g., bmessage "-[MyView setFrame:]".

visualize

Given a view, visualize will composite all the subviews of the view into one image, save it to a PNG, and open it in Preview.app.

  • visualize <view-variable-name>; e.g., visualize _tableView.

show/hide

Shows and hides a view or layer.

  • show <view-variable-name>; e.g., show _tableView.

  • hide <view-variable-name>; e.g., hide _tableView.

pjson

Prints a JSON representation of an NSArray or NSDictionary.

  • pjson <object-variable-name>; e.g., pjson dictionary.

pdata

Prints a string representation of an NSData object.

  • pdata <object-variable-name>; e.g., pdata data.

The default encoding is UTF-8, which is analogous to typing this in LLDB (where 4 == NSUTF8StringEncoding):

po (NSString *)[[NSString alloc] initWithData:data encoding:(NSStringEncoding)4]

pcurl

Amazing command if you work heavily with networking code. Converts an NSURLRequest to a curl command and spits it out.

  • pcurl <object-variable-name>; e.g., pcurl urlRequest.

mwarning

Simulates a memory warning.

  • mwarning

Analogous to typing this in LLDB:

expr (void)[[UIApplication sharedApplication] performSelector:@selector(_performMemoryWarning)]

Reveal

http://revealapp.com

Similar to the View Debugger in Xcode 6, but actually useful. You can change fields, toggle properties, and see classes Apple doesn't want you to see.

@NullExir
Copy link

NullExir commented Sep 6, 2025

Many thanks for the useful commands.

Combine this with a breakpoint that continues after evaluation and suddenly you've permanently commented out two lines without even recompiling.

Could you please add an example on how exactly to do that?

The way I interpreted is as follows, let's say that we want to skip the current call instruction:

(lldb) br set -a <addr>
(lldb) br command add
Enter your debugger command(s).  Type 'DONE' to end.
> thread jump -a $pc+5
> continue
> DONE

This effectively jump five bytes (call instruction) and moves the $SP to the next instruction.

Is that what you meant?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment