EECS 280 Tutorials

LLDB Tutorial

LLDB is a command line debugger. It is the default debugger on macOS, and is used by Xcode behind the scenes.

LLDB is harder to learn compared to most visual debuggers. However, you might want to use LLDB instead of VS Code or Xcode for several reasons:

LLDB uses commands. Here’s a handy list of LLDB and GDB commands.

Quick Start

Compile your program with the -g flag and start LLDB. EECS 280 project Makefiles include -g by default.

$ g++ -g --std=c++17 main.cpp -o main.exe
$ make main.exe  # If you have a Makefile
$ lldb main.exe
b main breakpoint on main function
b 13 breakpoint on line 13 of current file
b main.cpp:13 breakpoint on line 13 of main.cpp
r run or rerun
n step over (next)
s step into
up step out (up)
c continue
p myvar print variable myvar
bt backtrace, useful for segfaults
q quit

Install

You should already have g++ and lldb installed from the main macOS tutorial. Your versions might be different.

$ g++ --version
Apple clang version 12.0.0 (clang-1200.0.32.28)
$ lldb --version
lldb-1200.0.44.2

Compile and Run

LLDB uses an executable you build at the command line.

First, compile and run your executable at the command line.

$ g++ -g --std=c++17 main.cpp -o main.exe
$ make main.exe  # If you have a Makefile
$ ./main.exe
Hello World!

Pitfall: LLDB debugging will be very hard to understand if there are no debugging symbols. If you’re using a Makefile, double check the output of make and verify that you see -g.

Run with LLDB. You now see the LLDB prompt. LLDB’s interface is similar to your command line shell, where you enter commands and press Enter (Return).

$ lldb main.exe
(lldb) target create "./main.exe"
Current executable set to '/Users/awdeorio/src/eecs280/p1-stats/main.exe' (arm64).

The r command runs the program.

(lldb) r
Process 76550 launched: '/Users/awdeorio/gdbeg/main.exe' (arm64)
Hello World!
Process 76550 exited with status = 0 (0x00000000)

Quit with q. Pro-tip: Control-D will also quit at any time.

(lldb) q

Sanitizers

We recommend enabling the address sanitizer and undefined behavior sanitizer. These will help you find memory errors like going off the end of an array or vector.

First, edit your Makefile and add the CXXFLAGS recommended by the ASAN Quick Start.

Command-Line Arguments and Options

Inputs to a program may be provided when it is initially run via command-line arguments or options. Here’s an example from EECS 280 Project 1:

$ ./two_sample.exe HCMST_ver_3.04.tsv q24_met_online 1 0 ppage

The arguments above specify the name of a data file, coulumns, and filter values for the program to use.

To run a program with options or arguments in LLDB, include them after r.

$ lldb main.exe
(lldb) r HCMST_ver_3.04.tsv q24_met_online 1 0 ppage

Input redirection

If you’re unfamiliar with input redirection, first read the CLI tutorial section on input redirection.

Run with input redirection. Make sure to add the name of your input file (main_test.in in this example).

$ lldb main.exe
...
(lldb) settings set target.input-path main_test.in
(lldb) r
...

Debug

In this section, we’ll set a breakpoint, which pauses the debugger. Then, we’ll cover some of the options to continue execution.

n Next / Step Over: Run one line of code, stepping over any function calls by running the whole function in one step.

s Step / Step Into: Run one line of code, stepping into any function calls to execute them line-by-line.

up Up / Step Out: Run the program until it returns from the current function (or until the next breakpoint).

c Continue: Run the program until the next breakpoint.

q Quit: Quit LLDB.

Example code

To get started, copy this example main.cpp into your editor.

#include <iostream>
#include <vector>
using namespace std;

double sum (const vector<double> &data) {
  double total = 0;
  for (size_t i = 0; i < data.size(); ++i) {
    total += data[i];
  }
  return total;
}

int main() {
  vector<double> data;
  data.push_back(10);
  data.push_back(20);
  data.push_back(30);
  cout << "sum(data) = " << sum(data) << endl;
}

Start LLDB

Start LLDB.

$ lldb main.exe
(lldb) target create "main.exe"
Current executable set to '/Users/awdeorio/src/eecs280/p1-stats/main.exe' (arm64).

Breakpoint

Set a breakpoint on the main function.

(lldb) b main
Breakpoint 1: where = main.exe`main + 20 at main.cpp:14:18, address = 0x0000000100003e48

Pro-tip: There are several ways to set breakpoints.

b main breakpoint on main function
b 13 breakpoint on line 13 of current file
b main.cpp:13 breakpoint on line 13 of main.cpp

Run

Run the program being debugged. The program pauses at the breakpoint.

(lldb) r
Process 72957 launched: '/Users/awdeorio/src/eecs280/p1-stats/main.exe' (arm64)
Process 72957 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100003e48 main.exe`main at main.cpp:14:18
   11  	}
   12  	
   13  	int main() {
-> 14  	  vector<double> data;
   15  	  data.push_back(10);
   16  	  data.push_back(20);
   17  	  data.push_back(30);
Target 0: (main.exe) stopped.

Step over

Enter n (Next / Step Over) a few times until you reach the highlighted line of code.

(lldb) n
Process 72957 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step over
    frame #0: 0x0000000100003ea4 main.exe`main at main.cpp:18:8
   15  	  data.push_back(10);
   16  	  data.push_back(20);
   17  	  data.push_back(30);
-> 18  	  cout << "sum(data) = " << sum(data) << endl;
   19  	}

Pro-tip: Hit Return to repeat your previous command.

Inspect

Print the value of a variable with p.

(lldb) p data
(std::vector<double, std::allocator<double> >) $0 = size=3 {
  [0] = 10
  [1] = 20
  [2] = 30
}

Step into

Enter s (Step / Step Into). The cursor enters the sum() function.

(lldb) s
Process 72957 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
    frame #0: 0x0000000100003d7c main.exe`sum(data=size=3) at main.cpp:6:10
   3   	using namespace std;
   4   	
   5   	double sum (const vector<double> &data) {
-> 6   	  double total = 0;
   7   	  for (size_t i = 0; i < data.size(); ++i) {
   8   	    total += data[i];
   9   	  }

Step out

Enter up (Step Out). The sum() function completes, and the program pauses again.

(lldb) up
frame #1: 0x0000000100003eb8 main.exe`main at main.cpp:18:29
   15  	  data.push_back(10);
   (lldb) up
frame #1: 0x0000000100003eb8 main.exe`main at main.cpp:18:29
   15  	  data.push_back(10);
   16  	  data.push_back(20);
   17  	  data.push_back(30);
-> 18  	  cout << "sum(data) = " << sum(data) << endl;
   19  	}

Continue

Enter c (Continue) to run the program to the next breakpoint, or the end, whichever comes first.

(lldb) c
Process 72957 resuming
sum(data) = 60
Process 72957 exited with status = 0 (0x00000000)

Quit

Quit LLDB. Pro-tip: Control-D will quit.

(lldb) q

Pro-tips

Use the up and down arrow keys to cycle through previous commands similar to your command line.

Use TAB completion to automatically complete the name of a command or a variable.

Use Emacs keyboard shortcuts to enter and edit your current command.

Acknowledgments

Original document written by Andrew DeOrio awdeorio@umich.edu.

This document is licensed under a Creative Commons Attribution-NonCommercial 4.0 License. You’re free to copy and share this document, but not to sell it. You may not share source code provided with this document.