@@ -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
3640def 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+
127142class 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
169184class 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+
388541control_character_finder = re .compile (r'[\x00-\x1F]' )
389542escaped_characters = re .compile (r'[\\"]' )
390543def escape_string (str ):
0 commit comments