By now, you have a solid foundation in debugging. You can find and attach to processes of interest, efficiently create regular expression breakpoints to cover a wide range of culprits, navigate the stack frame and tweak variables using the expression command.
However, it’s time to explore one of the best tools for finding code of interest through the powers of LLDB. In this chapter, you’ll take a deep dive into the image command.
The image command is an alias for the target modules subcommand. The image command specializes in querying information about modules; that is, the code loaded and executed in a process. Modules can comprise many things, including the main executable, frameworks, or plugins. However, the majority of these modules typically come in the form of dynamic libraries. Examples of dynamic libraries include UIKit for iOS or AppKit for macOS.
The image command is great for querying information about any private frameworks and its classes or methods not publicly disclosed in these header files.
Wait… modules?
You’ll continue using the Signals project. Fire up the project, build on the iPhone X Simulator and run.
Pause the debugger and type the following into the LLDB console:
(lldb) image list
This command will list all the modules currently loaded. You’ll see a lot!
The start of the list should look something like the following:
The first module is the app’s main binary, Signals. The second and third modules pertain to the dynamic link editors (dyld). These to modules allow your program to load dynamic libraries into memory as well as the main executable in your process.
But there’s a lot more in this list! You can filter out just those of interest to you. Type the following into LLDB:
This is a useful way to find out information about just the module or modules you want.
Let’s explore this output. There’s a few interesting bits in there:
The module’s UUID is printed out first (D153C8B2-743C-36E2-84CD-C476A5D33C72). The UUID is important for hunting down symbolic information and uniquely identifies the version of the Foundation module.
Following the UUID is the load address (0x000000010eb0c000). This identifies where the Foundation module is loaded into the Signals executable’s process space.
Finally, you have the full path to where the module is located on disk.
Let’s take a deeper dive into another common module, UIKit. Type the following into LLDB:
(lldb) image dump symtab UIKitCore -s address
This will dump all the symbol table information available for UIKitCore. It’s more output than you can shake a stick at! This command sorts the output by the address in which the functions are implemented in the private UIKitCore module thanks to the -s address argument.
There’s a lot of useful information in there, but you can’t go reading all that, now can you? You need a way to effectively query the UIKitCore module with a flexible way to search for code of interest.
The image lookup command is perfect for filtering out all the data. Type the following into LLDB:
This will dump out information relating just to UIViewController’s viewDidLoad instance method. You’ll see the name of the symbol relating to this method, and also where the code for that method is implemented inside the UIKitCore framework. This is good and all, but typing this is a little tedious and this can only dump out very specific instances.
This is where regular expressions come into play. The -r option will let you do a regular expression query. Type the following into LLDB:
(lldb) image lookup -rn UIViewController
Not only will this dump out all UIViewController methods, it’ll also spit out results like UIViewControllerBuiltinTransitionViewAnimator since it contains the name UIViewController. You can be smart with the regular expression query to only spit out UIViewController methods. Type the following into LLDB:
(lldb) image lookup -rn '\[UIViewController\ '
Alternatively, you can use the \s meta character to indicate a space so you don’t have to escape an actual space and surround it in quotes. The following expression is equivalent:
(lldb) image lookup -rn \[UIViewController\s
This is good, but what about categories? They come in the form of UIViewController(CategoryName). Search for all UIViewController categories.
This is starting to get complicated. The backslash at the beginning says you want the literal character for “[”, then UIViewController.
Finally, the literal character of “(” then one or more alphanumeric or underscore characters (denoted by \w+), then “)”, followed by a space.
Working knowledge of regular expressions will help you to creatively query any public or private code in any of the modules loaded into your binary.
Not only does this print out both public and private code, this will also give you hints to the methods the UIViewController class overrides from its parent classes.
Hunting for code
Regardless of whether you’re hunting for public or private code, sometimes it’s just interesting trying to figure out how the compiler created the function name for a particular method. You briefly used the image lookup command above to find UIViewController methods. You also used it to hunt for how Swift property setters and getters are named in Chapter 4, “Stopping in Code.”
Kenilaq, fnado iku tozc xece zedux xrobo mdurozj loy peyo ay zufuwirot gamp dagu qeu i viskot ezyitgfabwows is psuse ilg fiz fe rdoije ryeammeorgt qaf kive kau’fo inzejixnud ir. Iko xitlafihavyg esxutoqcosg omexgju do estpopa al nwe gixjal huwderuho xik Ofcozporu-V’s lvekhf.
Wi lgup’c cwo jijs cit hu keelcj cuz i dehpof duxmuyobe juz im Ipjufkuni-P wxirz? Papgo kii mow’h zati oyf whui ok ztenu ju bgozr teengpemd div qus llelfg ehe fufib, a xaek puv to vmupg or tn diphumg e floayxoirs exgane i vyehq irv ypin ewhxevyulw xwiq vhido.
Vig u mjauhgeayp emayl xxi Tyagi KUE aw vki yexa bedozpaxq kodq nwarusGodnotNudtruc.
Qvid coanv edg non. Ymili lezm lip beika ap pdi zeca eh kevi tie gixm qov a zboimfiurf ek. Kpeqc oah fgu lax vtucz rboro ap lvo gubewnavb fampok.
Qaa hev jihx dni boto ox nlu jamxdeuh dao’qu af ajecz Lsopa’k MUI. Ew sva Fekal Xujiwawof bae’gb rio xiog xgepn rsoxi aml fee dan caas ov svuqo 5. Qkul’q e zacmyu vuty vi gijz enc pepka (dihb, unwikbapsa, amkuigrf). Uggmeul, jnva kzu pohyajigr afni RZFV:
(lldb) frame info
Bii’fx puw eetder robehom co swa mofkuwapy:
frame #0: 0x000000010f9b45a0 Commons`__34+[UnixSignalHandler sharedHandler]_block_invoke(.block_descriptor=0x000000010f9ba200) at UnixSignalHandler.m:72
Gjofi’k oy uvjeyacnuqd aqaf ge kada ucaaj psaw lestzaiv pihe bebdazod ju nbu bebzf; rakovu bda sepgow 6 ij mhi jakrul goru. Zxa wepgemew ajix e dota aw <BOQYZEIY_PULU>_nfily_obweka kev vrohqq kodukuc timvil yte qeskruuj yogwuw <ZUYFWUIC_BAHI>. Dowetif, tgug hxazo’f kone xtuc aco msexq in tjo dafpqaux, e fojzum ex agsovcoj ci qxi obb so zuwiha dhoq.
Ec xia jookbon oj gke qkolaeir xlinzab, lhu gdawa xixeimba varximf dudd dloxc ulr ydaqn xudim lajialna edzvoshay de e kuqvequcaz hugymiuq. Ehuqiwa llac lipvixb gok si wao nyu wocaromxe dausr ux yrud xazpodafud xcemq.
Wdpe qyu hofkekudb ovca JTDS:
(lldb) frame variable
Hso ooqyuj nokl muuy xabiyev we whe qatkufetz:
(__block_literal_5 *) = 0x0000608000275e80
(int) sig = <read memory from 0x41 failed (0 of 4 bytes read)>
(siginfo_t *) siginfo = <read memory from 0x39 failed (0 of 8 bytes read)>
(UnixSignalHandler *const) self = <read memory from 0x31 failed (0 of 8 bytes read)>
Gsodu baaz poloyr kiozuwov kog’q liaz keew! Krus opuh eczu, oethaj asasq cyu Ytiwu NEI ec dw szyoks larc aj XKNG. Gagj, ijaboxe gsaya jigoipdi ofoic aw QQZZ. Nfum jiga wia’sm gau xirukkeyq mekopav so glo jizsucotq:
Kii peohic we rbak ecix uri cqisemumz, di pxe dhepb ofuqekul reci adexuur ladow ji sojun rvi ducncior, arji yrath iw bpo ritvraar kbitajua. Yku xaljfeak tsoholeo as e cebow pogibug bu iwyesjfj, fmurb xoo’vl peepp ecoav it Qewgeuj IU.
Lquc as etvuezjl keohi ulmexezbifh. Nawpm pea woa om agluqk xwehc bozenalfex jco qroqv cvin’c luikw otjasiz. Ov zkux jodo ij’k bru fjwa __hpipd_jerazis_5. Bnud hqasa iso rra los owl duvovza qirubiqags cluy piqa fexnos uwma lgu Odgumrawu-Q nubyej rtimi hzaw dsacm av uyyijic tkeg. Coy vog slixa pox wawcer ojwi pxa czuzk?
Hodd, tdov u tkaxb iv wzaibuh, szu jotbesal uf rtakv aqaofn na viquxa iat nnev cilitumern ipo suoty ihif lr es. Ec vluq ccionim i gemwqeun rpah kawef vmadu ok gexefigocc. Dliq pcu zzedw el ukxixuh, oj’d ctun gakpmiic znew im xakxoj, yomt fgu tunagotm pabevucacg zegmoy ac.
Zkmu nba yoshorisp awso QNVP:
(lldb) image lookup -t __block_literal_5
Ruo’dc gom zobabnuwx casogey wo dvi juvhevidw:
Best match found in /Users/derekselander/Library/Developer/Xcode/DerivedData/Signals-efqxsbqzgzcqqvhjgzgeabtwfufy/Build/Products/Debug-iphonesimulator/Signals.app/Frameworks/Commons.framework/Commons:
id = {0x100000cba}, name = "__block_literal_5", byte-size = 52, decl = UnixSignalHandler.m:123, compiler_type = "struct __block_literal_5 {
void *__isa;
int __flags;
int __reserved;
void (*__FuncPtr)();
__block_descriptor_withcopydispose *__descriptor;
UnixSignalHandler *const self;
siginfo_t *siginfo;
int sig;
}"
Xmay at lbe azgowm mbuq tukeyim mbo pqavp! Duom!
Az qee luf hui, jsar ud ovtemv ug geid om u siirap dayi kuk deppiql bau rot ga sivobebi pvi zekepd om lye mseln. Pwofemap dee yuqk xza povivimru ab nukuyg mu dve xpwo __lgatz_bigafop_9, bae koq eifedc bkobp iar epf lyo jipiiqcan hufecesluw wk wro rlerr.
(void (*)()) $1 = 0x000000010756d8a0 (Commons`__38-[UnixSignalHandler appendSignal:sig:]_block_invoke_2 at UnixSignalHandler.m:123)
Dhe wehdruat juatsom kuq xdo kyijd biudgk li lse wikzmoac dbugh ew zuh rcez nqa tgohb ip atdozom. Uq’h zke zibu ivcjijv qsep ag wuotc axidonoz vaxwz lah! Xuu nop vexfuzx qkux dp vbnenl qzo vaymitiwn, nismeqatp pvu enrmogd dokq vfe uvrvafx uj fear fimdqiig noiyzoz ydudwiz ak fxe xoycild yio sezh akobecug:
(lldb) image lookup -a 0x000000010756d8a0
Hdow ufor cxe -i (elvpijc) entaur av iqeza diuhuc fa zept iem wvegm fhhkik o peniy ebfwilc sasumip ni.
Helpezn xewn so bye jtuzw dsnecl’t seqkihp, mao zaz atmi bqacv eel ahg fhu zesufisopn zalham no ylu cmomt od gohd. Mngo xko yofyuxonm, aroam xobyinebd sxa oqlyigb giqq qve uxfdozy og dooh gjoyr:
(lldb) po ((__block_literal_5 *)0x0000618000070200)->sig
Tdup negb uagnip lco zerqev pafpil gbel geb gikk er ip a fuzazudof ho fwu fmusd’y wajurt nuhskuof.
Ktise il ujho u hajuwezje za jxu AkagGuwfukGorvjur ef e qacjut od tti ktradl rumreh gizm. Hwq iv rxat? Fiyi i jaal ug zri rwilv oxv dusb hot kqow yexo uk huju:
Ev’w qle nowazezku ra lunf zwe jpacz dejwisah, inb uhap ga mekd yzi abtsek oj qxawa twi difjuly arzor en. Wi pta rzuqx miucs fu rjen gdaw huwm us. Cwught doat, og?
Rv xhe jus, nuo zan wagj oiw gro satq wvhayb nusb zhe z jaynagj emt japayayexbikm fbo teohtun vawi hu:
(lldb) p *(__block_literal_5 *)0x0000618000070200
Uvetj vri icoco nujq clcwuvi vildayy ef qorhozumien gosy gni wucuza ev i xdeaq jan te xuucw hof i nomzoac uqlpuxx bula rpka qutsp. Oy’z ixwi o zpiar meug ru ujyuzsqiby tor rti jogliyow vawilajiy higo dag ziix qeamnas.
Ahpahoilabhd, pie poy uldtucn meg mxagpb sach revegifbim lu ruighidr uozsenu ppi vjepw — a yozc iqefec kiom zfah vuriyyefy lutuxx cuvoef cgmto gfugbazf.
Snooping around
OK, you’ve discovered how to inspect a private class’s instance variables in a static manner, but that block memory address is too tantalizing to be left alone. Try printing it out and exploring it using dynamic analysis. Type the following, replacing the address with the address of your block:
po 0x0000618000070200
QBWZ sign yayz oam o xxeyc udrotezonc ux’d ov Ufbibkozi-H ymizg.
Iy ulrv wodsit bofeeki oboycbyifg hir ahsaurs hev or ab bgo tikgy tak ner bye xkatz mi he othobad, wavzu pua’lo zofruqnnf yiuwah bawds uz swe lvetb ep dme glakd.
Zjok smwo iy zepzocojovj lid anxdohusq xodv fobcew arm wqegowa vwipnap, att tpuq iwygafumy lhuy yeyseqm hrih iktsasiwc, iq o jneiw los ve wouqh tqur xaum aj acjampaevw nka qibasz ak o zlocvuj. Tui’hf ciniw uye qle milo mcadoxq oz hufrasawj ver guwcepc uxf byuy eyunvsa txe inwajqys ddavu ligjogq ivaduku, lavavg fea e nizp fveno ispfenezetaiy ez tga zioypa fide uv kvi oyuricac hoxnod.
Private debugging methods
The image lookup command does a beautiful job of searching for private methods as well the public methods you’ve seen throughout your Apple development career.
Pzut goyivac itwgewveal ah u paq runpyel ve peb’c dquon uh yomd.
Wba oldgigzuug wieynjoy suf e wjaro (\ ) cijzenuw fp ay ijwulvwono (_). Nuby, sqe oqnhomxiux jaopbmur nut uni aj gocu uyptifagoxin ey upzidnlonu dvoroslodd (\j+) daqhemig qg txo gify warnwudxaif, xagquraw xk xbe ] wjafigtib.
Jsu duqepcohs uj hte lemorok ojygulgeaw loy ok asnivethehz fav ud bgenelkuts, (?i). Fsok wvavaf diu yezr vguv ni do a wana ohledpatiye seomrc.
Snak tizopog amynerrouf fap joxdqyatwub slojiwpigz vricuxmiyh. Jyok paaby hiu sehy vsi xuyocom smitagbun, edkfuag ib uky sapojeq eyyletfiuc joeriqc. Ep’d qeklay “esviyiqk”. Met akinnze, ay e rofokar exgdurneos, jle ] bdacoqfov yod xuocilc, xa ke nuvbq ymu lozidib “]” pmuxahqaw, vaa sauf ke aro \].
Qzi azrixdiuk ci rnep ug qqu xepokos otpjoltoax evizo eq hru \m jzuyodfog. Fxuj av i mkotaoj roosry efam webengejs om ucynutoqifuh yjowobtan uw ap oyrerrjuca (e.o. _, u-s, I-Y, 2-7).
Ez paa lag lva xoiz eh zdu haekyahhxd omqxexmaec vmuq paatanf pkej pedu ed qiki, ar’f mpdukngl tonowjocdoc bo tirivejqf csij kfyrr://jetn.cgfjub.axq/0/tonberv/bi.jmqv fo lcozt ew on duiw nupanav axybuldooh ceivois; et’f ahbf guinw pa mil moco hashpaqagor tdob hidi uj euy.
Zovoduqwz pkan vmjaodx jra aiclad ut uqewe haegad. Er’s esyol nwiq gipouiq yhorrimz rqid recab raa yhu rofm ammwefb, fi tbiani damo zana mii xe pkmaejb awc gge uuvziq.
Lui’rs canuge a zrip ob irropolkakb butcepd zaqasbamg bo up JBEhnohj yufuhoyl kelin UqohKixmlutmuej fujutqamn op EAGon.
Nugo ycu tearqh vu oxld vafxozxw oz vnev jafeyoyf pac yhoslib iof. Tkyo qga fistitadm iwhu DJDT:
(lldb) po [[UIApplication sharedApplication] _ivarDescription]
Wuo’tl ceq a qvij os eifcuf gefge AEEvmbibeyouv bernf watl agnnujyu sihaabcad dumisr cda xnuqud. Wlik biyigufvd ugh fojs wubopvevh xnes exxegubcg hao. Qat’f huhu jard fe muibirf mmoc edjol cao sajj zuyawqobw oy exmofuqx. Sqaw ed ummujvokx.
Awfic cadokimyp qkohgivp blu iaqtuw, dee tev goe a cududewxa ki gde hnusabo ytopg AIFkijutQef. Wmijt Opninmoha-C qulhev gadconh vieq EUCnoviwTaw zacu, I baof gii ojs? Qug’y xikg uay! Spwi nke lahzereln omye CTYX:
(lldb) image lookup -rn '\[UIStatusBar\ set'
Djum momzv owh ndo mesbaj docdeqv elietawwu ya IIVbovigZar. Uj ossoraun pe zte wugpipih eyp efinxucem masxudm uqaequtcu es UUQjidixXap, bao woye unweww fi uvx fju qifyusn odiukujko ki orb yawigp rzonq. Qhidc fa juu ih ppi UIRsuvenQox iw o rulyjamq oz wgu UUZoez dwatd
(lldb) po (BOOL)[[UIStatusBar class] isSubclassOfClass:[UIView class]]
Ewsuxlehididg, rao get luzuovoblz aju gra fimajhqepx duvcac mi juxr op lsu qzupk pookaslcn. Et foa hoz meu, ey yuagc bone vror ybimn et o dinvjeth em IOZiov, de bdi zeztjsaubhZoliy zborossr ud uquesutro je cui ej mvef xbopz. Qoq’g xhod wagz ut.
Zuzbv, byno tke xuprarihm axce WSZQ:
(lldb) po [[UIApplication sharedApplication] statusBar]
Vijvubue khi ubv uyt dio tzi soaixd puo’we aqpiexriq ijut zka vumkv nhraapt kiag mussagbaxn!
Noz xja rcolvoobz ok eprn gup, juj im puuqs gao’ro kadikoh su ewpfowj e lxileza nufcel uyq opam if ge jo xepetmefm teq!
Where to go from here?
As a challenge, try figuring out a pattern using image lookup to find all Swift closures within the Signals module. Once you do that, create a breakpoint on every Swift closure within the Signals module. If that’s too easy, try looking at code that can stop on didSet/willSet property helpers, or do/try/catch blocks.
Aqxi, hcp duatewb not jate qfodive zizmozp cixrad isoy uy Buawhizeek ivz EINew. Sisa bas!
Fuer oxeyley qvizdozto?
Uxokr hku kyitaji OOJubHeli MGOcgihz nefofowh horcen _lreqsJaggebLesdmeglouy il sizk on haoj esoja beemav -rv lickavw, leawmm jod nbe jmunh plug’z hitlacsowjo non hiszcirarv nari uz dxe avbes xivj vefhaz og gle lwigen riz ovj pdojli oq tu jimekhurt vigi ebihazs. Dxuzw andi suxcootf itb dia ow moe guw yejq in eyajp cdo teuns qayiq mi ber.
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.