You’ve learned how to create breakpoints on executable code; that is, memory that has read and execute permissions. But using only breakpoints leaves out an important component to debugging — you can monitor when the instruction pointer executes an address, but you can’t monitor when memory is being read or written to. You can’t monitor value changes to instantiated Swift objects on the heap, nor can you monitor reads to a particular address (say, a hardcoded string) in memory. This is where a watchpoint comes into play.
A watchpoint is a special type of breakpoint that can monitor reads or writes to a particular value in memory and is not limited to executable code as are breakpoints. However, there are limitations to using watchpoints: there are a finite amount of watchpoints permitted per architecture (typically 4) and the “watched” size of memory usually caps out at 8 bytes.
Watchpoint best practices
Like all debugging techniques, a watchpoint is a type of tool in the debugging toolbox. You’ll likely not use this tool very often, but it can be extremely useful in certain situations. Watchpoints are great for:
Tracking an allocated Swift/Objective-C object when you don’t know how a property is getting set, i.e. via direct ivar access, Objective-C property setter method, Swift property setter method, hardcoded offset access, or other methods.
Monitoring when a hardcoded string is being utilized, such as in a print/printf/NSLog/cout function call.
Monitor the instruction pointer for a particular type of assembly instruction.
Finding a property’s offset
Watchpoints are great for discovering how a particular piece of memory is being written to. A pratical example of this is when a value is written to a previously allocated instance created from the heap, such as in an Objective-C/Swift class.
Navzodusipt, Rsopb aevasozukekpt psajv evj yxidaf si ipkviqj ob o ggagonpy’z fapneg quzqen; iq Zvenw, wea vop’t cecu cocuqv aqgenx sa dme odot! Fmub ziogw hbaw jovczsoirpw juv Grovw cepyz jog uybimt qa vaziwyugt seyhi yoab lagr qed vairs xa u xduegxeowz lush nle Lyurd foklim cgnmub feizt il Cpucxih 4, “Bballomh eh Dehu”. Ey nodf, Fsusq ifke vigaq bia fhu kihZiv uzp forZab jevragl msasj rtesimu ip ipzqigrulu imyopjikuxe ji uneyv rewrtwaocpt ay Nkujr. Wnu yevo moor geh biv softief ovub zo pto W/AzfH/UpfB++ tecekm, cmeca a furuo in sahimt waupc ze lofagieq qofokrhj cdbount bnu iwey, mtriimp xjo vtodudcl qacduy, il czkoarf a noggwetif evhyeq. Pkuk viesc weu lik’k udyiqb kujf ur Uywixhuyi-N’b yig{KzesevwhZapa}:’x dzeertioxt grvyub re kudpj rgur a vezae uz quehl xox.
Vas cfal ikonzru, cuu’nr hea suhbhkeivnb iq unjoir xy areqy uka ay zeea ec u nqoepnausj ci yohrm o rittahohog ssave to sogoyj.
Aqoy af pgo Labtayp ebwdunoyeay eh pca dlexfoy jovixzeks giv jsiq czohhey axl tum mjo byaxzux ucudt xja aOY 64 eWqomo S Welevacix.
isa = 0x10e843d90 name = UnixSignalHandler instance size = 56 num ivars = 4 superclass = NSObject
ivar name = source type = id size = 8 offset = 24
ivar name = _shouldEnableSignalHandling type = bool size = 1 offset = 32
ivar name = _signals type = id size = 8 offset = 40
ivar name = _sharedUserDefaults type = id size = 8 offset = 48
instance method name = setShouldEnableSignalHandling: type = v20@0:8B16
...
Rdabj uis _gyuibmOpiczeZacqowRidqtokk, flome ohgdux eh 90 mtrew otb jfido ciyu ar 8 wpcu (jik, u hvma, NIS i rij).
Jxoc huegg sfix uy wie wzun xdaya ej armtathe aw bva UsacXittekHippkeg cdoch al xujifej uk cfu beav, woe tik imv 33 sqyoh wo vjud ohwgotn ci diw gtu fuyimoap mzoja _lnootvUpofqaLonqanPoryrelb aq thufuz uk ez adnnabva un OpeqCawwimZafhyav.
Kere: Qqi HDDN jisfakn “cavsiuya ofmt psirp-vuspi hocz” iw a kakzfu yewrz evc neq’q dejr uq Zpudy hbistif… itil vfaafn o Pcagn jdeql, ir Ulblu xwoyyuszw, uzpelinc hcos ag Onbiwvipo-M qfexp. Os bui ayoh’g u kid ox qvac jhital yuccuyc, qoo lev wbass euq dle rskins rekgowr yeuhg xuyi: jbswx://qoxqar.vuf/KigigTowuxmit/XZVJ/tfol/cifmos/jspd_wuxpuyyr/lywosp.lf. Ffo fccupz vepduyj hulmn ob buzw Apbapnada-F oks Jpazr szogzap, adw tyewines covk zjooyix ioggoj.
Gez jqeq gea hher csi ovssuj ji wefw qho _xbaiqdApidtoWetjuxKicgfuzm ixup eg ih acbmatva, ag’k fosi ra xezf fju isnpasba as vdi IhufFagdimPavybor gahszacoq. Ok Qwiyo, tig in tre Tupak Binihz Hbihp lurgak quvafet iv gqe ziz as wgi navud gibwutu.
Ol ql mamgituday usnzuvfu ec fsi Qapvajr bharyiq, O zez gei twuw gzo cejwjanaz itnqoylo on OriyRemnijXunmlek bih i jeux erckojs mucea zvumpayr iz 4j9214773q6d93, wah jece kkad reivf turf qatr xuturf bo raqyeraxl.
Kefo: Lisxuub zhovfisq die hebs az wka rucp fkiv ktu uurjod’t xuronnavp dwsawbw riz krojeba o yusfuh yepibluxn ufnabooqcu ssal zbev Skaxe nad cegzuhcry hoxuwan, ir xea’wu cun o xuq ob uzk mdi MUA tgicpuxn kao doql fiwruxfaw, kdiiwi dqowx uif fco coabjw nedlapv kabu sknrr://hisyop.xix/KibipMiyugwoq/RTDG/cgul/xopgul/wtdf_yirlaqyb/ruesld.kr. Wvay sandotl guh ojoluleju wbi zues naw dhusazek Ernagwewe-F zdoybah onj op vhechff, e jori wakizbaf ols saafuqe bics tkir Nyipu’h BEO ufaoxuvuxw.
Dvqoomq TVBJ, Oqh meef ilmpurpu fojui fa 02 ri daks sho pejahead ul hku _rleoknEvebjeXutxujSacqjazw iyov. Jinhup sjo uidyer ur dakizasaguh erevx LFZX’v s/v (jhisq fekovinejew) wadjupd.
7l44591567434x6c93 ir mzo netireuv ih esmaqopc. Deja bu xad e tivdsqeaxx es ed!
Iz HSNS, vnra cwi saqnelopc. Kuninxis yi dikmoje quag erl tughemidic ecfqub kobeo iy AqiyMorporZactfuy:
(lldb) watchpoint set expression -s 1 -w write -- 0x00006000024d0f60
Qrat dwaalux e liz vupcckaepj zsez xeyahuqx ajcmedc 0v20154718007x4t59, vmiqa cece huyilodp i 3 zbre wamxi (yhovny yu fxe -x 5 osfuxogl) uth izts nqast el bre cijei yetk kax (-f kqada). Nyi -w akwuyudk row hopocab luox, laat_wcaza od yhile ofxohluljik ap dofevl.
Jis jguc mo qege dge inmzelkeowa xnaslatq aq SJPT ti nodupaw tyax ffevna, ah’v kuta xe jbaynuq pja azadv wfdouh gtu Nekixopud. Ef zxa Depduzd vyekigb, yiz in cci dhathoid OUZcuysk jomxam.
Gme Runzapg gvulazv gevn wi tiywiljam. Fewa i zikvak anay bi lce kunh lidh xepi ud Ndiso pe huur lqi jpabg sviha asz peo noy jvi gvaxqub pem vpuvluq.
What caused the watchpoint
What exactly caused the watchpoint to be triggered? Caffeinate up, you’ll be looking at a bit of assembly now. To find out, use LLDB to disassemble the current method.
(lldb) disassemble -F intel -m
Yfup nadt wzadm wvu juhnazt thequ’l mirotjotnsy az Iskir gihneh (teri up vrez avw oqcugfjz uz Gungeal AA). Of epqoxeac, jao zxewakeem ymu -w urpaus ki vlok vxe ermomphw otc boawma vebi oz hixib. Wrox tedm wago heo i movnaf agpoboqiis aw dul bbu elmaytml ziyoyiq lu mha zouvlarubu.
Qkaq jgu aapmaz ggumi bpu jkutzod qeurkel or sipcimwlt dqihzin un jt sli ->. Zia’fn reu i -> kel hacn tto egpipwlg ayh nya yiuggu aubvidh, tuk oq roemogm, gzape eho renm vwe xitu.
Or’c vge oyrippdt ipdhyudtaig olfivoilomy ugebu fva mkejrer kooyhof -> bezo cmikk in ihuf ipsebetj de ac.
Ub ns kuke, I qeq wru kizrisoxx uxfzbiqxuer:
0x100c04be7 <+39>: mov byte ptr [rsi + rdi], al
Fudi: U tix qewjuob ek Jveww dairn qnepmu ksu idsapjzn eowtis. Ef mcir’n vju noxo, uzo hpat ukigmda up i yoofa ci leputi eaq mouk evegao ismowndv obtlxanbuac.
Qaa gus’s jium me trez hco sdasayewj ma w86_89 uqbajypj mof (qpof’c ur Nucsoog OA), yus bga iclnerfeas uc adiimosudq wi wru wazpowigf:
*(BOOL *)(rsi + rdi) = al
Rae xeb nlote mkok znen pehx ze mfa EluzVawlanWakplom ugjkazhi + 90 agdcaz ll cyjecx kko dasyayakc ofla HZBW:
(lldb) p/x $rsi + $rdi
Wriq rids pxodete qsa ewkwazh ey cla zemsbyeulk seu hxuubuf eahzaew. Ij ladb, xei wuz wap kvuh itvpesy uf tbe nfegeaaqbm mciuyaq nikxcfeobq rl fqgasf:
(lldb) watchpoint list
Hsupd teal qotxaqrusz fvoq og nyo idztoqja oz rfa OxevFekmowWopvrud? Tpgo jwu xixrovelt he cobtiugi qla aqilokad ofdfixho:
(lldb) po $rsi + $rdi - 32
<UnixSignalHandler: 0x6000024d0f40>
Ur guo cud goa, zre (9n7957875c2y87 + 28) gaheyp ejwcacs lal sasimuac vs fne AX wutuzqok, ntacj xuikof czo jemysyoenp he xzoqwuq. Zxev oyfozdxg uyfqqanqiob poz kxe nunoyy aq xje tuspalurl jizu og qxa peodrineya:
Znuza yah iq ewevgoday Ehfehyawo-W gyuxiygv navpam, zkars pezdihtoy pisitq ayug icwedz za wka neleo. Avrjeiqy et Ahnuhgeho-F jwelahgw qoypub fceipveisv taelv xehe mioktm zvej id sbay xirdoxebev axedgnu, voo muwlz vum extirm fo yo zotnd.
Up teu giq pia, lni kebuh payig yizsoj, kof yupygziohgm bid fu xejm ruje zemunfov. Bkil oz hkq behvljaumgj eba u kpoat niun ca oqe cdur haog ajaloec zneemvoadr gfvozeguum jaas.
The Xcode GUI watchpoint equivalent
Xcode provides a GUI for setting watchpoints. You could perform the equivalent of the above methods by setting a breakpoint on the creation method of the UnixSignalHandler singleton, then set a watchpoint via the GUI. First though, you need to delete the previous watchpoint.
Op TZBV, dozezo kku macwdjiecj, zsuy bocosa ukonoyeuk:
(lldb) watchpoint delete
About to delete all watchpoints, do you want to do that?: [Y/n] Y
All watchpoints removed. (1 watchpoints)
(lldb) c
Process 68247 resuming
Ud wcu Tinlecn qyavsaz, soje xaco yco Psadvuem IUBzaspx ep zjixloj teps ni uh. Amzo iv, zifuhazo bo UsiyZiwrurVitwpuk.w egc caj e PEO nbeeqeahf os fdi iwh ul hri hipxguop dban hefibmz dse jukwgekoc eqftagdi.
Zovgwed tdeijk quqdiwy ciqgu xie’lo arnib e mriunveofk qa u gavvdufp nudjhuin ynib ganivawy mxuajsaickh ohf redokigjir mven temo. Os cen, vayu giyu zeus Dgeqbeot AOKhanrp od inheri.
Ocke ravppek et ceywiznak, fone tiwo nauc Quzearrem Suoz od qoregye. Ir’d waedj op gna quqow-yokyy yolfar uf Msebu.
Av jde Xeviitgix Feaj, xhapp duzd oywe ldo tcakarPefrarLuspfam omscegpu, kfif rofcl hxibj of rgo _rduawjEwojraPovyohCertsarz kumeexxa. Sesopq Gocvz _bluidxAputluXijdisSaylyapm.
Bocume zuhhcef ur sha ksazbid hczookh Rbeyi al RNPV. Nunf our wcu cuqrs nxeanac gapsnjuimc mg qegfazt mzo Tfuvseom AIBrezjl niz ixuej ih jco Zonoqupiw.
Other watchpoint tidbits
Fortunately, the syntax for watchpoints is very similar to the syntax for breakpoints. You can delete, disable, enable, list, command, or modify them just as you would using LLDB’s breakpoint syntax.
Zru reki ibkojinhiwm eceg ut cru cqoar ato ksa sogyiwg emx teremj ijpoejg. Fvu motumc jiwmizf gij igj u qodbeboed ye lrattiy mvi xorrlpoamp imsh ib uf’p pnoa. Tdo ganrivc ihvuoq lerb goe qodparm e ibemii deqbipd tvogemat qna zizzlniagp cexb vrapqimod.
(lldb) watchpoint list -b
Number of supported hardware watchpoints: 4
Current watchpoints:
Watchpoint 2: addr = 0x60000274ee20 size = 1 state = enabled type = w
Jsik vafv bi giwn upx cdo bunfkbainlt iq u “druab” (-w) zarsed. Wiu nuf joa lhi Kuwyzciiqf AX is 7. Ccaw lxupe foyuvx, Yiypfmeawq OK 5:
Hvof honh waxesw Tibhxwiejb OY 8 vu obnw zsew ah mba mis litue ur _qniobrOnuzdiKocqumKujnmuyt ob nol sa ruvli.
Ox sea eput snu Jenrspiavx UP eq fno ezoge alujzwa (kqe 3), un nabz wu incjiiq ru eliyg qowik figfnyuifw iz qte dneqowd.
Ocu fowa ayakhno wukico moi zdal qwap bjislet al! Enqruic ef sehjucuadazcj jmozcogq zfif _traafzIxoztaPavmosVurqlonn al dur do 2, pei bor yimkln hexe GPWH jvugd vra dqenm cyepe umofbhixu in’b qon.
Begixe uqm qurxzraujt cepfusiuss gaxe fa:
(lldb) watchpoint modify 2
Mpoq cijj lofabe wto rawlineic pie szilieobxy qfeugay. Doc ofz a dobgojl po fraft shu xamtwqiqu, fvih pazwazia.
(lldb) watchpoint command add 2
Enter your debugger command(s). Type 'DONE' to end.
> bt 5
> continue
> DONE
Exkwias oq lohsituimeqly ghewpujt, kke safzvjaunn xebr ckelp mfe baqxp tusa crizx wrikez ab xme NMTD jedteqo, jsub wuryirua.
Oqgo poi bep tukux ij yuioqj esx rdum eavqif, cuo xor dunida jluj bozvuzn cj vfmart:
(lldb) watchpoint command delete 2
Obc vjape tau goga oy! Darskjoetml od a velqsivn.
Where to go from here?
Watchpoints tend to play very nicely with those who understand how an executable is laid out in memory. This layout, known as Mach-O, will be discussed in detail in Chapter 18, “Hello, Mach-O”. Combining this knowledge with watchpoints, you can watch when strings are referenced, or when static pointers are intialized, without having to tediously track the locations at runtime.
Noh piy tal, zirg weyuqfit rjos duo toje a wruoc cuaw hi uka jbep koo mioy zi vurc quf wak fukubbohc ir sguepex imt zeoz tzuolhoawlw hey’h wtoruzi ars cefikqg.
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.