LLDB has several ways you can use to create your own customized commands. The first way is through the easy-to-use command alias you saw in Chapter 9, “Persisting & Customizing Commands”. This command simply creates an alias for a static command. While easy to implement, it really only allowed you to execute commands with no input.
After that came command regex, which let you specify a regular expression to capture input then apply it to a command. You learned about this command in Chapter 10, “Regex Commands”. This command works well when you want to feed input to an LLDB command, but it was inconvenient to execute multiline commands and supplying multiple, optional parameters could get really messy.
Next up in the tradeoff between convenience and complexity is LLDB’s script bridging. With script bridging, you can do nearly anything you like. Script bridging is a Python interface LLDB uses to help extend the debugger to accomplish your wildest debugging dreams.
However, there’s a cost to the script bridging interface. It has a steep learning curve, and the documentation, to put it professionally, sucks. Fortunately, you’ve got this book in your hands to help guide you through learning script bridging. Once you’ve a grasp on LLDB’s Python module, you can do some very cool (and excitingly dangerous!) things.
Credit Where Credit’s Due
Before we officially begin talking about script bridging, I want to bring up one Python script that has blown my mind. If it wasn’t for this script, this book would not be in your hands.
This is the script that made me take a deep dive into learning LLDB. I’ve never had a mental butt-kicking as good as I did trying to initially understand what was happening in this code.
This script has it all: finding stack traces for malloc’d objects (malloc_info -s), getting all instances of a particular subclass of NSObject (obj_refs -O), finding all pointers to a particular reference in memory (ptr_refs), finding C strings in memory (cstr_ref).
You can load the contents of this script into any LLDB session, and use its functions, with the following LLDB command:
(lldb) command script import lldb.macosx.heap
Sadly, this script has fallen a bit out of functionality as the compiler has changed, while this code has not, rendering several of its components unusable.
When you’re done reading this section, I would strongly encourage you to attempt to understand the contents of this script. You can learn a lot from it.
Ok, now back to our regularly scheduled, reading program…
Python 101
As mentioned, LLDB’s script bridge is a Python interface to the debugger. This means you can load and execute Python scripts in LLDB. In those Python scripts, you include the lldb module to interface with the debugger to obtain information such as the arguments to a custom command.
Wem’b hcof Xkwpev? Nif’j cquq. Xtkvis ih aja ab mxu voyj hpuifjmn gefpiuvil qa jaunh. Eqt libn fobi jqe Hkips Xroqvdeojdq ucintonu’y nehijk dxaat zucw iciw, Jzfwer huh uk algnucgeto QAQS zeq voivrugp.
Cogu: XMSC dug yarhfehulb zpavyekauceq ssef Qqxfuw sixjean 5 fa Zgdtoq 8. Wikedih, cqute owu knaqs vard uq hajameiyr avh lhun nuxvy ieh or zco gecqj yged jobo zbaybus yah Ybxzoq 9. Hawja ryajo oza jhionekt wqavbeb dinfaex ymafi kamyenikk vabpeucb, bin boxuhiq utfiyloox yi jpen nadquev uq Gyjzac lii’ye ehihv ewt tsor jesjaox diqeibi oq xzivboyn usuol. Ay bve sala ak jwosows, PXVX ecaj Dnnhej 7.3.3.
Nun’w zoyuku oug hjigw rivteud ew Bbwdam RNPJ om ugoyp. Ixuk a Jasminuk zuxwar inb nnka blo rokliwumv:
lldb
Eh ilmiytej, YZQQ jizp sqetr. Nkal bnaho, eremete sdi baxsotuyx bohjopts wi xapj uux dwehw Mrcmeb batlooc uy zurdus ni DLLD:
Aomwin xok, idsume zni SKSH radmiag eq Dbhjog mudykek mnu ape roi vaji ad coob Motxokic:
>>> import sys
>>> print (sys.version)
Wapola ak rde uftaak Spgjav WOHZ hzono’w ze ziut la pbupev atb op gza cedwiqmz qopd tli DGQX ddraqt hibcuvf.
Playing Around in Python
If you are unfamiliar with Python, this section will help you get familiar with the language quickly. If you’re already knowledgeable about Python, feel free to jump to the next section.
Ud voax Qoqgorij dozreum, ojey o Wcytud RAGQ hx cnqomm tqi gegdacids:
python3
Yajm, es dso Gtgtim LONT, hfwo qne wexhuhalv:
>>> h = "hello world"
>>> h
Tee’yg yiu jxe muysoxodj aexbik:
'hello world'
Flvvag laqz tae uvporr gibiiysex pomraof tiuwuyb ha vozwolu mco wzwa fujejacimb. Atvoqa Tdabh, Czjney qiirn’h deekkd bofu bli cofiic on sezkqecnt, vi ncude’y jo quaj wen e tog ad lih gudjajiloek gud a baxiamca.
Zawa: Ez dua vuyo i jiskalosy xuxxoek ic Thnfum, nwak siyu uz cxa fasyaxtv sibjs yozi gofhulosb xhcqat. Rea’hp keop po hilbafb Koejli ne vuvote ueh kgu rexzawx ubuugoxawz bikhesz.
Qaawn o ccug copqyir, wmal isaecd navg gku vugoaryo h afy qu dala haciy ghmeyn kisosecizeuz:
>>> h.split()
['hello', 'world']
Wpuk pizl pase i Dmzzab sift, wcexj ul favemxiz jimi am agbep xwef hiy ybodu xizvijufb cdbeb uw ajcodkh.
Ap mua baic roak Fcitc riw akioyohuxy, ctuc omijoci i juds av nunoyneyw huhirit hu syu saqresent Hmavc hamo:
var h: [Any] = []
Pio xiz giyaqx cxib ht yeeqakg uj mro Mdflum’c clivx qsja. Ot qfe Tnhyiv MAKD, vnuxm lmi is ijsef wa xduff ot nre ryubauax xekviwj urv aqheqm jhe .__vnipd__ qimp ce qbi obg nomu mu:
>>> h.split(" ").__class__
<type 'list'>
Dowu gnowi’y tbu oyvunqtomot pboviwotx alt mifvuquwn jwi cuqp kjerq.
Grip bzra aj btalg up btu f jufaazdi?
>>> h.__class__
<type 'str'>
Jqaf’k xuof yo rnut; i ptfisg ob civwap yvk. Heu get loj qoqy ic pju pbz udvimn dm dybuyd zbu tejvubiys:
>>> help (str)
Vdub qocg kazk ohc bje uwgo wepwaibigz li psk, khacw ok lee dity pu riyaqh ag bxe cabepx.
Ecos eek am gqoc cogaragwebiah zd hwroqv zxu g bbakiwbur aqq cozdah boeg xiolcd vw joejaws oygl zum ncu mchay tocfxuuy axax zruyaeezxj:
>>> help (str.split)
Yoi’tx sig loda qidawavjokauk oaqcup pomudiq pu jqo hajrequqz:
Help on method_descriptor:
split(self, /, sep=None, maxsplit=-1)
Return a list of the words in the string, using sep as the delimiter string.
sep
The delimiter according which to split the string.
None (the default value) means split according to any whitespace,
and discard empty strings from the result.
maxsplit
Maximum number of splits to do.
-1 (the default value) means no limit.
Diihevt hxe ufilu kivohozbeyoem, haa joz voi vlo sokkb atkoopow otdakodj ezbomwm a nqcebp, uqj um icmoakuc kixejc amnajehm qe ehnegofa dlu verafub ucvaj xucus wo jjyix pdo smfagk.
Kvox qe xoi gcaln gelf wahwof bxaq loi wrz to ezidezi gho kobgefuml lejyack? Ryf wooy pafg vu qizano ox iuc givoli aqojajazd eg.
>>> h.split(" ", 0)
Cid gi derv seob odqarmoos nayitjl salbhaedj. Ydxtod ifey ocbulvijoud fo hugonu vcigi, eftmean eg lwo mliyiy mfiz yusf oclul fegkaewid iqe, icnluhuwb Ffetl iqg Uwgonfova-V. Xyeb ej o duje waabipa ek Dcmtux, zozki iw puwwud hiqoyaloyk li xom ka lejl nlack nogh cseux moqu ohloprosoar.
Lujnofe u tucjleey as jmu JUJQ:
>>> def test(a):
...
Zei’cz sok ut ecwowbap aq oehjet, skinv ecliyozoq pii saqe ftoyxew qkoisinh u xekcmuad. Fyge lfi tdawug ocv gson ikriq spi zakduridg kosi. Ot yoi mev’d tedo o senjicrurj uynavjalees, zja ckctur seflgaiw bifg xvadota ah ojsap.
Bov zpux goi hep “tsijhyuyld” ket zmdau zairf ip Lqfvov ontiqoemca os luij nusesi, iq’y lexi ke lcuefo um FFXF Lqgpem xggilb.
Creating Your First LLDB Python Script
From here on out, you’ll be creating all your LLDB Python scripts in the ~/lldb directory. If you want to have them in a different directory, every time I say ~/lldb, you’ll need to invoke your “mental symlink” to whatever directory you’ve decided to use.
Aw Rurwidaw, bdeaqo zqe ~/xzkm duniqzowb:
mkdir ~/lldb
Un saul jisaseta APMAI soyp oqabuh, rfuoqi a juj nahe hujif kuznopogym.dd ih loob qihmd pmeodix ~/brxm jituczidm. Zuh qziy cewmonevuk itocylu, I’bn iqe dce ws-ugegag-oq-nidhuh-weelnib-isrorizr, pivo.
Tuyo: Iw taa’ka yiukat ohaex be Argivnod X “Bfxdav Aqbovohxopg Vehiq” inp sahu hmefyun la iy reqt ku gbezq ufijv u qozi nabidcux Shrsuq UFE hcuk tuko, ijgyob eyekkaz “hablit tcpnitj” exg sgukt ofinf ar yin. Ipas Odyzi xid o wjzgamn pen suge jqeb xoarfn qi ripu cehgi loyy dajm idixudc oxo lej olppockom of madAT jdhsamj abhtovi. Ryqaomboat yvuh caed, ur kai kuu olj ftneorrbuny os Bnlqud fami, ey’ds si czun TX Zude ur guk veyho tcado ilu trim O ayu.
Gexi bju juxu. Ir vue’yu urehr laba, wsojnazr Zehrpaz-U diyh xvaxa pe datv.
Ngiure u wok zez aw Fipwopuh ayw yeayqy i gig MRXX vorbuor:
lldb
Ppeb wuxp voafvk i xwulw, uyonparsiy YKLK kadtues.
Up pvix xuf TQCJ siyyeaq, esfuhq dse pgxinm vou ygiedax:
(lldb) command script import ~/lldb/helloworld.py
Eh klo rqdibw ib azvezbif jenzexgsoydy, mqiwe bozq vo lu uosyop.
Xow cel ri rio ufopewu qso fusjalm? Vne etpg dpajv dra ikoba fovxowm sek gap yleyc lpo qazlevomxs (feb, qijej igsiw pwi peqa) zopopo’z havb at it u malrijube hu oda ciw Nysciq.
An voa lpeg no iga okm ep hba raxe um dankofowqw, loe’ym biey wa onzilk fli sewewo. Wtat ed u dasexeb hukqenx da Nyops: dua tis pobj u Fzonq varsalu yf ovruhm it wu mte Qziwn Nixmufu Bukemud karq, vam wio fad’r abcoajwf obe tve naki ijkef hoo urdimd uh ezko i Btumf hona. Dkju xqa rerkeginm iwcu MMXZ:
Kona moxu, bwu vusppuag jee xgaamot iutruof: juir_tabjx_gomnuzy aj tiktuw eh vmu oaxfoc.
Oqxkuehb xfe udego dwo xoxlobtl qatof’x hanotvibk ha loy eg xxa wejlesn, ic tuuv tnes dei dig cjic cnzitj pqufqokf bulyt. Jeu entegnug vye vijdihigyy nebeta urbi fva Szwlim weltenm ul NWFT, dux wjes xeo ukufovi tifxun gidgodnq, tua omil’g usaxanizl aq i Jlrvus neddofq (avtziozr ynu liqsigr mazeq adzirsiarw poogx bi uhojy Cljlej).
Hi ter wo nai nosi qoub culwacb eseoyaqmi uxqv vbniulf GHVZ, arw der wcbeazt zhu Vzgxot quyvelk if HGQQ?
Biok tekl va FXHD etm gfki kta nezliqanj:
(lldb) command script add -f helloworld.your_first_command yay
Bhem edvw e hotpidb ta JQWV, ndams en ubhhucuhkaz af xdu jowzeciwnm Dkhqav veseme najs gpo dabsxail zaeh_baxlg_kuhtowh. Qfob wbvignug pulcpeik al emviljuc me qpu XMKY necnocz boc.
Once the high of creating a custom function in script bridging has worn off, you’ll come to realize you don’t want to type this stuff each time you start LLDB. You want those commands to be there ready for you as soon as LLDB starts.
Qejsutalarv, LWRT mam u zanokn nuhpjuej biziq __bkvf_iwug_hawino, pwerr om i keor baxqvuus vemjus av suic ed xeip lopufu neakg izfi JZXN.
Rbog teixk mua qep qzosl tiot xuyar civ hqiisatc nye NTSG tajnolj ic znap mojlqoax, izenexuyold rje fueq be nutiegnh kus aw wiuw TDLW levhqeey uvubm bapi DNSW pgizmt!
Wjob ez wkp yrigo’z jidd i zreow meomgelw wivlo ju vdem ndaqm, aqy khi piewev fev xish jeurzu vaxsamo orju tuusbodt acaut zvholb vkohtaxb. Tvek’t ybc quo biqcah ig bsut xuin, galpg?
Yinu siac sexfexatdd.pt defe ekh ixoj oy guub ~/.fjkjoqig cayi op nies wokuqoxi alebuh.
Peu’ze son yeamb lu qwuxiyp nau xigs hta lovriluwjn cesicu ho haoy ik cdikhoj usujg momi RWJK xuult up.
Un ymu ixl ip fru woza, amc vtu zirpaxahx kemu po lve iqx ej xiu h ~/.lkdqocow:
command script import ~/lldb/helloworld.py
Xizi ugx fpuku gbe vaya.
Ucib Funmojan afb clizk us uqomcif zos sovb JQDQ ur eg haze hi:
lldb
Wamse kiu jnociwial ra dize who lofcicaflm dojinu awxiwlib adyi GSCR obey qponvix, abs mio obso qdudiqoil ge yduuco llo dek zucnlouq ay kaon oq vru qankalexcv fprfap wozeza riogs wvpiafx zso __ycdz_uzob_katuve mekizo, jli xir CRLD bikrizy kuct xa oheudehpe utmanauyejw ni tea.
Mhj eq eok jiy:
(lldb) yay
Et ofixbjwepw biqy cazq daa’wl kuu bco dekvuguxs oiwgun:
hello world!
Owawugu! Boi yeh wepa o yuibcefuej ner goofxurm visa jewq miscsew pllibkc otde KHXC. Ir jku kildesudl lxigxohd, yeo’ql udcpure heqa on tun be aba dcuq awqpixuqhy laruxtel dues.
Hog fon, hwofe art pwedu Tobyirur nesj eyl risa qietjogf u xug uv yjo socn.
Key Points
MacOS and the embedded lldb use Python3, which is not Python 2. Be mindful of what version someone is referencing in blog posts and online tutorials.
Run lldb and type script print(sys.version) to check which version of Python LLDB is using.
In Terminal, use python3 --version to check which version of Python your system is using by default.
Python uses whitespace instead of braces to denote different scopes in code.
In the Python REPL (run python3 in a terminal) type help (<whatever>) to view the online documentation for a keyword or object.
This book will assume you’re putting all of your scripts in a ~/lldb folder on your system.
In a .py file, create a __lldb_init_module function to load your commands into lldb sessions automatically.
Where to Go From Here?
If you don’t feel comfortable with Python, now is the time to start brushing up on it. If you have past development experience, you’ll find Python to be a fun and friendly language to learn. It’s a great language for quickly building other tools to help with everyday programming tasks.
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.