Repository navigation
Expand file tree
/
Copy pathjuce_lldb_xcode.py
More file actions
276 lines (229 loc) · 9.97 KB
/
Copy pathjuce_lldb_xcode.py
File metadata and controls
276 lines (229 loc) · 9.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
import lldb
#
# ABOUT
#
# This file allows LLDB to decode some common JUCE structures,
# in particular Arrays, Strings, var objects and ValueTrees.
#
# The facilities aren't quite as nice as those in VisualStudio
# so if you do find you need to disable any functionality you
# can do so in the __lldb_init_module function by commentting
# out the appropriate debugger.* line.
#
# Send bug reports, feature requests and issues to jim@credland.net
#
# USAGE
#
# Put this line in your ~/.lldbinit file:
#
# command script import [path]
#
# Where [path] is the full path to this file. For example:
#
# command script import /Users/me/juce-toys/juce_lldb_xcode.py
#
#
# (c) Credland Technical Limited.
# MIT License
#
# JCF_DEBUG - Debugging helpers for JUCE. Demo application.
#
# Don't forget to install the VisualStudio or Xcode debug scripts as
# well. These ensure that your IDEs debugger displays the contents
# of ValueTrees, Strings and Arrays in a useful way!
#
#
# Credland Technical Limited provide a range of consultancy and contract
# services including:
# - JUCE software development and support
# - information security consultancy
#
# Contact jim@credland.net
#
###################################
#
# Much Python/LLDB magic...
def __lldb_init_module(debugger, dict):
print "-- juce decoding modules loaded. www.credland.net"
print " - refer to the help for the 'type' command"
# ValueTree<*>
debugger.HandleCommand('type synthetic add "juce::ValueTree" --python-class juce_lldb_xcode.ValueTreeChildrenProvider -w juce')
# Array<*>
debugger.HandleCommand('type synthetic add -x "^juce::(ReferenceCounted)?Array<.*>" --python-class juce_lldb_xcode.ArrayChildrenProvider -w juce')
# Component
debugger.HandleCommand('type summary add juce::Component -F juce_lldb_xcode.ComponentSummary -w juce')
# String
debugger.HandleCommand('type summary add juce::String -F juce_lldb_xcode.string_summary -w juce')
# var
debugger.HandleCommand('type summary add juce::var -F juce_lldb_xcode.var_summary -w juce')
# Identifier
debugger.HandleCommand('type summary add juce::Identifier -F juce_lldb_xcode.identifier_summary -w juce')
# ScopedPointer
debugger.HandleCommand('type summary add -x "^juce::ScopedPointer<.*>" --summary-string "ScopedPointer<>=${*var.object}" -w juce')
# Rectangle<*>
debugger.HandleCommand('type summary add -x "^juce::Rectangle<.*>" --summary-string "${var.pos.x} ${var.pos.y} ${var.w} ${var.h}" -w juce')
debugger.HandleCommand('type category enable juce')
def string_summary(valueObject, dictionary):
#print dir(lldb.frame)
s = valueObject.GetChildMemberWithName('text').GetChildMemberWithName('data').GetSummary()
return s
def identifier_summary(valueObject, dictionary):
s = valueObject.GetChildMemberWithName('name').GetChildMemberWithName('text').GetChildMemberWithName('data').GetSummary()
if s is None:
return "((uninitalized))"
else:
return s
def rect_summary(valueObject, dictionary):
w = valueObject.GetChildMemberWithName('w').GetValue()
h = valueObject.GetChildMemberWithName('h').GetValue()
pos = valueObject.GetChildMemberWithName('pos')
x = pos.GetChildMemberWithName('x').GetValue()
y = pos.GetChildMemberWithName('y').GetValue()
s = "x=" + str(x) + " y=" + str(y)
s = s + " w=" + str(w) + " h=" + str(h)
return s
# Types of VAR
# class VariantType; friend class VariantType;
#
# class VariantType_Void; friend class VariantType_Void;
# class VariantType_Undefined; friend class VariantType_Undefined;
# class VariantType_Int; friend class VariantType_Int;
#
# class VariantType_Int64; friend class VariantType_Int64;
# class VariantType_Double; friend class VariantType_Double;
# class VariantType_Bool; friend class VariantType_Bool;
#
# class VariantType_String; friend class VariantType_String;
# class VariantType_Object; friend class VariantType_Object;
# class VariantType_Array; friend class VariantType_Array;
#
# class VariantType_Binary; friend class VariantType_Binary;
# class VariantType_Method; friend class VariantType_Method;
def var_summary(valueObject, dictionary):
varType = valueObject.GetChildMemberWithName('type').GetType()
varValue = valueObject.GetChildMemberWithName('value')
s = "t"
if varType.GetName() == "juce::var::VariantType_String *":
stringValue = varValue.GetChildMemberWithName('stringValue')
stringPointerType = valueObject.GetFrame().GetModule().FindFirstType('juce::String').GetPointerType()
print stringPointerType
stringPointer = stringValue.Cast(stringPointerType)
print stringPointer
s = 'string=' + stringPointer.Dereference().GetSummary() + stringPointer.GetValue()
# now we have to convert the .value to a pointer ...
if varType.GetName() == "juce::var::VariantType_Int *":
s = 'int=' + varValue.GetSummary()
return s
def ComponentSummary(valueObject, dictionary):
# Component 'name' parent=None visible=True location={ 0, 0, 20, 20 } opaque=False
print int(valueObject.GetChildMemberWithName('parentComponent').GetValue(), 16)
hasParent = int(valueObject.GetChildMemberWithName('parentComponent').GetValue(), 16) == 0
isVisible = valueObject.GetChildMemberWithName('flags').GetChildMemberWithName('visibleFlag').GetValue()
print type(isVisible)
name = string_summary(valueObject.GetChildMemberWithName('componentName'), dictionary)
s = name + " hasParent=" + str(hasParent) + " isVisible=" + str(isVisible)
return s
class ValueTreeChildrenProvider:
def __init__(self, valueObject, internalDict):
# this call should initialize the Python object using valobj as the
# variable to provide synthetic children for.
#
# JCF_ Most of the actual work is done in update()
print "VTCP with " + valueObject.GetName()
self.v = valueObject
self.count = 0
self.update()
return
def num_children(self):
# Return (a) properties and (b) children
return 4
def get_child_index(self, name):
# this call should return the index of the synthetic child whose name is
# given as argument
print "get_child_index: " + name
try:
return int(name.lstrip('[').rstrip(']'))
except:
return -1
def get_child_at_index(self, index):
if index == 0:
return self.ro.GetChildMemberWithName('properties').GetChildMemberWithName('values')
if index == 1:
return self.ro.GetChildMemberWithName('children')
if index == 2:
return self.ro.GetChildMemberWithName('parent')
if index == 3:
return self.ro.GetChildMemberWithName('type')
return None
def update(self):
# this call should be used to update the internal state of this Python
# object whenever the state of the variables in LLDB changes.[1]
self.ro = self.v.GetChildMemberWithName('object').GetChildMemberWithName('referencedObject')
return
def has_children(self):
# this call should return True if this object might have children, and False if
# this object can be guaranteed not to have children.[2]
return True
class ArrayChildrenProvider:
def __init__(self, valueObject, internalDict):
# this call should initialize the Python object using valobj as the
# variable to provide synthetic children for.
#
# JCF_ Most of the actual work is done in update()
print "ACP with " + valueObject.GetName()
self.v = valueObject
self.count = 0
self.update()
return
def num_children(self):
# this call should return the number of children that you want your
# object to have
#
# JC - no matter what we do here it seems to call get_child_at_index
# target.max-children times
if (self.count > 100):
print "WARNING count = " + self.count
return int(self.count)
def get_child_index(self, name):
# this call should return the index of the synthetic child whose name is
# given as argument
print "get_child_index: " + name
try:
return int(name.lstrip('[').rstrip(']'))
except:
return -1
def get_child_at_index(self, index):
# this call should return a new LLDB SBValue object representing
# the child at the index given as argument
if index < 0:
return None
if index >= self.count:
return None
try:
offset = index * self.data_size
return self.first_element.CreateChildAtOffset('[' + str(index) + ']', offset, self.data_type)
except:
print "Array<> error"
return None
def update(self):
# this call should be used to update the internal state of this Python
# object whenever the state of the variables in LLDB changes.[1]
data = self.v.GetChildMemberWithName('data')
self.first_element = data.GetChildMemberWithName('elements').GetChildMemberWithName('data')
self.data_type = self.first_element.GetType().GetPointeeType()
self.data_size = self.data_type.GetByteSize()
if self.first_element.IsValid():
# GetValue() returns a string(!) so we have to cast to an integer here.
try:
self.count = int(self.v.GetChildMemberWithName('numUsed').GetValue())
except TypeError:
print "ACP invalid numUsed. Set count to 0"
self.count = 0
else:
self.count = 0
print "ACP set self.count to " + str(self.count)
return
def has_children(self):
# this call should return True if this object might have children, and False if
# this object can be guaranteed not to have children.[2]
return self.count > 0