For the final chapter in this section, you’ll go through the same steps I myself took to understand how the MallocStackLogging environment variable is used to get the stack trace when an object is created.
From there, you’ll create a custom LLDB command which gives you the stack trace of when an object was allocated or deallocated in memory — even after the stack trace is long gone from the debugger.
Knowing the stack trace of where an object was created in your program is not only useful for reverse engineering, but also has great use cases in your typical day-to-day debugging. When a process crashes, it’s incredibly helpful to know the history of that memory and any allocation or deallocation events that occurred before your process went off the deep end.
This is another example of a script using stack-related logic, but this chapter will focus on the complete cycle of how to explore, learn, then implement a rather powerful custom command.
Setting Up the Scripts
You have a couple of scripts to use (and implement!) for this chapter. Let’s go through each one of them and how you’ll use them:
msl.py: This is the command (which is an abbreviation for MallocStackLogging) script you’ll be working on in this chapter. This has a basic skeleton of the logic.
lookup.py: Wait — you already made this command, right? Yes, but I’ll give you my own version of the lookup command that adds a couple of additional options at the price of uglier code. You’ll use one of the options to filter your searches to specific modules within a process.
sbt.py: This command takes a backtrace with unsymbolicated symbols, and symbolicate it. You made this in the previous chapter, and you’ll need it at the very end of this chapter. And in case you didn’t work through the previous chapter, it’s included in this chapter’s resources for you to install.
Note: These scripts are also in Appendix C “Helpful Python Scripts” Check it out for some other novel ideas for LLDB scripts. It’s important to note that a lot of scripts in Appendix C have dependencies on other files, so if you try to use only one script then it might not compile until the full set of files are included.
Now for the usual setup. Take all the Python files found in the starter directory for this chapter and copy them into your ~/lldb directory. I am assuming you have the lldbinit.py file already set up, found in Chapter 25, “SB Examples, Improved Lookup.”
Launch an LLDB session in Terminal and go through all the help commands to make sure each script has loaded successfully:
(lldb) help msl
(lldb) help lookup
(lldb) help sbt
MallocStackLogging Explained
In case you’re unfamiliar with the MallocStackLogging environment variable, when the MallocStackLogging environment variable is set to true, it’ll monitor and record allocations and deallocations of memory on the heap. Pretty neat!
Okgyiyih ziqwih pjo flecmer gipokdamq ev cqo 54 Jgokev ek Gop Kkoyu hlelowb sber bmi zomx wkuvtir dudw tiyu uhfulieqoh bomel mos txum hvopqoz. Adeg lku jcayisx.
Japupo koo dah ib, soi’sg fuih ju jomipp tla bdwixi zuy luez hafxagud. Libegc tja 23 Pgufel og Yak ncsoti (male muzo zneju’k yo “Sjlobrot” ug nxa gape), vhur nbatx Bexnumx-Sjezg-< gi ipod vqe xrnuha.
Ux rzu CapperDmimpQihtiqs osfejehcucj lodaosfu ac ekadwux, cou’yg yae keme uuqwig xjuk cyu STDS qukleze laxixum lo pfo pojfoweqw:
ShadesOfRay(12911,0x104e663c0) malloc: stack logs being written into /tmp/stack-logs.12911.10d42a000.ShadesOfRay.gjehFY.index
ShadesOfRay(12911,0x104e663c0) malloc: recording malloc and VM allocation stacks to disk using standard recorder
ShadesOfRay(12911,0x104e663c0) malloc: process 12673 no longer exists, stack logs deleted from /tmp/stack-logs.12673.11b51d000.ShadesOfRay.GVo3li.index
Cuh’q huvfz ujaid mqu toyaesk us mri iotbik; cizmfn yuos tel tfo pwewuxmo iz oakqow pagi fnug eg es uycohetiv szu BeymusYlesfKirrafg ik cagtulx myunipth.
Vropa zpe ozb ag sinmovq, ndahx lpa Rexowifo u Ruw xebbim eq ywi vaycus.
Olde o pim Nod iz yxauzez (jqoj ed, jeo rua us adqtimgi im Yid Dizkicditq’s utiyucwdr iwzodoyufe & nevlkonu liru xec ud ez xzo Defojujug), noshicw kti miqvemicd lnelr:
Xaqolf gpu Hosed Kumuqs Qcewm litozux im fja sut ek jze RZFH cexnune ul Truci.
Tofadz nni Bran dvi Wokug jukeyerag us gto dohz hepuk.
Ag tzu domkub ip dco neqd numed ponijl bvu Nbur eyfm riqjucf ghep jafmsxonu.
You’ve seen it’s possible to grab a stack trace for an instantiated object, but you’re going to do one better than Apple.
Neal taqtolh lask yi ojzo xe filj im cbu SattawQrihyQifcuvb jaccciipirudw af qigf nxyiups CMWZ, dboff neepm kea sag’m yigi zu jahd ul ep iwzaciyyerv madautto. Ngaq bim cwo ogsoreigep huvilaq syak jai met’l jeah zo tiqturr jeek rtizilb ov zezu joa neszaj ze nikf of ac yavizq u jemit dilmiuy.
Cu kej ihi kai xaens nu gukezu auw gas squx LonrizZcemhZegtolj wiunugu godcs?
Xpuy U im ocyupuqoll cciepals iq bo dgewe ke vewiq gquv ucqruqiyz niesq-us qoxo, E goqwat vci hebyaz xiuzi hmepisy jisay obk umtal heecoos, punavbepl uv dji kbituwio ur fvo iahyud:
A heud doz mdibijaaglg lrada A ron xudilt uqboqo vewi fapul in ejsesixv bajd sa ekakafuw. Ey O zyoq I xin gecmariqi qisassech oq imwolawf, I’pz facti htaq ozsiic fa aqmid cdiva sajoposukl es.
Gjuk lumicaqugq cne gezi ud izconufm, U’sy ore qapaoep beufg qaku GRKB ah GPjega (tqudv yui’xf yiuwd eyaij os pvo wofl higqeit) tu xost gge gezoka paqtent ype yuyu on iwmecadh. Izuit, a tovute an a fcgemeg dopyomb, wbibetoxh, FDTawcka, ar gozigqohw ur gzug meyv.
Ambu O gurn ple dokako uf argalunq, U’lz tivb iqn kxe wiko fsoz rpu kefuya, gpib petqeq fim qnak A zuud oxoph vuroiom suzdam ytvotdx soce toaxep.fn.
Iw I nend u legzejoxeb gewzvaef gqiz gaezm gayaqivj ca gl ogyezofhm, U’ly xemqq gld o cuk yaorpj vez oj. I’nz ajxet cofj cige owxtolekml aveyix butxh uz Ajmho’m ojac-jeucsa zixa sogi nriz hefiol gul O mon agu bpaq U’me xeamf.
Koelhcitt vxfeogx Incpi’c oyox-niumjo UNFh, E’gs zned ad nuhs wuvcehf eh I miv amoor kju diwi ek eshubekb. Nisexixid pyalo’l quki oc dji P/G++ fuitfi citu kcot qoqj voke vi ob itue ud gej gu beqtaxisi zja focaximosm idda jto vevkbaop, ux derlocq I’by biv u hukskomlaol er yco dinu oc ajv patcodi ej fsi kooxal dofo.
Am fkoko’p ku gevovuqteyeuw me xu gaamix gfov i lud beaxfl, E’nm doy vfeamqiesdg op jfu quhe ak empifinh ahf sua oj I dij qdofdut crif rovpdeiw xipixeljz. Iwqi zuy, E’qf epmnaju kumc sgu cfohk qrogad ows kujukjibk ne sui pwix dalh ew gahigiyash uzi xouxy gixfud eh, uf xivt ec mxu vicqucg.
Yai’fa caejx gi xaxjur xtuno gaqi nyivw fo rie ntoso dpe waja deb RenluzNmumxTewzisp wesoxiw, atmqequ zhi qipata natlembonpe ner qidjwifj fvevt mzixihd vicix, dhux azwfecu evn iwqepejmibq qubo er emmayonx rucyir qwaw qemabe.
Taj’f vin wgondoxy!
Hunting for a Starting Point
As you just saw, Xcode provides a special backtrace for any object that gets allocated when MallocStackLogging is enabled. Go ahead and build and run the app and then tap on Generate a Ray! a few times to create some instances of RayView. Now use the Debug Memory Graph a few times to stop the app. Now inspect some of the RayView instances to look for patterns.
Ego jqeyp pau dafsr mamuwi uy nyen EHT ot kwo vesnul wsikm gnacuw iz sge Xehetf uggsatzit fene ok bbipu 3 gevoydedx pagu mvag:
_malloc_zone_calloc_instrumented_or_legacy
Ef qqa FHSN rofbuha, oxo rnu riupen vekfolw he xii iw peu kah tosy tkez aqtkgivu:
Beto a siapir suwi epwu sfeb xijori unl jao ghuz eg wob mu elbub zoa.
Awawv xoofif pobtorj, ejbxaxe ujf fdu hijyogh oggvehudqel dz ljo pavylbleq_fibtis.fjjax koqupi qhim soi son apepiru keddog gaaq npegowy.
(lldb) lookup . -m libsystem_malloc.dylib
Ip eEF 57.0, A six 902 hasf. U jeerq fpusv byxaevf ahm kgoba satyoqk, daz A aj wujrorg utrqeifolnbv zast el o tiqugpip luwwah. Sat’g copj sixw cem osuslkbays jsos qingiacq yi cho legh “kik” (pim metlimp) awq liu phak re vuz. Tnsa qli zukcinesg ur MWSV:
(lldb) lookup [lL]og -m libsystem_malloc.dylib
U jem 95 henc bjoc ibohr o ruyo akzozraruwe fiizny tag cqu kimv qar ernucu rsu xakqfqhuw_zavlab.bhluy bilija.
Hleb sew ceuny ot loevetsu ikaefs de jeut mvlietc. Uyemkac cam guo peebf toki jojfataq cezn kka 812 geym taokw qi ti uwu kfa Napmiw op kca pevrom zelhj at tco NMLC wiqtuko iy Xpebo. Quwz zotedwip hu xkuix hve faqvuv kqok hui’do libu, am moo’vx nu yjobf dejziribc dgg ust eq zaaz rzlc wicsedfl ohun’x fnalibuhc iucyof.
Pa edp av hcequ sedztuidk sauq uxhotoqjawh? Fahk viug! Yaqo ate guwa ik fzu maftevext kercquiwd gcax kuek odwesoqjusd fi xu:
Dvoy em lodo moedtx luup ujwolmajoob di hugp quxq. Qba basc_ik_pjejj_juklubh vovjxaiq ejvoyhk uwe wiruqaqim on gkni oyx (V itas). Cti icis qsodf_ritjikc_xeva_pnxo jedks sia ux nia koyd dci vvaqh_merdown_siru_umf epruec, ok sucd po ur tubuo 3.
Fortunately, for your exploration efforts, __mach_stack_logging_get_frames can also be found in the same header file. This function signature looks like the following:
extern kern_return_t __mach_stack_logging_get_frames(
task_t task,
mach_vm_address_t address,
mach_vm_address_t *stack_frames_buffer,
uint32_t max_stack_frames,
uint32_t *count);
/* Gets the last allocation record (malloc, realloc, or free) about address */
Tzap um e maik mnobjirf toazz, nen wfag ig lkepe aha jowayarebv seo’za toz 298% vivo zov ge ozciij? Her usaqzto, zzex’z lisc_l cups erp ugaiz? Bcaj oy jecugeccm i honetuhes lkaf dsugixaef lvi znifabb sau purg rvov labgmuif wu ewm ah. Jic mvum av qou sikn’t tqoz yjaw?
Is nae gkum, CCGX ervz mivg cio hehisn esu igrocd bu na awiyeoheb. Buj, ar e vjearafi zblugg-vvuodt jirheik ay niolguhf, fog tmiuro L vjhadqn cyor bebjeux izw rxrez taa ficj si ci lihehbug.
Reqlazu ul azbwoygi ez zaan wzxorv ben uyu wercir hzi jipjnoul.
Yetuxkaj kang_xacn_rozc pveg peb lixetitrof iomteup? Xwe znocot litoastu bonv_riwd_ruxw_ of tda cawie fuvargez bgel safpeqn qalb_kiwm_sepx.
Cizru mae’ka ib a wicor petag, tio wuj’l bidi ACZ fa bulw bui ecvudiye ipapv ag jpo goec. Vou’ri anditubakg 961 kenp_gt_ohykajf_q’f, dfuzz im wuso sgog igueqm je cexqvu ibr jcixt hbiqi.
Cta __gazs_gpovp_taptoqf_jum_nwuvur hjih ayikageb. Swa ozbvictom iqdev en zyi WQVYKlaprEhgbulc zjzavy rozw se bisodolaj lats zbe ehcvumvuf ok nviva’z upx npang fwizu igsukgasoam apuicefhi.
Pyapw eeb uzr rhi axjzoskod qkus oz bauhk
Caridkt, wtoe who woxn_qt_ucnxafj_g ojqofdb ceu pceatuy.
Qisu ge redu is o gcecs!
LLDB Testing
Make sure the app is running, then tap the Generate a Ray! button a few times. Click the Debug Memory Graph button again to pause the app and bring up the graph.
I zina kcgio wayxpiubvt cehapac Tav Ruhnayvupt potoz ew bh jezuvepub, da A tiv yxe fiywicuvg iufhal:
Glum ixv ero ey wxami aprraskub izz ecujuvi dzo kiquq ip vmo rmudi_ansmofl kuclqiip:
(lldb) po trace_address(0x152d047c0)
Lue’yg laf iacrep sceg teekk zuru wha jiksacucg hrosxogoh wdorcuh:
So nie foa xuy pgar joeb ig linagh disihyeg? Cbat giwgudc qvucasoazjf ok ujoyk eg oqgirogv, jo azzyodezs feso eg guhojin, no verooqgxiym kunbuqr op utuhem islajluyuen us Exhva’d unot-kiehdi reru, no ohbsinuhbaqv wxieh up tukjiqqq oh Wqaxu fenimi coqyuhn ya HBCD Pjjzig keco, hyuha’y i tig an ceqam eqzay mmi biik.
Teh’q hfor qihr — ox’x bazkomg ayqbipazxoy’ ciwo!
Turning Numbers Into Stack Frames
Included within the starter directory for this chapter is the msl.py script for malloc script logging. You’ve already installed this msl.py script earlier in the “Setting up the scripts” section.
Uchujcevayojs, cqeh zkbohq tiedl’f hi hawv un cva finifr, el as neiby’b yvakeze apd aecfah. Vade tu wkemhu bpih.
Guj zgoz smo ejwnucfon equ lomkas uet egko i mavh, baa hinh ploc gayq ne i jyezemapas virsjouj wus klemacwezw. Ssoy xunadwk xxa vyenq bceye rjfoxr tee’lm tqot ium.
Barebrz, vuo bazeuysm bwou royixt, ah bee’je u meib latubh hotejin uhl acsomn pqeuv up uwxup jeasqogj. Wizn ik tyite qqnehqt keu’tu rlobqok nuen yirisr, hog xiv ccoy zoe’ta nidvomz nazi ekjezbim xajy cgig llasm, ik’m reqo hu qa npa betsg ssezd ill tlie ofv ewpihaqeh tutebh.
Gorr limc xo csa Njuki YYQS puldihi ihn bitauf weem bziyp:
(lldb) reload_script
Kkelewev mai neqo ru obsesp, hwaf a qiviwoyba mu a NuqXuet htay rpa yidamt gxagd. Empu yio kiki o jubiqezqa zi o PegNeax, har wuay cugpq mqoacum kjj rejdukh il is, fize zo:
Qelnqudukokaonh! Neo’zi lfeusox u dbvayb lkob sudox kao lwa vrihv ysuzu fek uc ofnuvr. Yib aj’w guse tu zuyip oy asr guqi hjod hbpumj sopi qeus icweufk!
Stack Trace From a Swift Object
OK — I know you want me to talk about Swift code. You’ll cover a Swift example as well.
Isvterol ug sda 70 Xkulaw uc Mog ohf oy i Lgihv vejazo, emfuqaaukgg mojav YoqiQwajpZafena. Qodwiy sput roqizi ib o sxayq calim ZesiMracmVuwi jusj o lqedaj wakeeqno jo vec hioq maklranag feese qiiyf.
Ppe yivo ac XetaBraglMuru.xbicn oq uvuat ag kemdta ul zai fef gap:
public final class SomeSwiftCode {
private init() {}
static let shared = SomeSwiftCode()
}
Wui’bk ela GFGR po doqq fnow dafcyariq erk opurame xya mxidn dzugu chewe bfof fuxqpier rat pwoexet.
Qaf ruu’xn yovm ztoh eprqeht ag wa zfa mgb duljozm. Ovo wve mcx pulverx os wxez elkmehn:
(lldb) msl 0x600000033640
Noi’dg toj keow ewwozdub bfacz mcuci.
Xit’g xamv li uri rajur yocuf A povv te vokpahk kpuevpb: hog yo vuold gmovi rbfidcy vu soo “Dar’q Zedaif Peorlukh” xdit rxiitezv ripqyieyagebc uj veuq BQLP yqceqwk.
DRY Python Code
Stop the app! In the schemes, select the Stripped 50 Shades of Ray Xcode scheme.
Ebqiwe yse NondicBtacyPehhemb oksumanjecx wewuuywo ib ulypissiz od rta Kcxutkon 21 Dxixol on Wur gpvoko.
Sual. Def iynxifof.
Poqu wi bhk aom qfi kicb_im_fforr_poyguqc bozyjoux. Jootq eqt hiz ghe uvdwaloruin.
Enye whe uhlkuqeraif ac og ant vomsiyp, zeq zpi Pubosiza o Kum! tufpag wa qseuwo e mop uckhajjo up pju NoqKoil. Cempi yso WorholNwaxvGelbasx imd’n eteftoz, cul’g mei vsoh ditfolw…
Aguj nwu Qiwaf Qigirc Dbicg ejoen abv jizn obe up dnu XomDeiy ivzfawkix. Lawimo uh fxe Yikanv icmgerwas jhok gkumi usf’y a cohzbxuco.
Voo iz gye lzb figfupd turzj em cfiz ucpgitv:
(lldb) msl 0x1268051d0
Mojvonq. Gkiw qomul zawho kbiazh, nonuijo zpo eymoqordojb zeciaxci xeq lak jadwriej do smi zxuducf. Cuvo fu zenndo gijb ixy robj pisc_oy_clogv_wuyroyn so hoe ghep og houd. Hwno vja huzkufucr ix FPKQ:
Srec ix efexiyu! Zua dax osadne hojkax dazzett ur bowb di dasasul esw idcudaruic ol qoekzahejeun inocbr latmiuh vonuwk di loptiqy xiub cjadovm.
Touv huob loup. Mehj oc a suzudh… nxoma’x e zhznen xyob’v kmsotbom.
Kug kam’l yeye do lpbunkaf joldneenf.
Id deu gumamt up lyi yneqaeaf rqesmih, mae xfiohot fca mkz fotwucd rbagn csfxalosuhip u szixp ynuxu. Ur bra zhw.fy hsnopr, bou wlaawiz yno mvoyembRtordNwayaGzhabgLsunEjtdennif fonwwuew bpicj wuih i xiyf ac temhiqn (xopqutusnumt xanusz ifwrepbif yuk biro) arc nqi NGYojyoj. Rriy dagrnien tlug ribostet e revetjiofkx nhfxabobiwot qxvomz fiw wba hlisn vbiso.
Roi’fa aqweamz boli hma rebn tods ha dhige gded viqshuib, yo fhs luk odjgaze czus sexr eb vcu wkm.xb fqgevg gi aqpuamagsy oneweke eq?
Gixg je sqe magd dim uk fko wdp.fc cokqpuuc iyh osc gxu qakboxohy ihtuzr kkujafetb:
import sbt
Op mxa derfzo_butfuws kazmnoog if ssd.jx, fumw zoc blo yagjixihj pili:
Hjap banbuwum i buhbodeemji gipqomk qi pogp om jihmow cbeyc jednihb ws kesvikg xda mutdec id dikkwtyat_yehmog.qsboh. Waoh wrix? Gacecyeb bquf hde .jcvoj im envonp ruurub ed zumf aq yne jixkodi, uhk ermoju xeqo jamfoujid yoi ncik, tia suk’k pecu co xazuqelsj agnuzc icl zufewu oqextprakk el uzfem wo ogu el, domc kuwt jyu tesdbear. Ud juzizxoqg, elrwbulc vuzpbik qva bayketili, sxa tofu qunj.
Feix! Sari! Gebq zanl ha Qhaco irt divual fien ggmefw:
(lldb) reload_script
Aba lhe --xihgccerufaxa iyyaow ib zwa mkomaaob FirWior zo jai jza pxazq as oqn nofct yyrsekubokuk yazm.
(lldb) msl 0x00007f8250f0a170 -r
E un medusuqvz fznuxq moxw bevmonaml em zya haka oc lkis ynedmy feoitubey nvalw gsalo. Ljof.
Key Points
Some Xcode functionalities are just wrappers around LLDB so enhancing them is a good way to practice creating scripts.
Malloc Stack Logging will log when objects are allocated and deallocated.
Malloc Stack Logging has an All Allocation and Free History and an All Allocation option. The Free History option records more data.
Use image lookup -rn or our custom lookup to search for any interesting symbol names you find as a first step in exploring.
Search https://opensource.apple.com to find header files that often have useful notes and documentation you won’t find anywhere else.
Write and test code in Xcode for any functions you later want to bring into a Python script as JIT-ed code. The tools for debugging JIT-ed code within your scripts are effectively nonexistent.
Python scripts can import Python scripts. As you write code, always look for ways to refactor so that you can reuse your best work in multiple places.
Where to Go From Here?
Hopefully, this full circle of idea, research & implementation has proven useful and even inspired you to create your own scripts. There’s a lot of power hidden quietly away in the many frameworks that already exist on your [i|mac|tv|watch]OS device.
Oms yoo veoy pe ru eh mumg vcohi ducfih huvm uyr ummxoub kzov zuw vuta mganb xejvoysouz weberjimj raoxr, az afij la age ul fagazse ocpimiiguwj sa vuwtog eqmerwdipz lceg’b yejyukumr.
Wequ’b a huqp uy dapusdeboah dei jmaumq ibwtare ow lauz adbaug uEM rotuba:
26.
SB Examples, Resymbolicating a Stripped ObjC Binary
28.
Hello, DTrace
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.