SlideShare a Scribd company logo
1 of 76
Download to read offline
Advanced Debugging With XCode
Extending LLDB
Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
Aijaz
@_aijaz_
(Since 1982)
😱
Debug
Sample
Project
Session
id: String
title: String?
sessionDescription: String?
startTime: Date
endTime: Date
speaker: Speaker?
startDate: String
init?(withId id: String)
Speaker
id: String
name: String
imagePath: String?
bio: String?
twitterHandle: String?
website: String?
sessions: [Session]
init?(withId id: String)
speaker
sessions
Demo 1
Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
Let’s Recap
# In ~/.lldbinit, available to all LLDB sessions
type summary add --summary-string 
"(${var._indexes[0]}, ${var._indexes[1]})" IndexPath
type summary add --summary-string 
"${var.title} by ${var.speaker.name}" MyConf.Session
Quick & Dirty Type Summaries
Summaries in Python
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format ()
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
title = valobj.GetChildMemberWithName('title')
name = valobj.GetChildMemberWithName(‘speaker’)
.GetChildMemberWithName('name')
return stripQuotes(title.GetObjectDescription())
+ " by " + 
stripQuotes(name.GetObjectDescription())
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
title = valobj.GetChildMemberWithName('title')
name = valobj.GetChildMemberWithName(‘speaker’)
.GetChildMemberWithName('name')
return stripQuotes(title.GetObjectDescription())
+ " by " + 
stripQuotes(name.GetObjectDescription())
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
title = valobj.GetChildMemberWithName('title')
name = valobj.GetChildMemberWithName(‘speaker’)
.GetChildMemberWithName('name')
return stripQuotes(title.GetObjectDescription())
+ " by " + 
stripQuotes(name.GetObjectDescription())
def __lldb_init_module(debugger, dict):
command = 'type summary add —-python-function 
sessionFormatter.format MyConf.Session'
debugger.HandleCommand(command)
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
title = valobj.GetChildMemberWithName('title')
name = valobj.GetChildMemberWithName(‘speaker’)
.GetChildMemberWithName('name')
return stripQuotes(title.GetObjectDescription())
+ " by " + 
stripQuotes(name.GetObjectDescription())
def __lldb_init_module(debugger, dict):
command = 'type summary add —-python-function 
sessionFormatter.format MyConf.Session'
debugger.HandleCommand(command)
sessionFormatter.py
#!/usr/bin/python
import re
regex = re.compile('[^"]*"(.*)"n$')
def stripQuotes(str):
"""Utility method to strip the first and last quote
and anything outside them"""
match = regex.match(str)
if match :
return match.group(1)
return str
def format (valobj,internal_dict):
title = valobj.GetChildMemberWithName('title')
name = valobj.GetChildMemberWithName(‘speaker’)
.GetChildMemberWithName('name')
return stripQuotes(title.GetObjectDescription())
+ " by " + 
stripQuotes(name.GetObjectDescription())
def __lldb_init_module(debugger, dict):
command = 'type summary add —-python-function 
sessionFormatter.format MyConf.Session'
debugger.HandleCommand(command)
sessionFormatter.py
command script import …/sessionFormatter.py
# Add things here, like type summaries, breakpoints
# Even execute Swift or Objective-C code with 'expr'
.lldbinit-MyConf
Project-Specific Loading
in main() or application(_:didFinishLaunchingWithOptions:)
Any
Questions?
{ "version": 1,
"speakers": [
{"id": 3,
"img": “chad.jpg",
"name": “Chad Perk",
"twitter": "chad",
"blog": “www.example.com/chad”,
"bio": "Chad is the co-author of…”
},
jq
http://feelgrafix.com/data_images/out/28/973590-avatar-the-last-airbender.jpg
$ cat avatar.json
[{"name":"Aang","sex":"M","born":-12,"died":153,"bending":["Air","Water","Earth","Fire","Energy"],"identity":
{"nationality":"Southern Air Temple","ethnicity":"Air Nomad"},"spouse":"Katara","children":[{"sex":"M","name":"Bumi"},
{"sex":"F","name":"Kya"},{"sex":"M","name":"Tenzin"}]},{"name":"Katara","sex":"F","born":85,"died":null,"bending":
["Water","Blood"],"identity":{"nationality":"Southern Water Tribe","ethnicity":"Water Tribe"},"spouse":"Aang","children":
[{"sex":"M","name":"Bumi"},{"sex":"F","name":"Kya"},{"sex":"M","name":"Tenzin"}]},{"name":"Sokka","sex":"M","born":84,"died":
164,"bending":[],"identity":{"nationality":"Southern Water Tribe","ethnicity":"Water Tribe"},"spouse":null,"children":[]},
{"name":"Toph Beifong","sex":"F","born":88,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Gaoling, Earth
Kingdom","ethnicity":"Earth Kingdom"},"spouse":null,"children":[{"sex":"F","name":"Lin Beifong"},{"sex":"F","name":"Suyin
Beifong"}]},{"name":"Iroh","sex":"M","born":null,"died":null,"bending":["Fire","Energy"],"identity":{"nationality":"Fire Nation
Capital, Fire Nation","ethnicity":"Fire Nation"},"spouse":null,"children":[{"sex":"M","name":"Lu Ten"}]},
{"name":"Zuko","sex":"M","born":83,"died":null,"bending":["Fire","Energy"],"identity":{"nationality":"Fire Nation Capital, Fire
Nation","ethnicity":"Fire Nation"},"spouse":null,"children":[{"sex":"F","name":"Izumi"}]},
{"name":"Kya","sex":"F","born":null,"died":null,"bending":["Water"],"identity":{"nationality":"Southern Water
Tribe","ethnicity":"Water Tribe, Air Nomad"},"spouse":null,"children":[]},
{"name":"Bumi","sex":"M","born":null,"died":null,"bending":["Air"],"identity":{"nationality":"United Republic","ethnicity":"Water
Tribe, Air Nomad"},"spouse":null,"children":[]},{"name":"Tenzin","sex":"M","born":null,"died":null,"bending":["Air"],"identity":
{"nationality":"Republic City, United Republic","ethnicity":"Water Tribe, Air Nomad"},"spouse":null,"children":
[{"sex":"F","name":"Jinora"},{"sex":"F","name":"Ikki"},{"sex":"M","name":"Meelo"},{"sex":"M","name":"Rohan"}]},{"name":"Lin
Beifong","sex":"F","born":120,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Republic City, United
Republic","ethnicity":"Earth Kingdom"},"spouse":null,"children":[]},{"name":"Suyin Beifong","sex":"F","born":
126,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Republic City, United Republic","ethnicity":"Earth
Kingdom"},"spouse":null,"children":[{"sex":"M","name":"Bataar Jr."},{"sex":"F","name":"Opal"},{"sex":"M","name":"Wei"},
{"sex":"M","name":"Wing"},{"sex":"M","name":"Huan"}]}]
$
# Pretty print the jq
$ jq '.' avatar.json
command input filefilter
# Pretty print the jq
$ jq '.' avatar.json
...
{
"sex": "M",
"name": "Huan"
}
]
}
]
$
# Pretty print the jq
$ jq '.' avatar.json
...
{
"sex": "M",
"name": "Huan"
}
]
}
]
$
# The ']' on the last line tells me this is an array
# Pretty print the jq
$ jq '.' avatar.json
...
{
"sex": "M",
"name": "Huan"
}
]
}
]
$
# The ']' on the last line tells me this is an array
# The '}' on the 2nd-last line tells me this is an array of objects
# List the keys of each object
$ jq ' .[] | keys ' avatar.json
foreach item in array print the keys of each object
pipe the output of one filter into the input of the next
# List the keys of each object
$ jq ' .[] | keys ' avatar.json
[
"bending",
"born",
"children",
"died",
"identity",
"name",
"sex",
"spouse"
]
[
"bending",
"born",…
$
# The name of each character
$ jq ' .[] | .name ' avatar.json
foreach item in array extract the ‘name’ field
# The name of each character
$ jq ‘.[] | .name’ avatar.json
"Aang"
"Katara"
"Sokka"
"Toph Beifong"
"Iroh"
"Zuko"
"Kya"
"Bumi"
"Tenzin"
"Lin Beifong"
$
# The name of each female character
$ jq ' .[] | select(.sex == "F") | .name ' avatar.json
foreach item in array
extract the ‘name’ field
where sex is F
# The name of each female character
$ jq ' .[] | select(.sex == "F") | .name ' avatar.json
"Katara"
"Toph Beifong"
"Kya"
"Lin Beifong"
"Suyin Beifong”
$
Demo 2
Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
(lldb) jq ‘.speakers[]|keys’ jsonString
jq filter (program) String
1. Gather input
2. Run the jq filter on the string, saving the output
3. Print the output
#!/usr/bin/python
import commands
import lldb
import shlex
#!/usr/bin/python
import commands
import lldb
import shlex
# The actual python function that is bound to the lldb command.
def jq_command(debugger, command, result, dict):
def jq_command(debugger, command, result, dict):
def jq_command(debugger, command, result, dict):
target = debugger.GetSelectedTarget()
def jq_command(debugger, command, result, dict):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
def jq_command(debugger, command, result, dict):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
def jq_command(debugger, command, result, dict):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we don’t have to worry
about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>"
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we don’t have to worry
about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq
will be invoked on the file, not using stdin
jq_json_file = “/tmp/jq_json"
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>”
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we don’t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>”
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we don’t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
f = open(jq_filter_file, 'w')
f.write(jq_filter)
f.close()
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>”
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we don’t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
f = open(jq_filter_file, 'w')
f.write(jq_filter)
f.close()
# invoke jq and capture the output
output = commands.getoutput("%s -f %s %s" % (
jq_exe, jq_filter_file, jq_json_file) )
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>”
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we don’t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
f = open(jq_filter_file, 'w')
f.write(jq_filter)
f.close()
# invoke jq and capture the output
output = commands.getoutput("%s -f %s %s" % (
jq_exe, jq_filter_file, jq_json_file) )
print >>result, output
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>”
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we don’t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
f = open(jq_filter_file, 'w')
f.write(jq_filter)
f.close()
# invoke jq and capture the output
output = commands.getoutput("%s -f %s %s" % (
jq_exe, jq_filter_file, jq_json_file) )
print >>result, output
Gather Input
Run Command
Print Output
def jq_command(debugger, command, result, dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
# The command is called like "jq <filter> <stringVar>”
command_args = shlex.split(command)
jq_filter = command_args[0]
val = frame.var(command_args[1]) # access the variable
val_string = eval(val.GetObjectDescription())
# path to the jq executable.
jq_exe = "/Users/aijaz/local/bin/jq"
# We save the filter to a file so that we don’t have to worry about escaping special characters.
jq_filter_file = "/tmp/jq_filter"
# the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin
jq_json_file = "/tmp/jq_json"
# write the json file and jq filter to temp files
f = open(jq_json_file, 'w')
f.write(val_string)
f.close()
f = open(jq_filter_file, 'w')
f.write(jq_filter)
f.close()
# invoke jq and capture the output
output = commands.getoutput("%s -f %s %s" % (
jq_exe, jq_filter_file, jq_json_file) )
print >>result, output
def __lldb_init_module(debugger, dict):
# Add any commands contained in this module to LLDB
command = 'command script add -f jq.jq_command jq'
debugger.HandleCommand(command)
What have
we learned?
Validate your
hypothesis
(if you’re lucky enough to have a hypothesis.)
Observe
Analyze
Extend
Any
Questions?
https://github.com/aijaz/lldbPythonScripts
http://aijaz.net/2017/01/11/lldb-python/index.html
https://github.com/facebook/chisel
LLDB: https://lldb.llvm.org/
A blog post from January, where I write about most of the same stuff:
Extending LLDB: http://aijaz.net/2017/01/11/lldb-python/index.html
JQ
jq: https://stedolan.github.io/jq/
A Facebook library that adds a lot of cool extensions to LLDB
Facebook Chisel: https://github.com/facebook/chisel
WWDC Sessions:
Debugging Tips and Tricks https://developer.apple.com/videos/play/wwdc2016/417/
What’s new in LLDB: https://developer.apple.com/videos/play/wwdc2015/402/
Introduction to LLDB and the Swift REPL https://developer.apple.com/videos/play/wwdc2014/409/
Advanced Swift Debugging in LLDB https://developer.apple.com/videos/play/wwdc2014/410/
Debugging in Xcode 6 https://developer.apple.com/videos/play/wwdc2014/413/
Debugging with Xcode https://developer.apple.com/videos/play/wwdc2013/407/
* Advanced Debugging with LLDB https://developer.apple.com/videos/play/wwdc2013/413/
* Debugging in Xcode https://developer.apple.com/videos/play/wwdc2012/412/
* Debugging with Xcode https://developer.apple.com/videos/play/wwdc2012/415/
*: Contains material related to this talk
Thank You!
https://www.theodysseyonline.com/overthinking-spongebob
@_aijaz_

More Related Content

What's hot

C# 7.0 Hacks and Features
C# 7.0 Hacks and FeaturesC# 7.0 Hacks and Features
C# 7.0 Hacks and FeaturesAbhishek Sur
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
 
Advanced Python, Part 1
Advanced Python, Part 1Advanced Python, Part 1
Advanced Python, Part 1Zaar Hai
 
Introduction to Gremlin
Introduction to GremlinIntroduction to Gremlin
Introduction to GremlinMax De Marzi
 
The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185Mahmoud Samir Fayed
 
From android/java to swift (3)
From android/java to swift (3)From android/java to swift (3)
From android/java to swift (3)allanh0526
 
Ast transformations
Ast transformationsAst transformations
Ast transformationsHamletDRC
 
Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. ExperienceMike Fogus
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftGiordano Scalzo
 
Designing with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaDesigning with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaNaresha K
 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyIván López Martín
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기Arawn Park
 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and InferenceRichard Fox
 
Rust Mozlando Tutorial
Rust Mozlando TutorialRust Mozlando Tutorial
Rust Mozlando Tutorialnikomatsakis
 
Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012aleks-f
 

What's hot (19)

C# 7.0 Hacks and Features
C# 7.0 Hacks and FeaturesC# 7.0 Hacks and Features
C# 7.0 Hacks and Features
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
Advanced Python, Part 1
Advanced Python, Part 1Advanced Python, Part 1
Advanced Python, Part 1
 
Introduction to Gremlin
Introduction to GremlinIntroduction to Gremlin
Introduction to Gremlin
 
The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185
 
From android/java to swift (3)
From android/java to swift (3)From android/java to swift (3)
From android/java to swift (3)
 
Python lec4
Python lec4Python lec4
Python lec4
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
 
Groovy
GroovyGroovy
Groovy
 
Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. Experience
 
How to Clone Flappy Bird in Swift
How to Clone Flappy Bird in SwiftHow to Clone Flappy Bird in Swift
How to Clone Flappy Bird in Swift
 
Designing with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaDesigning with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf India
 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovy
 
groovy & grails - lecture 3
groovy & grails - lecture 3groovy & grails - lecture 3
groovy & grails - lecture 3
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and Inference
 
C# 7
C# 7C# 7
C# 7
 
Rust Mozlando Tutorial
Rust Mozlando TutorialRust Mozlando Tutorial
Rust Mozlando Tutorial
 
Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012
 

Similar to Advanced Debugging Xcode Extend LLDB

Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeAijaz Ansari
 
Advanced Debugging with Xcode - Extending LLDB
Advanced Debugging with Xcode - Extending LLDBAdvanced Debugging with Xcode - Extending LLDB
Advanced Debugging with Xcode - Extending LLDBAijaz Ansari
 
Spring Framework - Expression Language
Spring Framework - Expression LanguageSpring Framework - Expression Language
Spring Framework - Expression LanguageDzmitry Naskou
 
AST Transformations
AST TransformationsAST Transformations
AST TransformationsHamletDRC
 
Automatically Spotting Cross-language Relations
Automatically Spotting Cross-language RelationsAutomatically Spotting Cross-language Relations
Automatically Spotting Cross-language RelationsFederico Tomassetti
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)HamletDRC
 
Type safe embedded domain-specific languages
Type safe embedded domain-specific languagesType safe embedded domain-specific languages
Type safe embedded domain-specific languagesArthur Xavier
 
Stupid Awesome Python Tricks
Stupid Awesome Python TricksStupid Awesome Python Tricks
Stupid Awesome Python TricksBryan Helmig
 
Swift와 Objective-C를 함께 쓰는 방법
Swift와 Objective-C를 함께 쓰는 방법Swift와 Objective-C를 함께 쓰는 방법
Swift와 Objective-C를 함께 쓰는 방법Jung Kim
 
Clojure for Java developers - Stockholm
Clojure for Java developers - StockholmClojure for Java developers - Stockholm
Clojure for Java developers - StockholmJan Kronquist
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
jRuby: The best of both worlds
jRuby: The best of both worldsjRuby: The best of both worlds
jRuby: The best of both worldsChristopher Spring
 
WordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPressWordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPressAlena Holligan
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kirill Rozov
 

Similar to Advanced Debugging Xcode Extend LLDB (20)

Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCode
 
Advanced Debugging with Xcode - Extending LLDB
Advanced Debugging with Xcode - Extending LLDBAdvanced Debugging with Xcode - Extending LLDB
Advanced Debugging with Xcode - Extending LLDB
 
Spring Framework - Expression Language
Spring Framework - Expression LanguageSpring Framework - Expression Language
Spring Framework - Expression Language
 
Grammarware Memes
Grammarware MemesGrammarware Memes
Grammarware Memes
 
AST Transformations
AST TransformationsAST Transformations
AST Transformations
 
Automatically Spotting Cross-language Relations
Automatically Spotting Cross-language RelationsAutomatically Spotting Cross-language Relations
Automatically Spotting Cross-language Relations
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
 
Python basic
Python basicPython basic
Python basic
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)
 
Functional Scala 2020
Functional Scala 2020Functional Scala 2020
Functional Scala 2020
 
Type safe embedded domain-specific languages
Type safe embedded domain-specific languagesType safe embedded domain-specific languages
Type safe embedded domain-specific languages
 
Stupid Awesome Python Tricks
Stupid Awesome Python TricksStupid Awesome Python Tricks
Stupid Awesome Python Tricks
 
Swift와 Objective-C를 함께 쓰는 방법
Swift와 Objective-C를 함께 쓰는 방법Swift와 Objective-C를 함께 쓰는 방법
Swift와 Objective-C를 함께 쓰는 방법
 
Clojure for Java developers - Stockholm
Clojure for Java developers - StockholmClojure for Java developers - Stockholm
Clojure for Java developers - Stockholm
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
jRuby: The best of both worlds
jRuby: The best of both worldsjRuby: The best of both worlds
jRuby: The best of both worlds
 
WordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPressWordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPress
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2
 
Groovy intro for OUDL
Groovy intro for OUDLGroovy intro for OUDL
Groovy intro for OUDL
 
Python : Functions
Python : FunctionsPython : Functions
Python : Functions
 

Recently uploaded

Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfDrew Moseley
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...Akihiro Suda
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commercemanigoyal112
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identityteam-WIBU
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Rob Geurden
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf31events.com
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...Technogeeks
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfYashikaSharma391629
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprisepreethippts
 

Recently uploaded (20)

Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdf
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
20240415 [Container Plumbing Days] Usernetes Gen2 - Kubernetes in Rootless Do...
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commerce
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identity
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Sending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdfSending Calendar Invites on SES and Calendarsnack.pdf
Sending Calendar Invites on SES and Calendarsnack.pdf
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprise
 

Advanced Debugging Xcode Extend LLDB

  • 1. Advanced Debugging With XCode Extending LLDB Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
  • 3.
  • 7.
  • 8.
  • 9. Session id: String title: String? sessionDescription: String? startTime: Date endTime: Date speaker: Speaker? startDate: String init?(withId id: String) Speaker id: String name: String imagePath: String? bio: String? twitterHandle: String? website: String? sessions: [Session] init?(withId id: String) speaker sessions
  • 11. Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
  • 13. # In ~/.lldbinit, available to all LLDB sessions type summary add --summary-string "(${var._indexes[0]}, ${var._indexes[1]})" IndexPath type summary add --summary-string "${var.title} by ${var.speaker.name}" MyConf.Session Quick & Dirty Type Summaries
  • 15. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') sessionFormatter.py
  • 16. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str sessionFormatter.py
  • 17. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str sessionFormatter.py
  • 18. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format () sessionFormatter.py
  • 19. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): sessionFormatter.py
  • 20. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): title = valobj.GetChildMemberWithName('title') name = valobj.GetChildMemberWithName(‘speaker’) .GetChildMemberWithName('name') return stripQuotes(title.GetObjectDescription()) + " by " + stripQuotes(name.GetObjectDescription()) sessionFormatter.py
  • 21. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): title = valobj.GetChildMemberWithName('title') name = valobj.GetChildMemberWithName(‘speaker’) .GetChildMemberWithName('name') return stripQuotes(title.GetObjectDescription()) + " by " + stripQuotes(name.GetObjectDescription()) sessionFormatter.py
  • 22. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): title = valobj.GetChildMemberWithName('title') name = valobj.GetChildMemberWithName(‘speaker’) .GetChildMemberWithName('name') return stripQuotes(title.GetObjectDescription()) + " by " + stripQuotes(name.GetObjectDescription()) def __lldb_init_module(debugger, dict): command = 'type summary add —-python-function sessionFormatter.format MyConf.Session' debugger.HandleCommand(command) sessionFormatter.py
  • 23. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): title = valobj.GetChildMemberWithName('title') name = valobj.GetChildMemberWithName(‘speaker’) .GetChildMemberWithName('name') return stripQuotes(title.GetObjectDescription()) + " by " + stripQuotes(name.GetObjectDescription()) def __lldb_init_module(debugger, dict): command = 'type summary add —-python-function sessionFormatter.format MyConf.Session' debugger.HandleCommand(command) sessionFormatter.py
  • 24. #!/usr/bin/python import re regex = re.compile('[^"]*"(.*)"n$') def stripQuotes(str): """Utility method to strip the first and last quote and anything outside them""" match = regex.match(str) if match : return match.group(1) return str def format (valobj,internal_dict): title = valobj.GetChildMemberWithName('title') name = valobj.GetChildMemberWithName(‘speaker’) .GetChildMemberWithName('name') return stripQuotes(title.GetObjectDescription()) + " by " + stripQuotes(name.GetObjectDescription()) def __lldb_init_module(debugger, dict): command = 'type summary add —-python-function sessionFormatter.format MyConf.Session' debugger.HandleCommand(command) sessionFormatter.py
  • 25. command script import …/sessionFormatter.py # Add things here, like type summaries, breakpoints # Even execute Swift or Objective-C code with 'expr' .lldbinit-MyConf
  • 26. Project-Specific Loading in main() or application(_:didFinishLaunchingWithOptions:)
  • 28. { "version": 1, "speakers": [ {"id": 3, "img": “chad.jpg", "name": “Chad Perk", "twitter": "chad", "blog": “www.example.com/chad”, "bio": "Chad is the co-author of…” },
  • 29. jq
  • 31. $ cat avatar.json [{"name":"Aang","sex":"M","born":-12,"died":153,"bending":["Air","Water","Earth","Fire","Energy"],"identity": {"nationality":"Southern Air Temple","ethnicity":"Air Nomad"},"spouse":"Katara","children":[{"sex":"M","name":"Bumi"}, {"sex":"F","name":"Kya"},{"sex":"M","name":"Tenzin"}]},{"name":"Katara","sex":"F","born":85,"died":null,"bending": ["Water","Blood"],"identity":{"nationality":"Southern Water Tribe","ethnicity":"Water Tribe"},"spouse":"Aang","children": [{"sex":"M","name":"Bumi"},{"sex":"F","name":"Kya"},{"sex":"M","name":"Tenzin"}]},{"name":"Sokka","sex":"M","born":84,"died": 164,"bending":[],"identity":{"nationality":"Southern Water Tribe","ethnicity":"Water Tribe"},"spouse":null,"children":[]}, {"name":"Toph Beifong","sex":"F","born":88,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Gaoling, Earth Kingdom","ethnicity":"Earth Kingdom"},"spouse":null,"children":[{"sex":"F","name":"Lin Beifong"},{"sex":"F","name":"Suyin Beifong"}]},{"name":"Iroh","sex":"M","born":null,"died":null,"bending":["Fire","Energy"],"identity":{"nationality":"Fire Nation Capital, Fire Nation","ethnicity":"Fire Nation"},"spouse":null,"children":[{"sex":"M","name":"Lu Ten"}]}, {"name":"Zuko","sex":"M","born":83,"died":null,"bending":["Fire","Energy"],"identity":{"nationality":"Fire Nation Capital, Fire Nation","ethnicity":"Fire Nation"},"spouse":null,"children":[{"sex":"F","name":"Izumi"}]}, {"name":"Kya","sex":"F","born":null,"died":null,"bending":["Water"],"identity":{"nationality":"Southern Water Tribe","ethnicity":"Water Tribe, Air Nomad"},"spouse":null,"children":[]}, {"name":"Bumi","sex":"M","born":null,"died":null,"bending":["Air"],"identity":{"nationality":"United Republic","ethnicity":"Water Tribe, Air Nomad"},"spouse":null,"children":[]},{"name":"Tenzin","sex":"M","born":null,"died":null,"bending":["Air"],"identity": {"nationality":"Republic City, United Republic","ethnicity":"Water Tribe, Air Nomad"},"spouse":null,"children": [{"sex":"F","name":"Jinora"},{"sex":"F","name":"Ikki"},{"sex":"M","name":"Meelo"},{"sex":"M","name":"Rohan"}]},{"name":"Lin Beifong","sex":"F","born":120,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Republic City, United Republic","ethnicity":"Earth Kingdom"},"spouse":null,"children":[]},{"name":"Suyin Beifong","sex":"F","born": 126,"died":null,"bending":["Earth","Metal"],"identity":{"nationality":"Republic City, United Republic","ethnicity":"Earth Kingdom"},"spouse":null,"children":[{"sex":"M","name":"Bataar Jr."},{"sex":"F","name":"Opal"},{"sex":"M","name":"Wei"}, {"sex":"M","name":"Wing"},{"sex":"M","name":"Huan"}]}] $
  • 32. # Pretty print the jq $ jq '.' avatar.json command input filefilter
  • 33. # Pretty print the jq $ jq '.' avatar.json ... { "sex": "M", "name": "Huan" } ] } ] $
  • 34. # Pretty print the jq $ jq '.' avatar.json ... { "sex": "M", "name": "Huan" } ] } ] $ # The ']' on the last line tells me this is an array
  • 35. # Pretty print the jq $ jq '.' avatar.json ... { "sex": "M", "name": "Huan" } ] } ] $ # The ']' on the last line tells me this is an array # The '}' on the 2nd-last line tells me this is an array of objects
  • 36. # List the keys of each object $ jq ' .[] | keys ' avatar.json foreach item in array print the keys of each object pipe the output of one filter into the input of the next
  • 37. # List the keys of each object $ jq ' .[] | keys ' avatar.json [ "bending", "born", "children", "died", "identity", "name", "sex", "spouse" ] [ "bending", "born",… $
  • 38. # The name of each character $ jq ' .[] | .name ' avatar.json foreach item in array extract the ‘name’ field
  • 39. # The name of each character $ jq ‘.[] | .name’ avatar.json "Aang" "Katara" "Sokka" "Toph Beifong" "Iroh" "Zuko" "Kya" "Bumi" "Tenzin" "Lin Beifong" $
  • 40. # The name of each female character $ jq ' .[] | select(.sex == "F") | .name ' avatar.json foreach item in array extract the ‘name’ field where sex is F
  • 41. # The name of each female character $ jq ' .[] | select(.sex == "F") | .name ' avatar.json "Katara" "Toph Beifong" "Kya" "Lin Beifong" "Suyin Beifong” $
  • 43. Image by Aijaz Ansari. Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
  • 44. (lldb) jq ‘.speakers[]|keys’ jsonString jq filter (program) String 1. Gather input 2. Run the jq filter on the string, saving the output 3. Print the output
  • 46. #!/usr/bin/python import commands import lldb import shlex # The actual python function that is bound to the lldb command. def jq_command(debugger, command, result, dict):
  • 48. def jq_command(debugger, command, result, dict): target = debugger.GetSelectedTarget()
  • 49. def jq_command(debugger, command, result, dict): target = debugger.GetSelectedTarget() process = target.GetProcess()
  • 50. def jq_command(debugger, command, result, dict): target = debugger.GetSelectedTarget() process = target.GetProcess() thread = process.GetSelectedThread()
  • 51. def jq_command(debugger, command, result, dict): target = debugger.GetSelectedTarget() process = target.GetProcess() thread = process.GetSelectedThread() frame = thread.GetSelectedFrame()
  • 52. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
  • 53. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command)
  • 54. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command)
  • 55. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0]
  • 56. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable
  • 57. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription())
  • 58. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq"
  • 59. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we don’t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter"
  • 60. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>" command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we don’t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = “/tmp/jq_json"
  • 61. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>” command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we don’t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close()
  • 62. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>” command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we don’t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close() f = open(jq_filter_file, 'w') f.write(jq_filter) f.close()
  • 63. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>” command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we don’t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close() f = open(jq_filter_file, 'w') f.write(jq_filter) f.close() # invoke jq and capture the output output = commands.getoutput("%s -f %s %s" % ( jq_exe, jq_filter_file, jq_json_file) )
  • 64. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>” command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we don’t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close() f = open(jq_filter_file, 'w') f.write(jq_filter) f.close() # invoke jq and capture the output output = commands.getoutput("%s -f %s %s" % ( jq_exe, jq_filter_file, jq_json_file) ) print >>result, output
  • 65. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>” command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we don’t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close() f = open(jq_filter_file, 'w') f.write(jq_filter) f.close() # invoke jq and capture the output output = commands.getoutput("%s -f %s %s" % ( jq_exe, jq_filter_file, jq_json_file) ) print >>result, output Gather Input Run Command Print Output
  • 66. def jq_command(debugger, command, result, dict): frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() # The command is called like "jq <filter> <stringVar>” command_args = shlex.split(command) jq_filter = command_args[0] val = frame.var(command_args[1]) # access the variable val_string = eval(val.GetObjectDescription()) # path to the jq executable. jq_exe = "/Users/aijaz/local/bin/jq" # We save the filter to a file so that we don’t have to worry about escaping special characters. jq_filter_file = "/tmp/jq_filter" # the value of the NSString variable is saved in this file jq will be invoked on the file, not using stdin jq_json_file = "/tmp/jq_json" # write the json file and jq filter to temp files f = open(jq_json_file, 'w') f.write(val_string) f.close() f = open(jq_filter_file, 'w') f.write(jq_filter) f.close() # invoke jq and capture the output output = commands.getoutput("%s -f %s %s" % ( jq_exe, jq_filter_file, jq_json_file) ) print >>result, output def __lldb_init_module(debugger, dict): # Add any commands contained in this module to LLDB command = 'command script add -f jq.jq_command jq' debugger.HandleCommand(command)
  • 69. (if you’re lucky enough to have a hypothesis.)
  • 75. LLDB: https://lldb.llvm.org/ A blog post from January, where I write about most of the same stuff: Extending LLDB: http://aijaz.net/2017/01/11/lldb-python/index.html JQ jq: https://stedolan.github.io/jq/ A Facebook library that adds a lot of cool extensions to LLDB Facebook Chisel: https://github.com/facebook/chisel WWDC Sessions: Debugging Tips and Tricks https://developer.apple.com/videos/play/wwdc2016/417/ What’s new in LLDB: https://developer.apple.com/videos/play/wwdc2015/402/ Introduction to LLDB and the Swift REPL https://developer.apple.com/videos/play/wwdc2014/409/ Advanced Swift Debugging in LLDB https://developer.apple.com/videos/play/wwdc2014/410/ Debugging in Xcode 6 https://developer.apple.com/videos/play/wwdc2014/413/ Debugging with Xcode https://developer.apple.com/videos/play/wwdc2013/407/ * Advanced Debugging with LLDB https://developer.apple.com/videos/play/wwdc2013/413/ * Debugging in Xcode https://developer.apple.com/videos/play/wwdc2012/412/ * Debugging with Xcode https://developer.apple.com/videos/play/wwdc2012/415/ *: Contains material related to this talk