Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/tools/lldb_formatters.py
2723 views
1
# This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
3
import lldb
4
5
# HACK: LLDB's python API doesn't afford anything helpful for getting at variadic template parameters.
6
# We're forced to resort to parsing names as strings.
7
8
def read_non_cstring_from_data(data):
9
str_text = ""
10
for c in data.uint8s:
11
str_text += chr(c)
12
13
return str_text
14
15
def create_quoted_escaped_c_str(s):
16
"""Given a string, this function quotes the string and escapes any special characters (e.g. '\n', '\t')"""
17
return f'"{repr(s)[1:-1]}"'
18
19
def safe_summary_provider(func):
20
"""This decorator adds try/except around a function and returns the exception as a string
21
This is useful for summary providers to prevent python exceptions from being printed to the debug console.
22
It also makes it much easier to determine what variable generated the exception because the exception will
23
be shown in the debugger as the variable's summary.
24
"""
25
def wrapper(*args):
26
try:
27
return func(*args)
28
except Exception as e:
29
return f"Summary Error: {e}"
30
return wrapper
31
32
def templateParams(s):
33
depth = 0
34
start = s.find("<") + 1
35
result = []
36
for i, c in enumerate(s[start:], start):
37
if c == "<":
38
depth += 1
39
elif c == ">":
40
if depth == 0:
41
result.append(s[start:i].strip())
42
break
43
depth -= 1
44
elif c == "," and depth == 0:
45
result.append(s[start:i].strip())
46
start = i + 1
47
return result
48
49
50
def getType(target, typeName):
51
stars = 0
52
53
typeName = typeName.strip()
54
while typeName.endswith("*"):
55
stars += 1
56
typeName = typeName[:-1]
57
58
if typeName.startswith("const "):
59
typeName = typeName[6:]
60
61
ty = target.FindFirstType(typeName.strip())
62
for _ in range(stars):
63
ty = ty.GetPointerType()
64
65
return ty
66
67
68
@safe_summary_provider
69
def luau_variant_summary(valobj, internal_dict, options):
70
return valobj.GetChildMemberWithName("type").GetSummary()[1:-1]
71
72
73
class LuauVariantSyntheticChildrenProvider:
74
node_names = ["type", "value"]
75
76
def __init__(self, valobj, internal_dict):
77
self.valobj = valobj
78
self.type_index = None
79
self.current_type = None
80
self.type_params = []
81
self.stored_value = None
82
83
def num_children(self):
84
return len(self.node_names)
85
86
def has_children(self):
87
return True
88
89
def get_child_index(self, name):
90
try:
91
return self.node_names.index(name)
92
except ValueError:
93
return -1
94
95
def get_child_at_index(self, index):
96
try:
97
node = self.node_names[index]
98
except IndexError:
99
return None
100
101
if node == "type":
102
if self.current_type:
103
return self.valobj.CreateValueFromExpression(
104
node, f'(const char*)"{self.current_type.GetDisplayTypeName()}"'
105
)
106
else:
107
return self.valobj.CreateValueFromExpression(
108
node, '(const char*)"<unknown type>"'
109
)
110
elif node == "value":
111
if self.stored_value is not None:
112
if self.current_type is not None:
113
return self.valobj.CreateValueFromData(
114
node, self.stored_value.GetData(), self.current_type
115
)
116
else:
117
return self.valobj.CreateValueExpression(
118
node, '(const char*)"<unknown type>"'
119
)
120
else:
121
return self.valobj.CreateValueFromExpression(
122
node, '(const char*)"<no stored value>"'
123
)
124
else:
125
return None
126
127
def update(self):
128
self.type_index = self.valobj.GetChildMemberWithName(
129
"typeId"
130
).GetValueAsSigned()
131
self.type_params = templateParams(
132
self.valobj.GetType().GetCanonicalType().GetName()
133
)
134
135
if len(self.type_params) > self.type_index:
136
self.current_type = getType(
137
self.valobj.GetTarget(), self.type_params[self.type_index]
138
)
139
140
if self.current_type:
141
storage = self.valobj.GetChildMemberWithName("storage")
142
self.stored_value = storage.Cast(self.current_type)
143
else:
144
self.stored_value = None
145
else:
146
self.current_type = None
147
self.stored_value = None
148
149
return False
150
151
152
class DenseHashTableSyntheticChildrenProvider:
153
def __init__(self, valobj, internal_dict):
154
"""this call should initialize the Python object using valobj as the variable to provide synthetic children for"""
155
self.valobj = valobj
156
self.update()
157
158
def num_children(self):
159
"""this call should return the number of children that you want your object to have"""
160
return self.capacity
161
162
def get_child_index(self, name):
163
"""this call should return the index of the synthetic child whose name is given as argument"""
164
try:
165
if name.startswith("[") and name.endswith("]"):
166
return int(name[1:-1])
167
else:
168
return -1
169
except Exception as e:
170
print("get_child_index exception", e)
171
return -1
172
173
def get_child_at_index(self, index):
174
"""this call should return a new LLDB SBValue object representing the child at the index given as argument"""
175
try:
176
dataMember = self.valobj.GetChildMemberWithName("data")
177
178
data = dataMember.GetPointeeData(index)
179
180
return self.valobj.CreateValueFromData(
181
f"[{index}]",
182
data,
183
dataMember.Dereference().GetType(),
184
)
185
186
except Exception as e:
187
print("get_child_at_index error", e)
188
189
def update(self):
190
"""this call should be used to update the internal state of this Python object whenever the state of the variables in LLDB changes.[1]
191
Also, this method is invoked before any other method in the interface."""
192
self.capacity = self.valobj.GetChildMemberWithName(
193
"capacity"
194
).GetValueAsUnsigned()
195
196
def has_children(self):
197
"""this call should return True if this object might have children, and False if this object can be guaranteed not to have children.[2]"""
198
return True
199
200
201
class DenseHashMapSyntheticChildrenProvider:
202
fixed_names = ["count", "capacity"]
203
max_expand_children = 100
204
max_expand_capacity = 1000
205
206
def __init__(self, valobj, internal_dict):
207
self.valobj = valobj
208
self.count = 0
209
self.capacity = 0
210
211
def num_children(self):
212
return min(self.max_expand_children, self.count) + len(self.fixed_names)
213
214
def get_child_index(self, name):
215
try:
216
if name in self.fixed_names:
217
return self.fixed_names.index(name)
218
219
return -1
220
except Exception as e:
221
print("get_child_index exception", e, name)
222
return -1
223
224
def get_child_at_index(self, index):
225
try:
226
if index < len(self.fixed_names):
227
fixed_name = self.fixed_names[index]
228
impl_child = self.valobj.GetValueForExpressionPath(
229
f".impl.{fixed_name}")
230
231
return self.valobj.CreateValueFromData(fixed_name, impl_child.GetData(), impl_child.GetType())
232
else:
233
index -= len(self.fixed_names)
234
235
empty_key_valobj = self.valobj.GetValueForExpressionPath(
236
f".impl.empty_key")
237
key_type = empty_key_valobj.GetType().GetCanonicalType().GetName()
238
skipped = 0
239
240
for slot in range(0, min(self.max_expand_capacity, self.capacity)):
241
slot_pair = self.valobj.GetValueForExpressionPath(
242
f".impl.data[{slot}]")
243
slot_key_valobj = slot_pair.GetChildMemberWithName("first")
244
245
eq_test_valobj = self.valobj.EvaluateExpression(
246
f"*(reinterpret_cast<const {key_type}*>({empty_key_valobj.AddressOf().GetValueAsUnsigned()})) == *(reinterpret_cast<const {key_type}*>({slot_key_valobj.AddressOf().GetValueAsUnsigned()}))")
247
if eq_test_valobj.GetValue() == "true":
248
continue
249
250
# Skip over previous occupied slots.
251
if index > skipped:
252
skipped += 1
253
continue
254
255
return self.valobj.CreateValueFromData(f"[{index}]", slot_pair.GetData(), slot_pair.GetType())
256
257
except Exception as e:
258
print("get_child_at_index error", e, index)
259
260
def update(self):
261
try:
262
self.capacity = self.count = self.valobj.GetValueForExpressionPath(
263
".impl.capacity").GetValueAsUnsigned()
264
self.count = self.valobj.GetValueForExpressionPath(
265
".impl.count").GetValueAsUnsigned()
266
except Exception as e:
267
print("update error", e)
268
269
def has_children(self):
270
return True
271
272
273
class DenseHashSetSyntheticChildrenProvider:
274
fixed_names = ["count", "capacity"]
275
max_expand_children = 100
276
max_expand_capacity = 1000
277
278
def __init__(self, valobj, internal_dict):
279
self.valobj = valobj
280
self.count = 0
281
self.capacity = 0
282
283
def num_children(self):
284
return min(self.max_expand_children, self.count) + len(self.fixed_names)
285
286
def get_child_index(self, name):
287
try:
288
if name in self.fixed_names:
289
return self.fixed_names.index(name)
290
291
return -1
292
except Exception as e:
293
print("get_child_index exception", e, name)
294
return -1
295
296
def get_child_at_index(self, index):
297
try:
298
if index < len(self.fixed_names):
299
fixed_name = self.fixed_names[index]
300
impl_child = self.valobj.GetValueForExpressionPath(
301
f".impl.{fixed_name}")
302
303
return self.valobj.CreateValueFromData(fixed_name, impl_child.GetData(), impl_child.GetType())
304
else:
305
index -= len(self.fixed_names)
306
307
empty_key_valobj = self.valobj.GetValueForExpressionPath(
308
f".impl.empty_key")
309
key_type = empty_key_valobj.GetType().GetCanonicalType().GetName()
310
skipped = 0
311
312
for slot in range(0, min(self.max_expand_capacity, self.capacity)):
313
slot_valobj = self.valobj.GetValueForExpressionPath(
314
f".impl.data[{slot}]")
315
316
eq_test_valobj = self.valobj.EvaluateExpression(
317
f"*(reinterpret_cast<const {key_type}*>({empty_key_valobj.AddressOf().GetValueAsUnsigned()})) == *(reinterpret_cast<const {key_type}*>({slot_valobj.AddressOf().GetValueAsUnsigned()}))")
318
if eq_test_valobj.GetValue() == "true":
319
continue
320
321
# Skip over previous occupied slots.
322
if index > skipped:
323
skipped += 1
324
continue
325
326
return self.valobj.CreateValueFromData(f"[{index}]", slot_valobj.GetData(), slot_valobj.GetType())
327
328
except Exception as e:
329
print("get_child_at_index error", e, index)
330
331
def update(self):
332
try:
333
self.capacity = self.count = self.valobj.GetValueForExpressionPath(
334
".impl.capacity").GetValueAsUnsigned()
335
self.count = self.valobj.GetValueForExpressionPath(
336
".impl.count").GetValueAsUnsigned()
337
except Exception as e:
338
print("update error", e)
339
340
def has_children(self):
341
return True
342
343
344
def luau_symbol_summary(valobj, internal_dict, options):
345
local = valobj.GetChildMemberWithName("local")
346
global_ = valobj.GetChildMemberWithName(
347
"global").GetChildMemberWithName("value")
348
349
if local.GetValueAsUnsigned() != 0:
350
return f'local {local.GetChildMemberWithName("name").GetChildMemberWithName("value").GetSummary()}'
351
elif global_.GetValueAsUnsigned() != 0:
352
return f"global {global_.GetSummary()}"
353
else:
354
return "???"
355
356
357
class AstArraySyntheticChildrenProvider:
358
def __init__(self, valobj, internal_dict):
359
self.valobj = valobj
360
361
def num_children(self):
362
return self.size
363
364
def get_child_index(self, name):
365
try:
366
if name.startswith("[") and name.endswith("]"):
367
return int(name[1:-1])
368
else:
369
return -1
370
except Exception as e:
371
print("get_child_index error:", e)
372
373
def get_child_at_index(self, index):
374
try:
375
dataMember = self.valobj.GetChildMemberWithName("data")
376
data = dataMember.GetPointeeData(index)
377
return self.valobj.CreateValueFromData(
378
f"[{index}]", data, dataMember.Dereference().GetType()
379
)
380
except Exception as e:
381
print("get_child_index error:", e)
382
383
def update(self):
384
self.size = self.valobj.GetChildMemberWithName(
385
"size").GetValueAsUnsigned()
386
387
def has_children(self):
388
return True
389
390
391
def luau_typepath_property_summary(valobj, internal_dict, options):
392
name = valobj.GetChildMemberWithName("name").GetSummary()
393
result = "["
394
395
read_write = False
396
try:
397
fflag_valobj = valobj.GetFrame().GetValueForVariablePath(
398
"FFlag::LuauSolverV2::value")
399
400
read_write = fflag_valobj.GetValue() == "true"
401
except Exception as e:
402
print("luau_typepath_property_summary error:", e)
403
404
if read_write:
405
is_read = valobj.GetChildMemberWithName("isRead").GetValue() == "true"
406
if is_read:
407
result += "read "
408
else:
409
result += "write "
410
411
result += name
412
result += "]"
413
return result
414
415
@safe_summary_provider
416
def luau_tstring_summary(valobj, internal_dict):
417
str_start = valobj.GetChildMemberWithName("data")
418
str_len = valobj.GetChildMemberWithName("len").GetValueAsUnsigned(0)
419
str_data = read_non_cstring_from_data(str_start.GetPointeeData(0, str_len))
420
return create_quoted_escaped_c_str(str_data)
421
422
def tvalue_get_type_name(valobj):
423
type_val = valobj.GetChildMemberWithName("tt").GetValueAsUnsigned(0)
424
type_map = [
425
'TNIL',
426
'TBOOLEAN',
427
'TLIGHTUSERDATA',
428
'TNUMBER',
429
'TVECTOR',
430
'TSTRING',
431
'TTABLE',
432
'TFUNCTION',
433
'TUSERDATA',
434
'TTHREAD',
435
'TBUFFER',
436
'TPROTO',
437
'TUPVAL',
438
'TDEADKEY',
439
]
440
441
return f"{type_map[type_val] if type_val < len(type_map) else '<invalid type>'}"
442
443
@safe_summary_provider
444
def luau_tvalue_summary(valobj, internal_dict):
445
if valobj.GetType().IsPointerType():
446
valobj = valobj.Dereference()
447
valobj = valobj.GetNonSyntheticValue()
448
449
type_name = tvalue_get_type_name(valobj)
450
451
if type_name == 'TBOOLEAN':
452
bool_val = valobj.GetChildMemberWithName("value").GetChildMemberWithName("b").GetValueAsUnsigned(0)
453
bool_str = ["false", "true"][bool_val]
454
return f"{bool_str} ({type_name})"
455
elif type_name == 'TNUMBER':
456
num_val = valobj.GetChildMemberWithName("value").GetChildMemberWithName("n")
457
return f"{num_val.GetValue()}"
458
elif type_name == 'TVECTOR':
459
target = valobj.GetTarget()
460
float_type = target.GetBasicType(lldb.eBasicTypeFloat)
461
462
x_val = valobj.GetChildMemberWithName("value").GetChildMemberWithName("v").GetChildAtIndex(0).GetValue()
463
y_val = valobj.GetChildMemberWithName("value").GetChildMemberWithName("v").GetChildAtIndex(1).GetValue()
464
z_val_addr = valobj.GetChildMemberWithName("extra").GetChildAtIndex(0).GetAddress()
465
z_val = target.CreateValueFromAddress("z", z_val_addr, float_type).GetValue()
466
return f"({x_val}, {y_val}, {z_val}) ({type_name})"
467
elif type_name == 'TSTRING':
468
ts = valobj.GetChildMemberWithName("value").GetChildMemberWithName("gc").GetChildMemberWithName("ts")
469
return f"{ts.GetSummary()}"
470
471
return type_name
472
473
class TValueSyntheticChildrenProvider:
474
def __init__(self, valobj, internal_dict):
475
if valobj.GetType().IsPointerType():
476
valobj = valobj.Dereference()
477
valobj = valobj.GetNonSyntheticValue()
478
479
self.valobj = valobj
480
self.children = []
481
482
def num_children(self):
483
return len(self.children)
484
485
def has_children(self):
486
return len(self.children) > 0
487
488
def get_child_at_index(self, index):
489
if index < len(self.children):
490
return self.children[index]
491
return None
492
493
def update(self):
494
type_name = tvalue_get_type_name(self.valobj)
495
if type_name == 'TTABLE':
496
luatable = self.valobj.GetChildMemberWithName("value").GetChildMemberWithName("gc").GetChildMemberWithName("h")
497
self.children = [luatable.Clone("table")]
498
elif type_name == 'TFUNCTION':
499
luatable = self.valobj.GetChildMemberWithName("value").GetChildMemberWithName("gc").GetChildMemberWithName("cl")
500
self.children = [luatable.Clone("function")]
501
return False
502
503
def luau_tkey_summary(valobj, internal_dict):
504
"""TKey has virtually the same layout as TValue, so we can reuse the same summary logic."""
505
return luau_tvalue_summary(valobj, internal_dict)
506
507
def luau_table_get_entries(valobj):
508
"""Returns all the valid table entries of a table as two lists. The first list contains the array entries, and the second list contains the hash entries."""
509
array_entries = []
510
size_array = valobj.GetChildMemberWithName("sizearray").GetValueAsSigned(0)
511
array = valobj.GetChildMemberWithName("array")
512
array_addr = array.GetValueAsAddress()
513
tvalue_type = array.GetType().GetPointeeType()
514
tvalue_size = tvalue_type.GetByteSize()
515
for i in range(size_array):
516
entry = array.CreateValueFromAddress(str(i+1), int(array_addr) + i * tvalue_size, tvalue_type).GetNonSyntheticValue()
517
tt = entry.GetChildMemberWithName("tt").GetValueAsUnsigned()
518
if tt != 0: # Skip over nil entries.
519
array_entries.append(entry)
520
521
hash_entries = []
522
size_node = 1 << valobj.GetChildMemberWithName("lsizenode").GetValueAsUnsigned()
523
node = valobj.GetChildMemberWithName("node")
524
node_addr = node.GetValueAsAddress()
525
node_type = node.GetType().GetPointeeType()
526
node_size = node_type.GetByteSize()
527
528
for i in range(size_node):
529
entry = array.CreateValueFromAddress(f'Node_{i}', int(node_addr) + i * node_size, node_type).GetNonSyntheticValue()
530
key = entry.GetChildMemberWithName("key")
531
val = entry.GetChildMemberWithName("val").GetNonSyntheticValue()
532
tt = val.GetChildMemberWithName("tt").GetValueAsUnsigned()
533
if tt != 0: # Skip over entries with nil values.
534
hash_entries.append(entry)
535
536
return array_entries, hash_entries
537
538
class LuauTableSyntheticChildrenProvider:
539
def __init__(self, valobj, internal_dict):
540
self.valobj = valobj
541
self.array_entries = []
542
self.hash_entries = []
543
544
def num_children(self):
545
return len(self.array_entries) + len(self.hash_entries)
546
547
def has_children(self):
548
return self.num_children() > 0
549
550
def get_child_at_index(self, index):
551
array_count = len(self.array_entries)
552
if index < array_count:
553
return self.array_entries[index]
554
hash_index = index - array_count
555
if hash_index < len(self.hash_entries):
556
return self.hash_entries[hash_index]
557
return None
558
559
def update(self):
560
self.array_entries, self.hash_entries = luau_table_get_entries(self.valobj)
561
return False
562
563
@safe_summary_provider
564
def luau_table_summary(valobj, internal_dict):
565
valobj = valobj.GetNonSyntheticValue()
566
array_entries, hash_entries = luau_table_get_entries(valobj)
567
result = f"LuaTable (size={len(array_entries) + len(hash_entries)})"
568
return result
569
570
def convert_ptr_size_to_array(name, ptr, num_elem):
571
"""Converts a SBValue ptr into an array using the name and number of elements provided
572
num_elems may be a number of an SBValue with a numeric value.
573
"""
574
if isinstance(num_elem, lldb.SBValue):
575
if num_elem.GetType().GetTypeFlags() & lldb.eTypeIsSigned:
576
num_elem = num_elem.GetValueAsSigned()
577
else:
578
num_elem = num_elem.GetValueAsUnsigned()
579
array_type = ptr.GetType().GetPointeeType().GetArrayType(num_elem)
580
return ptr.CreateValueFromAddress(name, int(ptr.GetValueAsAddress()), array_type)
581
582
def read_from_pointer_to_array(ptr, index):
583
""" Reads a single element from a pointer to an array. This function is useful because lldb only allows reading
584
the 0'th element using GetChildAtIndex for a pointer type.
585
586
ptr should be a SBValue that is a pointer
587
index is the index of the array element to read (starting from 0)
588
"""
589
array = convert_ptr_size_to_array('ar', ptr, index+1)
590
return array.GetChildAtIndex(index)
591
592
def remove_outer_quotes(s):
593
return s[1:-1]
594
595
@safe_summary_provider
596
def luau_callinfo_summary(valobj, internal_dict):
597
func = valobj.GetChildMemberWithName("func").GetNonSyntheticValue()
598
cl = func.GetChildMemberWithName("value").GetChildMemberWithName("gc").GetChildMemberWithName("cl")
599
isC = cl.GetChildMemberWithName("isC").GetValueAsUnsigned(0) != 0
600
if not isC:
601
savedpc = valobj.GetChildMemberWithName("savedpc").GetValueAsAddress()
602
proto = cl.GetChildMemberWithName("l").GetChildMemberWithName("p")
603
code = proto.GetChildMemberWithName("code").GetValueAsAddress()
604
linegaplog2 = proto.GetChildMemberWithName("linegaplog2").GetValueAsUnsigned()
605
pcRel = 0
606
if int(savedpc) != 0:
607
pcRel = (int(savedpc) - int(code))//4 - 1
608
abslineinfo = proto.GetChildMemberWithName("abslineinfo")
609
lineinfo = proto.GetChildMemberWithName("lineinfo")
610
source = proto.GetChildMemberWithName("source")
611
line = read_from_pointer_to_array(abslineinfo, pcRel >> linegaplog2).GetValueAsUnsigned() + read_from_pointer_to_array(lineinfo, pcRel).GetValueAsUnsigned()
612
debugname = proto.GetChildMemberWithName("debugname")
613
return f"{remove_outer_quotes(source.GetSummary())}:{line} function {remove_outer_quotes(debugname.GetSummary())}"
614
else:
615
c = cl.GetChildMemberWithName("c")
616
f = c.GetChildMemberWithName("f")
617
debugname = c.GetChildMemberWithName("debugname")
618
return f"=[C] function {remove_outer_quotes(debugname.GetSummary())} {f.GetSummary()}"
619
620
@safe_summary_provider
621
def luau_proto_summary(valobj, internal_dict):
622
if valobj.GetType().IsPointerType():
623
valobj = valobj.Dereference()
624
valobj = valobj.GetNonSyntheticValue()
625
source = valobj.GetChildMemberWithName("source")
626
debugname = valobj.GetChildMemberWithName("debugname")
627
linedefined = valobj.GetChildMemberWithName("linedefined").GetValueAsUnsigned()
628
numparams = valobj.GetChildMemberWithName("numparams").GetValueAsUnsigned()
629
nups = valobj.GetChildMemberWithName("nups").GetValueAsUnsigned()
630
return f'{remove_outer_quotes(source.GetSummary())}:{linedefined} {"function " + remove_outer_quotes(debugname.GetSummary()) if debugname.GetValueAsUnsigned() != 0 else ""} [{numparams} arg, {nups} upval]'
631
632
class ProtoSyntheticChildrenProvider:
633
def __init__(self, valobj, internal_dict):
634
if valobj.GetType().IsPointerType():
635
valobj = valobj.Dereference()
636
valobj = valobj.GetNonSyntheticValue()
637
638
self.valobj = valobj
639
640
def num_children(self):
641
return len(self.children)
642
643
def has_children(self):
644
return len(self.children) > 0
645
646
def get_child_at_index(self, index):
647
if index < len(self.children):
648
return self.children[index]
649
return None
650
651
def update(self):
652
children = []
653
self.children = children
654
valobj = self.valobj
655
656
k = valobj.GetChildMemberWithName("k")
657
sizek = valobj.GetChildMemberWithName("sizek")
658
constants_array = convert_ptr_size_to_array("[constants]", k, sizek)
659
children.append(constants_array)
660
661
locvars = valobj.GetChildMemberWithName("locvars")
662
sizelocvars = valobj.GetChildMemberWithName("sizelocvars")
663
locvars_array = convert_ptr_size_to_array("[locvars]", locvars, sizelocvars)
664
children.append(locvars_array)
665
666
sizecode = valobj.GetChildMemberWithName("sizecode")
667
code = valobj.GetChildMemberWithName("code")
668
code_array = convert_ptr_size_to_array("[bytecode]", code, sizecode)
669
children.append(code_array)
670
671
sizep = valobj.GetChildMemberWithName("sizep")
672
p = valobj.GetChildMemberWithName("p")
673
p_array = convert_ptr_size_to_array("[functions]", p, sizep)
674
children.append(p_array)
675
676
sizeupvalues = valobj.GetChildMemberWithName("sizeupvalues")
677
upvalues = valobj.GetChildMemberWithName("upvalues")
678
upvalues_array = convert_ptr_size_to_array("[upvalues]", upvalues, sizeupvalues)
679
children.append(upvalues_array)
680
681
children.append(self.valobj.GetChildMemberWithName("source"))
682
return False
683
684
@safe_summary_provider
685
def luau_closure_summary(valobj, internal_dict):
686
if valobj.GetType().IsPointerType():
687
valobj = valobj.Dereference()
688
valobj = valobj.GetNonSyntheticValue()
689
690
isC = valobj.GetChildMemberWithName("isC").GetValueAsUnsigned(0) != 0
691
if isC:
692
f = valobj.GetChildMemberWithName("c").GetChildMemberWithName("f")
693
return f.GetSummary()
694
else:
695
p = valobj.GetChildMemberWithName("l").GetChildMemberWithName("p")
696
return p.GetSummary()
697
698
# Note for future work:
699
# LLDB is limited in terms of expansion. i.e. a child provider can expand to a set
700
# of children, but it can't directly express how those children can be expanded further.
701
# To acheive this functionality for special situations (e.g. showing callstacks in reverse
702
# order) it may be necessary to create types that are only used for debugging purposes which
703
# an then define how their children are expanded.
704
#
705
# Here's an example of how EvaluateExpression can be used to create such a type on the fly:
706
# e = lldb.target.EvaluateExpression("struct DebuggerOnlyType{int a; float b;}; (DebuggerOnlyType*)0;")
707