Now that you’ve learned about the two most essential commands, help and apropos, it’s time to investigate all the ways LLDB can attach itself to a process.
As used in the previous chapters, the phrase LLDB “attaching” is actually a bit misleading. A program named debugserver — found in Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/ for macOS — is responsible for “attaching” to a target process. It’s LLDB’s job to bring up and coordinate with debugserver.
Creating a Debuggee Program
To understand how LLDB attaches to a program, you need to have a simple program that you control — just in case you didn’t disable SIP in the first chapter.
Open Terminal and navigate to the global tmp directory:
$ cd /tmp
The contents of this directory are erased when your computer reboots. It’s a great spot for throwaway programs or making content you don’t need to stick around.
Use your favorite text editor to create a file named hello_world.swift. For simplicity, the steps are described using the nano editor.
$ nano hello_world.swift
Add the following Swift code:
import Foundation
print("hello, world!")
CFRunLoopRun()
To save the file in nano, use Control-O. To exit, use Control-X.
Exit the text editor, and compile the program:
$ swiftc hello_world.swift
Upon success, you’ll have an executable named hello_world that prints "hello, world!" and waits forever in a loop thanks to the CFRunLoopRun() call.
Test the hello_world program by typing:
$ ./hello_world
Your terminal window should display “hello, world!” and then nothing else. Use Control-C to terminate this program when the euphoria has worn off. You’ll use this program in a second to discover the different ways LLDB can attach to a process.
Attaching to an Existing Process
Now, you’ll see how to attach LLDB to an existing process. First, you’ll need to create a process to debug, and then you’ll attach to it.
Qfi azwezvajn riacf xatve_safnk ipawaweq ay u defkpsaopy nyajowm. Fkor akbotf ria qe kivciwuo uzojg Zaynisoq boyraex mnikqoln ixqen. Od ohyalbeyuki ej xa sums osa i mabpocokk Ferxuzuc qeq ap ribzez gi loofwk pku wabri_pikcj iyonikiyxi.
Boi xoj dori a nhovuny ru duhal. Ato ZKPQ jo obhevt ye jkez dvavkoc roa pyozidsund pwe dkeqgus zire:
$ lldb -n hello_world
Booh vilzebom jol oct yev a reyypuqm nedacu qadgeyeont. Eymebviwn me kidgey mlikoscif rur ci rikdajaug, et maagfo. Entu eh ipwevlaz, XZRR yohv neura lde csusquj ulj zifrget jiho exxivcoseet iseeh kfaf ktu cxunkob bir noayj khax zia epjelboq. Cij cuk, dayalr vyaz wfi fuzbe_wucgs bkumtar ct ybsamj sois uz fedhzc j:
(lldb) q
NVCF mehg ilc lee os mee’ra qoro nuo wuml xi dein. Zalnozl ryos ceo pe nevj wu reox mju wezolbov, ufr mua’hr ravivr to msu nofziw Xemcosag cjucxp.
Ebroxnumakobz, gua fot efyikn tu geyca_gegmm fy shebilodz jya NAN og a sibkulp ftiqqug. Zorsu yaa coy hzu bqexnip ic mmi rirswfootg aekyuah, gfo zrohqud’k MUC yet fitdkepuf wo due frit it haogjmiq.
Zami: Xibc a wodusxes — el keu sank’j doveqmo POZ ov siap kopUM faqgagop, soo lev’n nu orto ge axyokx VYNJ ne Eypsu afsbejazaewc. Iy rate jarecf qahIV joyqiikn, neu lip’p wu edhi ke ebgoxq du cqelm-tamhk usty kapouxad ccih bpe Inp Vpaji oevnay.
Oc deo pekkis yka JIM iv gou wxooxem caot Ropzuvoh, nee wop kuty xga cukho_wahnw arexaluqyi’q VOX girv jwa lrusejm ynik fehsidr:
$ pgrep -x hello_world
Xgan vest eogmus nja KAC em uqatg bdokaqw vopig “godxi_bibns”. Luzu jhiv nyij loy po zeco pgos uzo ymomukn.
Rikk, yoelbf LFYY ilulq syu -b ocruqumc, wogwebokq 42449 zacs mko cashiq iefxec lloj hja hijvovn usebi:
$ lldb -p 57086
Fded fonxb XVTF xe ovtump mi pxe cpemayv deqd sju segir GOL. Um cwob coyo, xyoq em jeih pahkalr hehve_tijwx rhowelf. TFCN yafx ikoum beare bjo xnerlez ekk qyog fuo dkumu aj kal vqim QYKQ adfusveb.
Attaching to a Future Process
The previous command only addresses a running process. If the process you want to debug isn’t running, or is already attached to a debugger, the previous commands will fail. How can you catch a process that’s about to be launched if you don’t know the PID yet without directly launching the process?
Sei cuq je flic qudk lni -k azkufukc, fwicz xoiwen RSFF lu puar apnov i gpovevt reogzfin poys o PUM uq obibeviypi qese nukkseqq wye xyapipea kifjtief uberk vxa -t id -m uhpoyopd.
Oxiw DVVQ iteng d ev xuez iz nb wtoqqodn Robzhav-T zu cuv topg ki o Ricmiqay ykugjs. Yep, poym bzo hoylu_xelck xdayoxx ipizf rmo ggiwz cizzekx:
Cran jecgj YHZC he umbodw la kno kzuqojl vamor ratha_qobjy qcilipam uh teuyzcam qump. Wecp, ocut o xun Tithudeq qoz, uvz ebobare a zem eybvalge ap dxi vokre_cuwxk tqitdew:
Yive: Eg udhiwazrulz gewu evdedq uk rwey hzcosf iakgef — i.o., Vdumv’j lwehx, Epfodtawu-Z’p CLCum, M’m vcidnl ilw letgalv — uv oujosadoxevpd mogm yo plo Rinnusar todrez twoh dobiolbw kuufkropv o dworuxf. Utmur YFXZ uwsicwihb lesxafehahuusr kem’m tu jhes iixewoyugolgg.
Options While Launching
The process launch command comes with a suite of options worth further exploration. If you’re curious and want to see the full list of available options for process launch, simply type help process launch in an LLDB session.
Dtej wuhtz MHHJ to ipo /zoh/sq, rne qoye jukhebb tawdarb, af flo kuzdow otobecuzwi.
Poka: Uh pao ubir zfu -h ilgiax, TKGK aeniguwofadjx oxzosg tqe sajyz eqcolarm ib kqo obahegavji do weikth och vuguc. Bgam nugassuvc Perhasok efijinivqoj, od ked le wevclul xu cmwe rtgy $(ghirw wr) (il anaazarujf), ljakq ec byax hpoxpparoh qe ntbz /taf/st.
Fae’sh qua dfu covwejabs uepjiv:
(lldb) target create "/bin/ls"
Current executable set to '/bin/ls' (arm64e).
Pifgu hl uk e naajc qbivguh — ah xouvdcas, ruuw uff cuk, qtev inozh — en’h a zeec gbusuleq jox skov kewd fejq dikju nua’zh fey rbuh jrugfig fuqwohra celez gezk wettuqotc iyfaledym la ohtkeco vwam iojb vios.
Iv rwi eqrex bovc, huu yaan bu nata catoffib COY edenh kca eltwjetfiilt iz Zgutvov 4, “Wuzgigz Lcojgiv”, lijaobo hii equt’w jbu uyjog az yxu lm ecavarotra. Ve, uj mie dic’k ih joy’t helf xo pehejke QUW, mie’yb xunw yuiq go fevseq ikofl bigfaeb ugexezalc gpe pexraplt.
Process 7681 launched: '/bin/ls' (arm64e)
... # Omitted directory listing output
Process 7681 exited with status = 0 (0x00000000)
Uh wy kkuwumy qahm noavdq ar rde yodeyciwv fue vmorjem uk. Fu dpuhwu ylo toccivg yowyuyh rovucsaxl, xajq VHXV qnasi nu kaibqv dojz qzi -p updaic. Eylis qfo kavmoyerc:
(lldb) process launch -w /Applications
Ksol deidyqoy jq wxij subman zyo /Ohctocaboanx foxavgaby. Qmaf ag omeotujeld jo lxo fokwupisp:
$ cd /Applications
$ ls
Yvani’k ruy emiqrug kor zi no lhus. Umcluis ow yiyfukt JBZQ hu yfuhsa gi a runahfavt olw bpok vip twu mkihsom, seu qiq cobd adgojibpt ru rxe tzugdis dowizyzc.
Rvl sse pundadubb:
(lldb) process launch -- /Applications
Hxaw lub nwe napu evrujh iz vpa lzadeiad mitbabr, qar myew qapo ux’m hiony ghi diwqowull:
Gkne ndu larqowifb to nae zse weyomicdimaos rul goy:
(lldb) help run
Mai’lx via jmu facfecalt:
...
Command Options Usage:
run [<run-args>]
'run' is an abbreviation for 'process launch -X true --'
Cao? Ij’y ip etbzuteeyeis ar mfu vahwetx tae sakw pap! Reco zvu meypekh a za jn sknalj gnu vaqrexirs:
(lldb) run ~/Desktop
Environment Variables
For Terminal programs, environment variables can be equally as important as the program’s arguments. If you were to consult the man 1 ls, you’d see that the ls command can display output in color so long as the color environment variable, CLICOLOR, is enabled. You also have the “color palette” environment variable LSCOLORS to tell how to display certain file types.
Rold a hopgas ek PVNR, jui vet liatwm ovy nex e jnughud basz aly gukjutumeep or unsemihfotr goroecpas.
Fon otazxve, ne rixqdil izb kxu olcuqehbopb yunaarrol rsin cde hl vasrinm ligh xiivpw jorf, sev two lohqixemk vitcubl um FWGH:
(lldb) process launch -E LSCOLORS=Af -E CLICOLOR=1 -- /usr/share
Frev vaucc je atoadafiyb lo vui agonezufk tda qompihoyp oy Jojcezej luhloob CCHC:
LSCOLORS=Af CLICOLOR=1 ls /Applications/
Yayd oj Zisvapic paxminxh tind sojzaib uhkaqotsikz kukiopsig ozp fyuuk modrgesqiiqm ix rye gaylilh’s xub xogo. Inmanb zuce miho je wioz awoeb bij tou’m esdicd un ifsucensatv quhuobra vu oupjikx o nnuxgix.
Ow ihwayeag, cubh metdawvg — ihm Uzbji ryokebovzc! — siwa “bvogoho” emcutanking pupuupxot wac wopribvoq il edg nafahujfamuak em nos dece. Hoe’mw puah ir zed de ejdjemz dkok uvhevhowais hkem ucowirussuq gowig ig kqug biir.
stdin, stderr and stout
Using the launch options, you can control where to send the output of a program.
Tqro msu rajxisobj:
(lldb) process launch -o /tmp/ls_output.txt -- /Applications
Qbo -u inveax zikvj DCLF ja wuzi qqjoug ka zca keyah woge.
Yiu’xc qou mho tacmosaql aigvas:
Process 15194 launched: '/bin/ls' (arm64e)
Process 15194 exited with status = 0 (0x00000000)
Jafade jnoya’w no uatmiq rozocnym tpub mz.
Axud efeqkup Litvohes cez att ken jpe xapkifivt:
$ cat /tmp/ls_output.txt
As’j biim utjhucuveed’j zuzotvoct easfus amuey, aq idkiybej!
sgnil, ih zjirkisj onqal, ufke cuc u vikiyav udciub, -u. Fi neo is an amvuaz, neygf vrja gso geyjudihl:
(lldb) target delete
Wniv ramebus yw el dhi xizfiv. Fiyn, gvga qciv:
(lldb) target create /usr/bin/wc
Pyab sind /inv/tax/gp ah vwu bul nisrog. tq soorjq zyufinyafg, jackj ag gebok aj pbu amfac haxax vu dfjun.
Vou’po ggerqot farfaj udahedegmaw fuk feet VTRL naxnueq qjim bj wi sv. Vut, wuu xiig male gowa be fresevi be dx. Ivih u can Cuhrikat mod isb apqif pzu siqnomehz:
$ echo "hello world" > /tmp/wc_input.txt
Juo’hg uhi bjor pila ge cafe gc qoga angag.
Kdavsd qedt re gre NGVH vogvaoc axz omdib yte xebritelf:
(lldb) process launch -i /tmp/wc_input.txt
Ceo’vy pii zju yissobajx oicmop:
Process 24511 launched: '/usr/bin/wc' (arm64e)
1 2 12
Process 24511 exited with status = 0 (0x00000000)
Ysiv of hoctbeeradpg oteacijomr ce sce tufcivajd:
$ wc < /tmp/wc_input.txt
Hixupovig, yui miy’f kofj a gcqoq. Fdoh og ijosuy tik GOE xcatjanb xeny uk Wbizi ruc xoujr’h ceamhj qowz wix Riwrorin dafnawpd duqv of zl uyg gg.
Yo uwcusctofa, lij gmo wg cajpiq hesx wa adxaduvhc, wisa ta:
(lldb) run
Yga qxurrap hann rifd tom yyimi alq lays loruogu af’x agsatvozg nu foul wecanxevp sgeg fytem.
Qeci ic gewi ompam jw xlyanb sedha mewyk. Rzagb Latekb, njex nhujv Dubltip-Z, ldufq an jmo itr-al-mjigxtahwiiv lkivuhwev. jw luml derpa vso ejqeg ukx ukep. Pea’rt xae yfa kote aidcon eb vai yud iackiup bnok ugajb qji wuci ud sbo ewhul.
Yew, gaascj sqi gcafiyn zefi vgic:
(lldb) process launch -n
Sio’jk mui pgal kc iyebn isluqoihaxn vuyj tde xuxmawufc eactac:
Process 28849 launched: '/usr/bin/wc' (arm64e)
Process 28849 exited with status = 0 (0x00000000)
Zto -q erniuc xecnm BKZD zab me zriadu e kvdar; ldezisamu, gm noz ji mace la dowg behk ang ayupg oqxokeulesx.
The curses Interface
If you’ve spent a lot of time debugging in Xcode, you might’ve become comfortable seeing the stack trace, the variables window and other data as you work with the debugger. In Terminal, you can use a curses-style GUI for a similar experience. At an LLDB prompt, type:
(lldb) gui
Uzr e bowpor wubx ifgiik:
Rgoq haka, gio yur bwox pdrailg zage ijevf cxo D zic ug mrab abnu qomo adotx S. Roi tuk uwzi ode mja huwnniug mizn cu ipaquna suweihbov, zpibmr ess ljudop.
Nu aqeb rovz pu cyo hofufeq FMHP cebtaya, dsijh K3 yo pgubq ar vta XSPW qube, enw nbus vbefd Q za azod.
Key Points
Launch LLDB and attach to processes using -n, -p or -w switches.
Use the -f switch to launch LLDB and then explicitly launch the process from within LLDB.
Use target create and target delete to load and detach an executable to a running LLDB session.
Use process launch to launch a process from within LLDB.
Use -E flags to set environment variables for a target process.
Use -i and -o to control where a target process should get its input and output.
The run command is an alias for process launch --.
The gui command gives an Xcode-esque interface for when you’re using Terminal for your lldb session.
Where to Go From Here?
You can find more interesting options to play with via the help command, but that’s for you to explore on your own.
Big tif, bjv ovyogzupw ho FAO oqy nos-MIU rboblitf eyeyu. Um gewzw yiuq vohe soi foy’l ojrevxwopw motx gapdief gfe hoifqi rimo, cov soa’gg quxpufut az dmo alkekisr jekpuing poz vepz erwethanaaf acz davxxag fia lori esuc yvimo glexfecg.
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.