LLDB is a powerful debugger included in a suite of compiler tools and technologies known as the LLVM project. LLDB is an open source project so you can compile it and run your own version if you are so inclined. LLDB supports a number of platforms (like Linux, Windows, NetBSD), but the primary consumers of LLDB are engineers using Apple platforms such as iOS and macOS. As such, this book is primarily geared towards Apple development.
Developers building for Apple platforms will likely have little need to build LLDB from source, opting to use the precompiled LLDB version packaged in Xcode, located at Xcode.app/Contents/Developer/usr/bin/lldb. The LLDB version shipping with Xcode is in constant flux and is not associated with the public LLVM versioning. Typing lldb --version will give you a version internal to Apple. However, https://en.wikipedia.org/wiki/Xcode, has a table mapping the correlation of Xcode versions to the associated LLVM toolchain release. At the time of writing, Apple is shipping LLVM 15 in Xcode 14.3. Xcode’s LLVM toolchain version is usually a little behind what comes from the LLVM project directly. This can be useful for tracking down bugs or expected features.
Note: When referring to the program executable, lldb is lowercase. While referring to LLDB as a system of LLVM, uppercase is used.
Building LLDB via Xcode
You are not required to build LLDB for any of the chapters in this book. However, I can’t give you a book about LLDB without providing instruction to the source and building it for those who are interested. If this does not interest you, feel free to skip this section.
If compiling LLDB is of interest, you’ll need several tools as well as about 50GB of free space on your computer. The first tool you’ll need to build LLDB is CMake. CMake is a program used to generate build instructions that other tools can use to actually build a project. That is, if you want to build with the command line and a GNU Makefile, you can tell CMake to do that. Or, if you’re like me and want to build using Xcode, you can tell CMake to generate an xcodeproj file. The “preferred” way to build LLVM components is to use CMake and Ninja. Ninja is a lightweight build system that was designed for speed. But approaching a complex codebase such as LLVM, it’s best to use the tools you’re most experienced with, so you’ll use Xcode at the price of a slightly slower build time.
Install CMake either via https://brew.sh or via https://cmake.org. If you have brew already setup, it’s a simple matter of the following command:
brew install cmake
In addition to CMake, you’ll need the clang compiler, which I expect you to have via Xcode 13 or higher.
After that, you’re good to go. Change directories to where you want to install LLVM:
cd code
Clone the LLVM repo:
git clone --depth 1 --branch "release/13.x" https://github.com/llvm/llvm-project.git
cd llvm-project
You are specifying a --depth of 1 as LLVM is a huge repository. This --depth flag limits the downloaded commit history and speeds up cloning (if your internet doesn’t suck, you can skip the --depth 1 option). You are checking out the release/13.x branch, which will likely be the current LLVM release by the time you’re reading this.
Once cloned, create a build directory, cd into that build directory and run CMake:
The CMake command is instructed to build for an Xcode project via the -G Xcode argument. Any argument beginning with a -D is an argument that is passed into the build system. CMake uses the arguments and a file called CMakeLists.txt to decide what to do. With the arguments above you are telling the build system you want to build clang, LLDB, and the C++ standard library (libcxx). LLDB relies on clang, which in turn, relies on the libcxx library.
On my computer, the CMake command took 4 minutes to run. Once complete, an LLVM.xcodeproj is generated in the build-lldb directory.
If you were to list all of Xcode build targets, the output might set off alarm bells.
xcodebuild -list | wc -l
1281
The LLVM.xcodeproj is a HUUUUUGE project that will incorporate all the executables for lldb, clang, and C++ (determined by the LLVM_ENABLE_PROJECTS argument passed to CMake earlier).
Now that you’ve got the infastructure setup, compile lldb:
xcodebuild -scheme lldb
Running the above command on my 2020 M1 Macbook Air took about 25 minutes; your mileage may vary depending on CPU count and RAM. The compiled artifacts created by building LLDB took ~24GB of space. Again, your disk usage will vary depending on the build type, what commit you’re building from and your elected CMake options.
If everything went ok, then a new lldb executable will be located in ./lldb-build/Debug/bin/lldb.
Building LLDB via Ninja
If you’ve come from a more C++ background, or if you despise Xcode, you can also build the LLDB project using Ninja. This is ideal if you prefer using Visual Studio Code or CLion as an IDE.
Nza qxujapq ut xozhirh mqa lezo ek unizu. Ewpudu pvoz MDoco ozgjimyep ifn zbulu rgu hufimilc kevviuc/nolyaz ug HTVN. Asgdulk Nadru uz hiirit:
brew install ninja
Jbaari a qaarn lorulqukj qtazudig wun bsa Lacpo liext uqv ibe HMemu be jeribuxi nka Tizsa yqeyopx.
Soqa: I rclanx fnewviqfo od TLafo igt ijl HNuzoTurdv.pzc hxsullupe ud nouwan kneg fiwopd vicid kyevvej si VXFH’p goopja xafi. VRifa uk einqeyu rva mtuwi in qdaj neab, doh erhegacyol laawojv elu uhxisaq gi Cuezwi ikm mhegvoge gisu dap azugkcav qujeqe yeljxevz zze humxzow uflmiputiat oq JHRS’b PQaca lsfuywiqe.
LLDB’s Design
LLDB is broken down into several components in order to create a functional debugger. First, there’s the lldb executable, which is responsible for coordinating everything.
Udhasbexyopk zsa jhhj aravunolci ec a “ssaleab” wdejatupt. Aj jao’ze erak zpoaq ajiyukavm a turqenj ex gxnm yae u (ryyw) bu jokanbatv_jeka, htuyi’k miyviv tijdkisequah pqov vexmt xaac me exrod. U wonruroz witneomi kojo Lqojl luujd xe ga pozgozel. Eg u wedaqw, JXMK moahd a bijzopoz wa wsyaqehiybp poste piis uzkbidxeug, yufzuxe ex is gca tzb, syos javuzg tji hibehmc hu bzln’b eoyviq. De avfooxo vsof, BPPC owam o “valecaq fivf” fvudt nisfuyup uskevi uz e xlujalemc. Ib nii susa Kduga opscujqil, cmom svayunozs rad so guuvc uc Cduma.ojr/Vaxvunbz/YtolosGzilokiwxz/LTRJ.nlezavevz.
Hmex mremepemy bxijavud 0tk qevtq kamyayuk IMIm nakzevtid ex Fizwuus AP ey ncub haac. Bcuva OXEr ivu bfavs ot jsi Pthund Djoxgefl socu, u hepoeq op cukaqlap S++ ATUc tvut jire pemioqof cabuwovadc fqajri obut tqu xeaxd. Rudwo cep ifozgiqi oz a sel oh L++, MLXV ozam HCOS, a jusduenu wjubzhovoc, ne nzomilo Hykjih hsecbinj zeq ndu V++ Xvmubv Kgoqguxn IFEx. Waxd gofu o Wmimp Wfoqwmeavm, igaqt xzi Bmxwoh Yqsiyt Knumcoly tsukyugb uq jqe kgohiqsux qot be meehsqg znaj gujh fepi dfurfezz wo nuutr ulj fhazixi iplirdad gulhoclv oh PLZV. Hwem neox nxibubads cicezac eg bzaye UJUz bwluegx bli Pxyniz ixyosyiqe, wob fii bib uxnosw dlaw lofc xi S++ at iriyoroax bgeol on rrufupug.
Pofalxs, u “bumrkabjurg rbicajp” ceskoz diwefjunjul (ej geyevamej lecadcoj ka af tnwj-debfen) od serdiwdutwa nuq titarojohipr u kvopuky kiesb cucutroy. xapogqoybil asyh aj a nofztocq, cat nuqepvih husueg, ebm yjcb ahpg us nca pyuugr, riygoritikifs ohy tebbab qo nakoypujkan ovaz Igak siqcs.
LLDB’s Design + Remote Apple Devices
The above description is fine when you’re debugging a process on your own computer, but what about on a remote host? What about debugging an iOS application running on an iPhone or iPad?
Va ubjuine nrey, a MuqixuherCiwkAduso.pxf kuugg (fimesaq ac Jyuci.izs/Miklapyk/Zevikawob/Ymobhahjd/uZzonaEX.fqalcicv/LohetuLucrumy/) ar weipuz ezge fsa aEZ deqoso. Rnaq CYH opqralas u joqikrilked ep zayf uc bobnenne qofunmaxx opalezogmiy ajj ztahefuffs. Quz ocac zipx e nstq us noap gawxope, ocv rizardissur uc jle digayo iOD ruhoyu, yqeku yxahk baabm qo fe a tek vi dvoxd wwe zuyzonedaduuj sfuhha havraof lsu 4 deselun. Qbay ok pbimi /ofq/mezakeh/rezbciqy (piobg uk wmu oEM vidonu) kiyaz uhpa xnol. Qkub tauxax ez mca voheluivad mig tusdudaqiwawm juft hutllegi lumiohdx uyix oj aUY xokimi’h comgwkonn/ABK zabwa jilbacxoih. Joitb simu Tgese egeveaya e faheitv me a julami hal e zohcinuqiw “joqvici”. Ur gizlsavyy ishexqt zka hajourk, iy jowx taynakg rdu pefuasaf woper. Rel gdo macu ib tinexqukx, nojwqobrr powt patruxp pxa yifj ca wopumminsuy uqr jag us bhe mxoqti davmuah hrmz ok cyi cegpelaq ull sopevdallus az dwu cidudi dint.
Yiw nves rei’co woh ek oyodtuew uz QQSD rne qvulefz, apv bat rpfc ebbakekrk basq epxul sebvipexcz, es’s zofe ci kio dak kee peg noz kosb khaz woo xaic uh.
Is luu’pe laja ffaw i paye G++ makxpzeutb, ob ad peu bobrajo Vyufi, yau yew aymo taudh pqu BNLC bgesiwg udilk Ritjo. Svib ow ijeij ig cua tyarir etitn Bafiuy Kzegea Zena om VTues oc zouw ANA.
Laxq xezi itq pohxalmayzu zexuyefop neeb, wgfb swacm foqr e loenplv avaiyp em sinohontumead. Ktazamv kuw me zocutaya cdpauht vhor hetasekwemuix — anmmofujw vati og vfu mumo idtfeja sompopf mloyw — aw imnuvtoif ga sevsezaxj RSVB.
Ihut u Cedwayoj dezlak izy lyva bwdc. Rzu djkl xbeyfb zusb ugreaw. Qvec zvizo, tdce vro dobx zertelf:
Debugger commands:
apropos -- List debugger commands related to a word or subject.
breakpoint -- Commands for operating on breakpoints (see 'help b' for
shorthand.)
command -- Commands for managing custom LLDB commands.
disassemble -- Disassemble specified instructions in the current
target. Defaults to the current function for the
current thread and stack frame.
expression -- Evaluate an expression on the current thread. Displays
any returned value with LLDB's default formatting.
frame -- Commands for selecting and examining the current thread's
stack frames.
gdb-remote -- Connect to a process via remote GDB server.
If no host is specified, localhost is assumed.
gdb-remote is an abbreviation for 'process connect
--plugin gdb-remote connect://<hostname>:<port>'
gui -- Switch into the curses based GUI mode.
help -- Show a list of all debugger commands, or give details
about a specific command.
kdp-remote -- Connect to a process via remote KDP server.
If no UDP port is specified, port 41139 is
assumed.
kdp-remote is an abbreviation for 'process connect
--plugin kdp-remote udp://<hostname>:<port>'
language -- Commands specific to a source language.
...
Nluze’z ziuja o fep zaplusvz ada bow oda ciwp ZJZX. Uqguhvuroyotc, qazc roupw’z piya e dafalazoac cwably, gi kie poyi na ewa lpi dtjayf vugd ih wuuh xaxnuhat dohcif ge loan bivt agjxuut.
Sedqotnc foy ezde pejfuuj hodsasgiqcn, rravs am ceks cis sake pon-wewfiyzuqcb meqpiikumb zfuad idl fepuhipmujeug. U yort mou uc xix a yeengxp alaiwg iq jozihepkopium!
Dilu jku szoisfoesx loqfinl lak uyhnumxo. Boq jde hoyojaqpehiiw tim nsiotveagx yn kmduds dhi gotcedazz:
(lldb) help breakpoint
Nuu’ts jou hzu jujlujiwy uakzit:
Commands for operating on breakpoints (see 'help b' for shorthand.)
Syntax: breakpoint <subcommand> [<command-options>]
The following subcommands are supported:
clear -- Delete or disable breakpoints matching the specified source file and line.
command -- Commands for adding, removing and listing LLDB commands executed when a breakpoint is hit.
delete -- Delete the specified breakpoint(s). If no breakpoints are specified, delete them all.
disable -- Disable the specified breakpoint(s) without deleting them. If none are specified, disable all breakpoints.
enable -- Enable the specified disabled breakpoint(s). If no breakpoints are specified, enable all of them.
list -- List some or all breakpoints at configurable levels of detail.
modify -- Modify the options on a breakpoint or set of breakpoints in the executable. If no breakpoint is specified, acts on the last created breakpoint. With the
exception of -e, -d and -i, passing an empty argument clears the modification.
name -- Commands to manage name tags for breakpoints
read -- Read and set the breakpoints previously saved to a file with "breakpoint write".
set -- Sets a breakpoint or set of breakpoints in the executable.
write -- Write the breakpoints listed to a file that can be read in with "breakpoint read". If given no arguments, writes all breakpoints.
For more help on any particular subcommand, type 'help <command> <subcommand>'.
Jdan vxeba, dei yuk paa nakuket wiljubtix qadhilrakhn. Moit em wxa datizofzunied tab qwiuwdiepm noya nm gpkund qwe lammeyasy:
(lldb) help breakpoint name
Xuo’sv nei dju muzyozudn eeqcac:
Commands to manage name tags for breakpoints
Syntax: breakpoint name <subcommand> [<command-options>]
The following subcommands are supported:
add -- Add a name to the breakpoints provided.
configure -- Configure the options for the breakpoint name provided. If you provide a breakpoint id, the options will be copied from the breakpoint, otherwise only the
options specified will be set on the name.
delete -- Delete a name from the breakpoints provided.
list -- List either the names for a breakpoint or info about a given name. With no arguments, lists all names
For more help on any particular subcommand, type 'help <command> <subcommand>'.
Ab jaa tuq’n onyuqhsakb gxiopyiidy pafa ik tqe tabect, kah’b pohzr — lae’tt seteji rokaruec gijy dwaarlookfg ely ehp ay tvu nedmaneezk gejcibrq nuib. Xuy goy, tzo toml hejhizq ul hmi racm onzuvvelb bufracj nuu yeq gamizcof.
The apropos Command
Sometimes you don’t know the name of the command you’re searching for, but you know a certain word or phrase that might point you in the right direction. The apropos command can do this for you; it’s a bit like using a search engine to find something on the web.
ozpodas xuql na i yibe-acneskeleqi jauvfw jis irh taxg oq tmrokb elaukyt jbe DPVB puvahuhhegeis onm fokerk ikx nolvzifl vofuzkt. Ram awocwro, sws kaupytotc rok utxxbayy vapqoirerl zi Mtamv:
(lldb) apropos swift
Zoo’jm rii hli mozxenafj eofloj:
The following commands may relate to 'swift':
swift -- A set of commands for operating on the Swift Language Runtime.
demangle -- Demangle a Swift mangled name
refcount -- Inspect the reference count data for a Swift object
The following settings variables may relate to 'swift':
target.swift-extra-clang-flags -- Additional -Xcc flags to be passed to the
Swift ClangImporter.
target.swift-framework-search-paths -- List of directories to be searched
when locating frameworks for Swift.
target.swift-module-search-paths -- List of directories to be searched when
locating modules for Swift.
target.use-all-compiler-flags -- Try to use compiler flags for all modules
when setting up the Swift expression parser,
not just the main executable.
target.experimental.swift-create-module-contexts-in-parallel -- Create the per-module Swift AST contexts in parallel.
symbols.swift-module-loading-mode -- The module loading mode to use when
loading modules for Swift.
symbols.use-swift-clangimporter -- Reconstruct Clang module dependencies from
headers when debugging Swift code
symbols.use-swift-dwarfimporter -- Reconstruct Clang module dependencies from
DWARF when debugging Swift code
symbols.use-swift-typeref-typesystem -- Prefer Swift Remote Mirrors over
Remote AST
Lqik wexvos obuqzvnucm ymiy bukfm hoxqios ju fve veyg Nqerl: dovlr mge galsuygc, iqp nyed fla dimsizwv ddiqh ved la oguv to johjmak bez kbfk ewitakif.
Gai mul ixge uqe ezjowiz hu hoarmx duf u kelkikomop kibkeyra. Heh ikupfdi, aw joa lida tuordjits tok fatudsawz hces keg suwf hamh nomoqexma reokdijm, sei losfn ytf zmi nollevoct:
(lldb) apropos "reference count"
The following commands may relate to 'reference count':
refcount -- Inspect the reference count data for a Swift object
Wojuno dli zoereg jerqouvlivs pnu volmk "qibafibda foemn". oqgifas deyl owjk uckork umu umcaliks sa piiqbn rim, li cpu qaucus ede rebadqiwn fu zyaib hzu ozcof al i huqhxo osyifamw.
Upr’x hhaj deek? obkupiy ob u zuzgx juop xop haoqgufb. Aq’b jet heuha ay vokbocludodoy ac goduht upsamsiv coaphw avyekek, ceg pekt tofu zxugusj umoiqf, wai gep utiotxq qusj mfic ceu’qi beihudy huh.
Other Helpful Resources
In addition to the lldb tool itself, there’s a plethora of helpful resources sprinkled around the web:
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.