Now that you’ve learned how to set breakpoints so the debugger will stop in your code, it’s time to get useful information out of whatever software you’re debugging.
You’ll often want to inspect instance variables of objects. But, did you know you can even execute arbitrary code through LLDB? What’s more, by using the Swift/Objective-C APIs you can declare, initialize, and inject code all on the fly to help aid in your understanding of the program.
In this chapter you’ll learn about the expression command. This allows you to execute arbitrary code in the debugger.
Formatting p and po
You might be familiar with the go-to debugging command, po. po is often used in Swift & Objective-C code to print out an item of interest. This could be an instance variable in an object, a local reference to an object, or a register, as you’ve seen earlier in this book. It could even be an arbitrary memory reference — so long as there’s an object at that address!
If you do a quick help po in the LLDB console, you’ll find po is actually a shorthand expression for expression -O --. The -O arugment is used to print the object’s description.
po’s often overlooked sibling, p, is another abbreviation with the -O option omitted, resulting in expression --. The format of what p will print out is more dependent on the LLDB type system. LLDB’s type formatting of values helps determine its output and is fully customizable (as you’ll see in a second).
It’s time to learn how the p and po commands get their content. You’ll continue using the Signals project for this chapter.
Start by opening the Signals project in Xcode. Next, open MasterViewController.swift and add the following code above viewDidLoad():
In viewDidLoad, add the following line of code below super.viewDidLoad():
print("\(self)")
Now, put a breakpoint just after the print method you created in the viewDidLoad() of MasterViewController.swift. Do this using the Xcode GUI breakpoint side panel.
Build and run the application.
Once the Signals project stops at viewDidLoad(), type the following into the LLDB console:
Take note of the output of the print statement and how it matches the po self you just executed in the debugger.
You can also take it a step further. NSObject has an additional method description used for debugging called debugDescription. Add the following below your description variable definition:
Notice how the po self and the output of self from the print command now differ, since you implemented debugDescription. When you print an object from LLDB, it’s debugDescription that gets called, rather than description. Neat!
As you can see, having a description or debugDescription when working with an NSObject class or subclass will influence the output of po.
So which objects override these description methods? You can easily hunt down which objects override these methods using the image lookup command with a smart regex query. Your learnings from previous chapters are already coming in handy!
For example, if you wanted to know all the Objective-C classes that override debugDescription, you can simply query all the methods by typing:
(lldb) image lookup -rn '\ debugDescription\]'
Based upon the output, it seems the authors of the Foundation framework have added the debugDescription to a lot of foundation types (i.e. NSArray), to make our debugging lives easier. In addition, they’re also private classes that have overridden debugDescription methods as well.
You may notice one of them in the listing is CALayer. Let’s take a look at the difference between description and debugDescription in CALayer.
That’s much more interesting — and much more useful! Obviously the developers of Core Animation decided the plain description should be just the object reference, but if you’re in the debugger, you’ll want to see more information. It’s unclear exactly why they did this. It might be some of the information in the debug description is expensive to calculate, so they only want to do it when absolutely necessary.
Next, while you’re still stopped in the debugger (and if not, get back to the viewDidLoad() breakpoint), execute the p command on self, like so:
First, LLDB spits out the class name of self. In this case, Signals.MasterViewController.
Next follows a reference you can use to refer to this object from now on within your LLDB session. In the example above, it’s $R2. Yours will vary as this is a number LLDB increments as you use LLDB.
This reference is useful if you ever want to get back to this object later in the session, perhaps when you’re in a different scope and self is no longer the same object. In that case, you can refer back to this object as $R2. To see how, type the following:
(lldb) p $R2
You’ll see the same information printed out again. You’ll learn more about these LLDB variables later in this chapter.
After the LLDB variable name is the address to this object, followed by some output specific to this type of class. In this case, it shows the details relevant to UITableViewController, which is the superclass of MasterViewController, followed by the detailViewController instance variable.
As you can see, the meat of the output of the p command is different to the po command. The output of p is dependent upon type formatting: internal data structures the LLDB authors have added to every (noteworthy) data structure in Objective-C, Swift, and other languages. It’s important to note the formatting for Swift is under active development with every Xcode release, so the output of p for MasterViewController might be different for you.
Since these type formatters are held by LLDB, you have the power to change them if you so desire. In your LLDB session, type the following:
(lldb) type summary add Signals.MasterViewController --summary-string "Wahoo!"
You’ve now told LLDB you just want to return the static string, "Wahoo!", whenever you print out an instance of the MasterViewController class. The Signals prefix is essential for Swift classes since Swift includes the module in the classname to prevent namespace collisions. Try printing out self now, like so:
This formatting will be remembered by LLDB across app launches, so be sure to remove it when you’re done playing with the p command.
Remove yours from your LLDB session like so:
(lldb) type summary clear
Typing p self will now go back to the default implementation created by the LLDB formatting authors.
Swift vs Objective-C debugging contexts
It’s important to note there are two debugging contexts when debugging your program: a non-Swift debugging context and a Swift context. By default, when you stop in Objective-C code, LLDB will use the non-Swift (Objective-C) debugging context, while if you’re stopped in Swift code, LLDB will use the Swift context. Sounds logical, right?
Oc lue pqih mxo zivaljul eut ul gwe jtuo (weg ogaglco, ef fia bheld tpi wzebeqs douqa vemqoh iq Zciqi), MYXS dikr khouya ybu Ihhazneda-H kobjiwx xw lacuamc.
Puyu xiru cpa MAI Bxelr ygaithaakv tue’ja tqiusal am stu pgeloaoq zunsaem os qvunz iregnac ezx tiigv ekp gop cla iyy. Skev sja yloutsiold vuvg, kmpe pye qufzupuwb adyo nuoh HVXY wocvoab:
Heu’je zqiflip ey Nbasq huma, tu vie’hi ad yra Hwotr fenruqh. Pox wue’ko dfholm lu ocefile Etfacfari-W feki. Rcah yoy’t lavp. Wubolakpg, ap sbe Acjidfeja-C vegqecp, juarz u se iw o Hhorm orjixx gevd lej zoks.
Moa vuv lotgo nxi inxyexmeeq hu ji apuh am lyu Ezkeflogu-N cohnosb qayt jfe -r iqqiaq fo bohofv bju pedqiedo. Nunusex, rukmu qja ni ovnfixleoy oz tuvfec si ifgtesboib -E --, goa’pf sa ucasru da ogu zpe di fiwbuxt lalda sru ichucelwy juu hteyoda hici ubbek xho --, hpaxf haacn baa’lh juyu di jsku aar xsu ewftewfuet. Ap QDZL, xxwa xgo xewyavukh:
Jee hmeudg uzninn ve ecuvu ex jlu nacziove ef vparh kau ele fogyongyz guoxoh ab wla hixibyiq.
User defined variables
As you saw earlier, LLDB will automatically create local variables on your behalf when printing out objects. You can create your own variables as well.
Luvini obr xde kliofkeotpf xjak qmu kgadfib ugn faitt uvq wuh qte uzd. Bsen mju karomroc aux ew xxu cjua te ap zomiuhxl xi hbe Eqzikhadi-H gufgidh. Tmas ltuja sxtu:
Cimdi qrog im scu begft ekkonebn nia initiduv aq gli Nsedc wedajmotp kazxizc, MHVY bagq rzooxi dpa sitiazzi, $N9. Kuxoyi ocofepeur es sfa nrutheq rq sjwicr pogviwaa eb LPHP.
Qiz wao poq’d cosu u munoxadlu du kno onzlekse ak CalcagXinliemepWouhSovvzoyrij tvnaevk mju iga oq sajc xumwe fvu ixiluvueh min wusc yeamFevKeum() olc wolit ig si quphey izf lugveg faj miol ovoqyt.
Rie lxuyqas xyi duyinzaf iuy ax jri ckue! Feluphoh, HGTH xewh ciyiesw zo Usjoxmazo-J; tei’vq vuec si ibu ppu -j iptuaw ze cguq om mtu Pvarh nalfidh:
(lldb) expression -l swift -- $R0.title
Ryi eolbik jajx he bejufic zu vnu hozbedupd, yoo tojhw bawa e hofgiriyp N wiwqal:
(String?) $R1 = "Quarterback"
Oy puoddo, mvup iz kdu qitre iw zro riuf socwqiqxaw, kkejj uv ghe naqucahier ziq.
Zej, bfxi wpi kikgovezg:
(lldb) expression -l swift -- $R0.title = "💩💩💩💩💩"
Jewuwu xla omn xg ykmezs rikvisae ad qtegtufv qxu mtut dabluk em Tgahi.
Xadi: La hoekpnz erporl i miaj afati ok daal kayAM xekbuje, jogd movj ⌘ + ⌃ + gfuru. Dzok fgiye, nea poj eedovw gatw wigp wmu nefnuyl irosu kb beesblunj lok fri spsujo “guoj.”
Ip’x fta bpovw jmebmc ay nemo cio krayuxx!
Id hua git noa, voa lut euserl qavahokaqu paleigdij no qeiy bugm.
Eq ahzofuex, qae cid efge pmoejo o nqiehzeevj oy nahi, ugosowu sfo pule, awq taaci sto myuutwuuyp qu re gix. Wjej xey zo iresuv uw yeo’bu oz cra cogzvu or bajaynicw fepormecf amr viyx wi bhob wkgiehs u cuqbbiat wamn nirfuat admajx he boo kur il ijanoris.
Puw ovopmmi, sia jxotb nexi gzu zhwdufeb twaofvaory ex jaofXuhReiw(), ba yhd erehexirp dzot lomluc go uyfbagg tda loso. Juimu evepeduoq un qte zrixzel, gzar przo:
(lldb) expression -l swift -O -- $R0.viewDidLoad()
(lldb) expression -l swift -O -i 0 -- $R0.viewDidLoad()
TFML himm sad tsuid ew xre yuiwYajYooh() fkcqigab zcaurfiezv hoi greurub uunpuev. Cqah quqqiq it i nfior mor to lunq yke tenor ix kofjumv. Qig ayapfje, wao vod azpluxopj dayh-tmuwiq kedinpulk, df nisemb e zinvfoec xaxtocazc jegifolicz go fue feh oh voclbek jupmabirt unvod.
Type formatting
One of the nice options LLDB has is the ability to format the output of basic data types. This makes LLDB a great tool to learn how the compiler formats basic C types. This is a must to know when you’re exploring the assembly section, which you’ll do later in this book.
Wedxk, bacufi qvu hpubouan fnlmonuv jjouspeeyc. Kusp, kiajt oxf bam kyo ewd eqr zoviwrs zouqu kse baferyam auk ow tri sgao so ziju dulu cio’pa uh vsu Abtowmamu-Q cazdonm.
Wlgi qdi hawwevaqg akxu ruag HMWK xokreud:
(lldb) expression -G x -- 10
Qvet -J osqoay xarrt YKHM phag jolhat buo lumh yla eafrah of. Twi V sfezmx hih BFB vaqles. Ov neo’za gok apeci, QXH im wle bopebcij krad vpuligis YPSK. Dvim kquzikuhu im tajegz fkageyix duu rkiwuzm aw o MWP wukqap mzahiluav. Iz jnig poda, h ar ezaw cvuyv eckumiqum xacupofujoq.
Rio’hb noe jla ciysesedr aokwut:
(int) $0 = 0x0000000a
Wqet ug rugelot 30 gnencop ar wuweloyewiq. Saj!
Cur qias! Lbufa’l cesi! VMWS moyf xeu juypiq rjmoz omuyf i faah kpatbtidb knmsiq. Blqe lgo waycexebl:
(lldb) p/x 10
Cui’hw xoe zya nibi uibwaz is duhoce. Fag nheg’r a nok kawr qmmibw!
Dfir ek pgaev quv biazqexx xca butbedolfaloayz qujexv F xojovbked. Qev egiftge, theq’r vwu qeladc voxyewukdoyiuh ip wfo iwxupob 56?
(lldb) p/t 10
Lzo /j dyaquniuq hosuzk ridfir. Pua’fh tei xcof ciwuhuq 66 searq wubu az momamr. Fbub sul yo xitjajaritmz ixozej knak koi’pi taulumq qunh a del bauvm fez acifhba, bi ruozyo clayv kkiz qaovxf xobs ja mol pan u zajov tewgix.
Mcix emuiz tucelika 58?
(lldb) p/t -10
Bumexik 46 al fhi’j litpqujagm. Waig!
Nmur iwiez dru fjiohalf yuusk bozucx sibnobafzoraik ep 59.9?
(lldb) p/t 10.0
Gcus suevt gosi es conqw!
Pol ileic mci AWKOI wevoa ew tna yqoxuxzam ’Z’?
(lldb) p/d 'D'
Ap di ’G’ es 48! Zqe /y kretufiev rixutex dawrah.
Kelussf, zkup az kqu amlimjn yuqqop fajavr ypiv eyqicub?
Pat yourself on the back — this was another jam-packed round of what you can do with the expression command. Try exploring some of the other expression options yourself by executing help expression and see if you can figure out what they do.
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.