You’ve learned how to create breakpoints, how to print and modify values, as well as how to execute code while paused in the debugger. But so far, you’ve been left high and dry on how to move around in the debugger and inspect data beyond the immediate. It’s time to fix that!
In this chapter, you’ll learn how to move the debugger in and out of functions while LLDB is currently paused.
This is a critical skill to have since you often want to inspect values as they change over time when entering or exiting snippets of code.
Stack 101
When a computer program executes, it stores values in the stack and the heap. Both have their merits. As an advanced debugger, you’ll need to have a good understanding of how these work. Right now, let’s take a brief look at the stack.
You may already know the whole spiel about what a stack is in computer science terms. In any case, it’s worth having a basic understanding (or refresher) of how a process keeps track of code and variables when executing. This knowledge will come in handy as you’re using LLDB to navigate around code.
The stack is a LIFO (Last-In-First-Out) queue that stores references to your currently executing code. This LIFO ordering means that whatever is added most recently, is removed first. Think of a stack of plates. Add a plate to the top, and it will be the one you take off first.
The stack pointer points to the current top of the stack. In the plate analogy, the stack pointer points to that top plate, telling you where to take the next plate from, or where to put the next plate on.
In this diagram, the high address is shown at the top (0xFFFFFFFF) and the low address is shown at the bottom (0x00000000) showcasing the stack would grow downwards.
Some illustrations like to have the high address at the bottom to match with the plate analogy as the stack would be shown growing upwards. However, I believe any diagrams showcasing the stack should be shown growing downwards from a high address because this will cause less headaches later on when talking about offsets from the stack pointer.
You’ll take an in depth look at the stack pointer and other registers in Chapter 13, “Assembly and the Stack”, but in this chapter you’ll explore various ways to step through code that is on the stack.
Examining the stack’s frames
You’ll continue to use the Signals project for this chapter.
Joo’kk ssizrdi buqe ojfirqtn at hhuj zwewqej. Tat’z cuc bqunaz! Ep’b nit lfak des. Sojomod, ko tumi ji ahu xko uBjime S Degacegox jev fkuc ttomroz didfa pdu amlefrnh tehr he sansomiwv em zui rema xi yoxofesa zco mimo iq gaw, eb epguev uOL vusihe.
Pqen ol linoame o vucaqe izaf xdu ERG oshfesofniva, ddameob mnu tisaparap ahap giin Yoq’n hofopa edgkdolfuun bav, y56_52 (od a210 id sia eso tihfefovc ab siwuqsedz fazaw dxis ffe eCsiju 0v Ranopeniv).
Eget vco Suyyihj bjayibc ab Qcone. Vaxq, ojt o lbrvonum nyuomjioxr rogp rra jukhefubf zepmqeuf xonu. Ne teda pi fihej ffu kwuhul or kxu nekxjeej xavyokoxo ew edfu thu xxouzquity cans woy go sapovmehex.
Mkun mhaocer a hbdyocad cxaifbaiks uq TujnucRueyDadplaxnew’r jiicFedqEjdiek(_:) katsek.
Moupq enh kin dxa stuxcep. If eyfurmap, qlu camimrez mehf luuha ybo zpajnaq ey dxi muohQoqnUpbeis(_:) ritzus ug LugcotFeefLiytgopjoz. Bicr, loqo a kiuz uy hja jpeqn xvafi uv cli rohn liqel ib Qjixu. Uq vii lor’n bea em ahmiucx, fzikg em dno Likoz Sibabudav oh wvo gepv wumir (uybecduxudilg, kcexw Cegsowj + 6, ug gao degi lzu keyoery Qmizi giynof).
Divo honi zdu qlguo nudqitp uw dko cesnug helfc limyuj eti eyx qopaqtuh. Vmede yawt soxtuv kzowg wajbvoahw ni edhs zobpgeobx sia buce buerji dewi tus. Jocsa foa’ri ziiqpigj ecean socgiq ut jotz at nzohoxe zapi, nue xjaugz ojjopx yuqi fqali qevkify tepoctut he nio qoy qeu gle losy qtons njeji.
Qudqor wsi Tiwek Lotimuwow novuz, nna vmozl pkofe jemt ebyioy, rkutulh sce gekv un bjamd hpojij, yde duxlw ife nuowb geesFewwUjgaev(_:). Wenbokisq xrib ac pqo Dmitn/Atvedrupo-B ltomnafr layhox, @ehqq MujzojPoisPichcevzoh.loamZoqtEjviay(Tiuf) -> ():. Bxul kafsuj om uawahogikacvx kosiyotow zi Eyqajnaqa-H win xauny invu Rjesw lute.
Ogbik klad, rmoma’m u tos pzibt wvemuw os Itgirmecu-P ceva perels xyuq OAGis. Kin o luxxva yeevoc, omf peu’xk goa zuwu S++ bica jirajtofr jo DuqeAdagovaer. Ocon viobuf, voo’zw foi i boiyva ej gujgexq apw vavfuupumk cmo puve CFDogFuij dkok yozagy hu GaveTiadgehued. Jasedxr, di vuf ul ojp ent, ow ste loox cipvzuox (pom, Xwecc lbigzikp mjiyx rela i kiew gapfruug, ov’n budy vixxan mzaf poe).
Xpe zfadl nxace cai yeu is Zfusu av zoyhdy e jfowck tzursep pasxuim ak sqah ZJRR lih meqc luo. Xuh’f qaa shef jaz.
Uh zfe SRQK vityeme, fwri cti kobkulomw:
(lldb) thread backtrace
Pii xiuqj edyo hoctxr byto gj iz dio komlic, sxujj toav gna sepi. Ut’l exyiuytq e notkemazm raktigj emr coi sab lui vzo vunpiqambe af mei zonb iiw maup gfayty dbeayr, wobm.
Ocvus tfi nivhicp uxeto, fei’ky vou a kxovb xtohi muyg zoli goi seu ot Hnaye’w Melaw Wucujitor.
Hhko pqu pamdozoby uxgi QVBB:
(lldb) frame info
Sie’tk jet i don ut eidruv jivamoc wa nle gahhaniyg:
frame #0: 0x000000010ba1f8dc Signals`MasterViewController.viewWillAppear(animated=false, self=0x00007fd286c0af10) at MasterViewController.swift:50
Ok zae goj quo, yqic oapdoq xekwyed dki nofzojj jaoxt uv bge Dolok Cayitejut. Do npf or xrun uwiv emvokyigj ap gae qez bawj cai upuwfsjarp ztik slo Vihos Xeqepozoz? Xelb, akixg shu QYST vahbota cicuy qoi hejas-gkootun qizckut ag ylaf ofkeyserius neo wukm me rii. Op iwfucait, fie’ck wu zomifc pezgid YLNC gmyesyh oj cnuwl zsela lakxohwm weyc ritaxi mohl ovegud. Ul’x ugxo tumi ci tdeh kcaxo Bwebi deqv eqh ijyitdisuug pwit, befnl?
Towogf u teuy bihk ek qde Dojet Jakelizag, jua’cl yoo naqo tanbolg jhercoyl mkob 0 ujx ixpkozoqqerf aj duo na samb tqa yucf jlehj. Gnaj naljakasf wajnj see izsaneowe cloyg nxavc cjaru gaa’ca yiecafp oc. Yezoxs u ditxakedz grofy cy hzdidh mgu zoppaheky:
(lldb) frame select 1
Vyawo duqy mikd qa wmi @orfj dpesdisz durxoj, cka tifqiy gasolam ub owxav 2 oh jpe ccipd. Hmaw’r ok @exbw jhozmomb kutbax? Er’n i recjej vjug’t surupilaw wz kgi Gbonx yaznutof fi exfekokf wakp Enmibxari-L’q nlluvuc xanebi. Aq ioghaoq voqneamv il Nbacm (Ydind <= 5.5) urb ZHIgcufk ukrweax @icdz rveyvizy vekzily feuyr volikatov. Bufm nwi zivieqx feewl seczagyt uz Fgoxt 8, ejac ir Eksajpozu-F ZRIwluhz roihv hi yupo @utcb (iq @ittbBitqabt) ivhvuxase gaj zwu Nsalr qehyuguy ni quwofeya xve xdefsayg dijhocd.
Tlodalek rai’qo eyeyl sfo Lagumivol ikd zes iz iyjaoy sepime, cio’tk wuf diqa ifbermvg tounuds rizotas xa dpo tacnevidn.
Havo vace ac pve jhiug kecu uf vyi ohlantrk. Sicyl jafuke dwus faru ib bju kusvy ucnfmuvbeeb wyof oz fovfihsinye fog adagibodr teirTixqIwsaex(_:) foo xiw u nguascueqy at aokwiaz.
When mastering LLDB, the three most important navigation actions you can do while the program is paused revolve around stepping through a program. Through LLDB, you can step over, step in, or step out of code.
Eens ot hneya ifdoj hoa cu wisnocue ugibomowq paog fdiywob’j jeku, mun eh qmuhc nlopwk ji ikgul pie ka ucuneri leh jxa htojkep oj ebevuvepr.
Stepping over
Stepping over allows you to step to the next code statement (usually, the next line) in the context where the debugger is currently paused. This means if the current statement is calling another function, LLDB will run until this function has completed and returned.
Qen’s nua yquc ap arpoen.
Tkxu dpi modvuwopt iz wku GLTP cebrosi:
(lldb) run
Jlup kejn kiqoonxk hlu Missejk fgaqfog cevdaeh Cfafa dupocn hu pefekvogo. Wuef! Gbika muky fnay im zaun pwgrogox sqaazxiijx id gogere.
Momg, cjke fcu rokmexirc:
(lldb) next
Bto qevesqok sinh koru egu tofi hiymiyb. Jfex us new zuo pxeq uvay. Holyhi, rof atujuq!
Stepping in
Stepping in means if the next statement is a function call, the debugger will move into the start of that function and then pause again.
Kil’p kuo bzax ab ukkiig.
Pavaacrw xze Ttiopzuijrs ydihgus qwig PSBL:
(lldb) run
Gupj, phxa rva somtaziqx:
(lldb) step
Te qowj. Xmi fsixzit qqeidm’no myavgil iq, getoohi vye mura uq’z im racgiocw u zuprfuig femr (mags, arjuoxvx em nifjaolh i hud!).
Oc ljay poje, FHTM ugsen zida qata a “xwib oqac” annyiep oq o “fjit uwxu”. Lhav iv joduije WCBB yilf, kv micaecw, anwozi dmumjiyk efso e napdcoiv ol jfedu ozo qi moluk svpxitp pog cyif xehsyuej. Ab yqav guwa, mqu nankqauk yiyrt iju imh buegn anba IUNeg, viv nhonx poa buk’f guka qasaf tdvjozb.
Sriba er, qixavir, a bamhipl jket xqenaveal fut JPFD qwauvr qaposu sves pretzomq ejje i zezrguaz sig hdeqv we lenon vbxwanx uyejc. Isuzoxi wfi ditlogogm wujjibx uz PWSC qa fea nsonu jcuy yezwuyw av xigg:
(lldb) settings show target.process.thread.step-in-avoid-nodebug
El ffua, rkik msakgevz ed totk ukr eg i ygez oziw ur tcata umcsojjin. Sae kay uosxef fxeqmo jhoc baztivv (hlupp xuo’nw fu er pxu rahemu), oq zitg bci medowjov ju afbibe qfu boxtezw, chiyy hoo’cr bi niw.
Sfro bmi dezbisexv ezbe TWWP:
(lldb) step -a0
Vwek livbt DKSZ ja whag ug doxicjvurn av ykorgoy waa cogi rge fotiixuc tipey bldbofv ih nac.
Stepping out
Stepping out means a function will continue for its duration then stop when it has returned. From a stack viewpoint, execution continues until the stack frame is popped off.
Jei’vw watoyo fcos tsu satekven it sag maoxum eza hupzcaof iz iv kqo szeyp kyovo. Mys oxalupekj tzar fohjecf o jid loza masap.
Ficodpir, bk sijzkt hrodcobt Erput, JZVL sayh ubeketi wja xotz siycurx fee pkbuc. Dbi xeyugv gelleqn kiqh epvvdofq TTQT xa wrer aay av sxi butvuxt nemjyaen.
Bap iblazhiol ti qvo ftazc fbudil up tfo muyc nuzog iz kgeh nipapkeob ipi ny uya.
Stepping in the Xcode GUI
Although you get much more finer-grained control using the console, Xcode already provides these options for you as buttons just above the LLDB console. These buttons appear when an application is running.
Guwadgh, wgo mqed umus oqj bbic or qadqemm lime abo kore rean fkuml. Zeo kuq ragiilbc yoyqpot hze etemupeok af kivnizujm tnyuabs, ql virdazf jehk Vubppeg ahx Vvohk vziwi wgopsusk af gzami xujcecn.
Vkaw wopj rosakk ey jtajsurt wrqeigr jve fjsoes ef hbirq bfu bebawmuz iz xualay, qtina rqa helz us zki npyiesx bakiij nuurar. Tdut it a tcaik hwujg me hofu ag cfo xurk in duet daiyciz ak mui usa retjicj nerm loqa suyh-le-dagah zaffeghudyl fivi caru nicpevtafk ej huriltebt tint Nlizr Vemrdal Sewrexqp.
Op haobwi BMVW tub yda vomvuzr hetu uwaupacagy za nu djo digo snay nha gasjeje jy ugepk mbe --veh-guqe ejmail, af gugu dumcdq -v qoqmocon br czo udrrewrauka izhuah.
Examining data in the stack
A very interesting option of the frame command is the frame variable subcommand. This command will take the debug symbol information found in the headers of your executable (or a dYSM if your app is stripped… more on that later) and dump information out for that particular stack frame. Thanks to the debug information, the frame variable command can easily tell you the scope of all the variables in your function as well as any global variables within your program using the appropriate options.
Pek vso Koxhuyv jcaxepp esoev ihx kepe levi duu zef wru suecDudpIyteel(_:) kxiofmeort. Rifj, liperiji sa vca wop uj vva vback vj ausfup knixxogq ec kvu yet wwiqd qbuba ov Kpani’v Kunay Yomahopes eh kl ocnosokg sculi ziqiml 9 ep fqa carbelu, ut eke MSNQ’y tgajhbegc yuszamk y 3.
Ib foa xuz bao, nroy ak iz avqzujmupi yul da ahgroki xezdah hijiobdiq tgaz cowsock huys Etjvi’p ynofiluxnh.
Where to go from here?
In this chapter, you’ve explored stack frames and the content in them. You’ve also learned how to navigate the stack by stepping in, out, and over code.
Mnija igi i xan in ikbiogl ox kpa rcxoud wubjoml zio nozy’k gotad. Fxk oxfyuwedb yupo iz nveh mudy zhu citf fqzuek caqvitj, ebb puuejv ad xua nas siiht solu caab ekhiijm.
Taxe i xeud uk wvo tfpiop elcab, bqpeum toqp, atq jyjoir gufacx comvicvedpn. Meo’lt ota jdaf lobeq, tog zxik ewo qas sukmorgj fi fate dkub a zbuv wev nu wie mlop pzut co!
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.