text: # GDB Sol extensions
  
  import gdb.printing
  import sys
  import traceback
  
  class _CatchExceptions(object):
      def __init__(self):
          self.excs = []
      def print_eidx(self, idx):
          traceback.print_exception(*self.excs[idx])
      def __enter__(self):
          pass
      def __exit__(self, t, v, tb):
          if t is not None:
              self.excs.append((t, v, tb))
  guard = _CatchExceptions()
  
  class DslArray(gdb.Function):
      '''Returns the (DSL_DATATYPE[]) array base of a dsl_array or dsl_seq (if it wraps an array), else NULL'''
  
      def __init__(self):
          super(DslArray, self).__init__('dsl_array')
  
      def invoke(self, val):
          with guard:
              stype = str(val.type)
              tp = gdb.lookup_type('sol_object_t').pointer()
              if str(val.type).startswith('dsl_seq'):
                  if str(val['type']) != 'DSL_SEQ_ARRAY':
                      return gdb.Value(0).cast(tp.pointer())
                  val = val['array']
              if str(val.type).startswith('dsl_array'):
                  return val['data'].dereference().cast(tp.array(val['len']))
              return gdb.Value(0).cast(tp.pointer())
  DslArray.instance = DslArray()
  
  class DslLen(gdb.Function):
      '''Returns the length of a DSL sequence'''
  
      def __init__(self):
          super(DslLen, self).__init__('dsl_array')
  
      def invoke(self, val):
          with guard:
              stype = str(val.type)
              if stype.startswith('dsl_seq'):
                  return int(gdb.lookup_symbol('dsl_seq_len')[0].value()(val))
              if stype.startswith('dsl_array'):
                  return int(gdb.lookup_symbol('dsl_array_len')[0].value()(val))
              if stype.startswith('dsl_list'):
                  return int(gdb.lookup_symbol('dsl_list_len')[0].value()(val))
              return -1
  DslLen.instance = DslLen()
  
  class SolObj(gdb.Function):
      '''Casts the argument to a sol_object_t *'''
  
      def __init__(self):
          super(SolObj, self).__init__('sol_obj')
  
      def invoke(self, val):
          with guard:
              return val.cast(gdb.lookup_type('sol_object_t').pointer())
  SolObj.instance = SolObj()
  
  class SolObjectPrettyPrinter(object):
      STYPE_TO_DISPHINT = {
              'SOL_SINGLET': 'string',
              'SOL_INTEGER': 'number',
              'SOL_FLOAT': 'number',
              'SOL_STRING': 'string',
              'SOL_LIST': 'array',
              'SOL_MAP': 'map',
              'SOL_MCELL': 'map',
              'SOL_FUNCTION': 'function',
              'SOL_CFUNCTION': 'function',
              'SOL_STMT': 'syntax',
              'SOL_EXPR': 'syntax',
      }
  
      def __init__(self, obj):
          self.obj = obj
  
      def display_hint(self):
          return self.STYPE_TO_DISPHINT.get(str(self.obj['type']), 'string')
  
      def to_string(self):
          with guard:
              return getattr(self, 'str_'+str(self.obj['type']), self.str_default)(self.obj)
  
      def str_default(self, obj):
          return '<Unknown object %r type %s>'%(obj, str(obj['type']))
  
      def str_SOL_SINGLET(self, obj):
          return obj['str']
  
      def str_SOL_INTEGER(self, obj):
          return str(obj['ival'])
  
      def str_SOL_FLOAT(self, obj):
          return str(obj['fval'])
  
      def str_SOL_STRING(self, obj):
          return obj['str']
  
      def str_SOL_LIST(self, obj):
          return '[List len=%d]'%(DslLen.instance.invoke(obj['seq']),)
  
      def str_SOL_MAP(self, obj):
          return '{Map len=%d}'%(DslLen.instance.invoke(obj['seq']),)
  
      def str_SOL_MCELL(self, obj):
          return '<{[%s] = %s}>'%(SolObjectPrettyPrinter(obj['key']).to_string(), SolObjectPrettyPrinter(obj['val']).to_string())
  
      def str_SOL_FUNCTION(self, obj):
          return '<Function %s>'%(obj['fname'],)
  
      def str_SOL_CFUNCTION(self, obj):
          return '<CFunction %r>'%(obj['cfunc'],)
  
      def str_SOL_STMT(self, obj):
          return str(obj['node'].cast(gdb.lookup_type('stmt_node').pointer())['type'])
  
      def str_SOL_EXPR(self, obj):
          return str(obj['node'].cast(gdb.lookup_type('expr_node').pointer())['type'])
  
      def children(self):
          with guard:
              stype = str(self.obj['type'])
              if stype in ('SOL_LIST', 'SOL_MAP'):
                  if str(self.obj['seq']['type']) == 'DSL_SEQ_ARRAY':
                      tp = gdb.lookup_type('sol_object_t').pointer()
                      lseq = DslLen.instance.invoke(self.obj['seq'])
                      arr = self.obj['seq']['array']['data'].dereference().cast(tp.array(lseq))
                      if stype == 'SOL_LIST':
                          return  [(str(i), arr[i]) for i in range(lseq)]
                      else:
                          return sum([[(str(i)+'k', arr[i]['key']), (str(i)+'v', arr[i]['val'])] for i in range(lseq)], [])
              if stype == 'SOL_FUNCTION':
                  return [('stmt', self.obj['func'].cast(gdb.lookup_type('stmt_node').pointer))]
              return []
  
      @classmethod
      def check_printable(cls, obj):
          with guard:
              stype = str(obj.type)
              if stype.startswith('sol_object_t') or stype.startswith('struct sol_tag_object_t'):
                  return cls(obj)
              return None
  
  # pp = gdb.printing.RegexpCollectionPrettyPrinter('Sol')
  # pp.add_printer('sol_object_t', '^sol_object_t.*$', SolObjectPrettyPrinter)
  # pp.add_printer('sol_tag_object_t', '^struct sol_tag_object_t.*$', SolObjectPrettyPrinter)
  # gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)
  gdb.pretty_printers.append(SolObjectPrettyPrinter.check_printable)
  
  print('Sol extensions loaded!')
  