Skip to content

Commit 8f2d686

Browse files
authored
Merge pull request #5 from dacki/master
2 parents 9502abb + 0cfa144 commit 8f2d686

1 file changed

Lines changed: 154 additions & 1 deletion

File tree

lldb_dlang.py

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ def __lldb_init_module(debugger, dict):
2727

2828
attach_synthetic_to_type(DAssocArrayPrinter, r'^_AArray_|[^0-9\[][^\[]*\]$', True)
2929

30+
attach_synthetic_to_type(DSArrayPrinter, r'\[[0-9]+\]$', True)
31+
3032
attach_synthetic_to_type(DArrayPrinter, r'^_Array_|\[\]$', True)
3133

3234
attach_synthetic_to_type(DCStringPrinter, r'^_Array_char$|^_Array_char8_t$|^string$|^(const|immutable)?\(?char\)?\s*\[\]$', True)
3335
attach_synthetic_to_type(DWStringPrinter, r'^_Array_wchar_t$|^_Array_char16_t$|^wstring$|^(const|immutable)?\(?wchar\)?\s*\[\]$', True)
3436
attach_synthetic_to_type(DDStringPrinter, r'^_Array_dchar$|^dstring$|^(const|immutable)?\(?dchar\)?\s*\[\]$', True)
37+
38+
attach_synthetic_to_type(DObjectPrinter, r' \*$', True)
3539

3640
def attach_synthetic_to_type(synth_class, type_name, is_regex=False):
3741
global module, d_category
@@ -124,6 +128,17 @@ def get_child_index(self, name):
124128
def get_summary(self):
125129
return None
126130

131+
class DSArrayPrinter(BaseSynthProvider):
132+
"print D static arrays"
133+
def num_children(self):
134+
return self.valobj.GetNumChildren()
135+
136+
def get_child_at_index(self, index):
137+
return self.valobj.GetChildAtIndex(index)
138+
139+
def get_summary(self):
140+
return get_array_summary(self)
141+
127142
class DArrayPrinter(BaseSynthProvider):
128143
"print D arrays"
129144

@@ -164,7 +179,7 @@ def get_child_index(self, name):
164179
raise
165180

166181
def get_summary(self):
167-
return get_array_summary(self)
182+
return '&' + get_array_summary(self)
168183

169184
class DBaseStringPrinter(DArrayPrinter):
170185
def get_child_at_index(self, index):
@@ -385,6 +400,144 @@ def get_child_index(self, name):
385400
def get_summary(self):
386401
return get_map_summary(self)
387402

403+
404+
def is_ptr_to_class(valobj):
405+
''' type of dereferenced value is a:
406+
class if directbaseclass > 0
407+
interface if bytesize == 0 (using DMD, LDC uses 8 bytes)
408+
primitivie otherwise
409+
'''
410+
return bool(valobj.Dereference().GetType().GetNumberOfDirectBaseClasses() > 0)
411+
412+
class DObjectPrinter(BaseSynthProvider):
413+
def initialize(self):
414+
pass
415+
416+
def update(self):
417+
try:
418+
self._update()
419+
except Exception as e:
420+
log.error('%s', e)
421+
raise
422+
423+
def _update(self):
424+
type_name = self.valobj.GetTypeName()
425+
if type_name in ['unsigned long *', 'void *'] or type_name.endswith('**'):
426+
return
427+
428+
if self.valobj.GetName().startswith('*'):
429+
# stop recursion when dereferencing values
430+
return
431+
432+
if is_ptr_to_class(self.valobj):
433+
# print('should be class:',self.valobj.GetTypeName())
434+
valobj = self.get_dynamic_value_from_address(self.valobj.GetValueAsUnsigned())
435+
if valobj is None:
436+
log.debug("couldn't get dynamic value from type %s", self.valobj.GetTypeName())
437+
return
438+
439+
self.valobj = valobj
440+
self.set_type_name(self.valobj)
441+
return
442+
443+
# print('is not a class:',self.valobj.GetTypeName())
444+
interface_type = self.valobj.GetType().GetPointeeType()
445+
if interface_type.GetByteSize() not in [0,8]:
446+
# interfaces size in dmd:0, ldc:8. Should filter out some false positives.
447+
return
448+
449+
target = self.valobj.target
450+
451+
# object of any interface I (technically I* b/c reference semantics) can be cast into Interface***
452+
453+
address = self.valobj.Cast(target.FindFirstType("void").GetPointerType().GetPointerType().GetPointerType())
454+
interface_struct_address = address.Dereference().Dereference().GetValueAsUnsigned()
455+
456+
# Interface has field 'offset' at relative location 0x18
457+
offset_address = interface_struct_address + 0x18
458+
offset = self.valobj.CreateValueFromAddress("offset_ptr", offset_address, target.FindFirstType("ulong").GetPointerType())
459+
460+
461+
# offset is relative location between interface and object pointer
462+
# object pointer can be cast into TypeInfo_Class**
463+
# TypeInfo_Class has field 'name' at relative location 0x20
464+
object_address = address.GetValueAsUnsigned() - offset.GetValueAsUnsigned()
465+
466+
dynamic_value= self.get_dynamic_value_from_address(object_address)
467+
if dynamic_value:
468+
# if not then value was not an interface to begin with
469+
self.valobj = dynamic_value
470+
471+
self.set_type_name(self.valobj)
472+
473+
def set_type_name(self, value):
474+
self.type_name = self.valobj.GetTypeName()
475+
if '!' in self.type_name:
476+
# template type names have a constant Suffix, i.e. mymodule.MyGenericType!int.Template
477+
self.type_name = self.type_name[0:-9]
478+
479+
480+
481+
def get_dynamic_value_from_address(self, address):
482+
target: lldb.SBTarget = self.valobj.GetTarget()
483+
void_ptr_type:lldb.SBType = target.FindFirstType("void").GetPointerType()
484+
485+
typeinfo_class = self.valobj.CreateValueFromAddress("obj_ptr", address,void_ptr_type.GetPointerType())
486+
# TypeInfo_Class has field 'name' at relative location 0x20
487+
tic_address = typeinfo_class.Dereference().GetValueAsUnsigned()
488+
if not tic_address:
489+
return
490+
name_address = tic_address + 0x20
491+
name_value = self.valobj.CreateValueFromAddress("class_name", name_address, target.FindFirstType("string"))
492+
name = (name_value.GetSummary() or '').strip('"')
493+
if not name:
494+
return
495+
496+
tpObject = target.FindFirstType(name)
497+
if not tpObject and '.' not in name:
498+
# dmd: 'object' module is implicitly imported
499+
tpObject = target.FindFirstType('object.' + name)
500+
501+
if not tpObject and '.' in name:
502+
# ldc: doesn't find types prefixed with e.g. 'object.'
503+
last_idx = name.rfind('.')
504+
tpObject = target.FindFirstType(name[last_idx+1:])
505+
506+
if not tpObject:
507+
# TODO: LDC does not publish types unless they are used as static type
508+
# print('could not find type', name)
509+
log.error('could not find type %s', name)
510+
return
511+
512+
return self.valobj.CreateValueFromAddress('', address, tpObject)
513+
514+
def num_children(self):
515+
return self.valobj.GetNumChildren()
516+
517+
def has_children(self):
518+
return self.valobj.GetNumChildren() > 0
519+
520+
def get_child_at_index(self, index):
521+
return self.valobj.GetChildAtIndex(index)
522+
523+
def get_child_index(self, name):
524+
return self.valobj.GetIndexOfChildWithName(name)
525+
526+
def get_summary(self):
527+
if getattr(self, 'type_name', ''):
528+
return self.type_name
529+
530+
try:
531+
tpVoidPtr = self.valobj.target.FindFirstType("void").GetPointerType()
532+
addr= self.valobj.Cast(tpVoidPtr).GetValueAsUnsigned()
533+
if not addr:
534+
return '%s(null)' % self.valobj.GetTypeName()
535+
return '%s(0x%016x)' % (self.valobj.GetTypeName(), addr)
536+
except Exception as e:
537+
log.error('%s', e)
538+
raise
539+
540+
388541
control_character_finder = re.compile(r'[\x00-\x1F]')
389542
escaped_characters = re.compile(r'[\\"]')
390543
def escape_string(str):

0 commit comments

Comments
 (0)