Added GDB pretty printers for SWIG types.

This has been extracted from the javascript branch.
diff --git a/Tools/swigprinters.gdb b/Tools/swigprinters.gdb
new file mode 100644
index 0000000..661aa3e
--- /dev/null
+++ b/Tools/swigprinters.gdb
@@ -0,0 +1,24 @@
+python
+import sys
+import os
+
+try:
+  global SWIG_PRINTER_DIR
+  sys.path.insert(0, SWIG_PRINTER_DIR)
+except NameError:
+  raise RuntimeError("""
+---------------------------------------------------------
+Change ~/.gdbinit to be able to use swig pretty printers:
+> set python SWIG_PRINTER_DIR = <path/to/swig>/Tools
+> source <path/to/swig>/Tools/swigprinters.gdb
+---------------------------------------------------------
+""")
+
+from swigprinters import register_swig_printers, enableGdbPrintWorkaround, \
+  setChildrenRecursionLevel
+
+#enableGdbPrintWorkaround()
+#setChildrenRecursionLevel(2)
+register_swig_printers (None)
+
+end
diff --git a/Tools/swigprinters.py b/Tools/swigprinters.py
new file mode 100755
index 0000000..7415659
--- /dev/null
+++ b/Tools/swigprinters.py
@@ -0,0 +1,574 @@
+import gdb
+import gdb.types
+import itertools
+import re
+
+log_file = None
+GDB_FLATTENED_CHILDREN_WORKAROUND = False
+CHILDREN_MAX_RECURSION_LEVEL = 0
+
+# workaround: don't cast the following DOHs to it's actual type
+# to avoid infinite pretty-print loops
+cast_black_list = {
+  'Hash': set(['parentNode', 'symtab', 'csymtab', 'sym:symtab', 'inherit', 'nextSibling', 'previousSibling'])
+}
+
+def print_(msg):
+    global log_file;
+    
+    if True:
+      if log_file == None:
+        log_file = open('swig_gdb.log', 'w')
+      log_file.write(msg)
+
+    print(msg)
+  
+class SwigStringPrinter:
+  """
+    Pretty print Swig String* types.
+  """
+
+  def __init__ (self, typename, val):
+    self.typename = typename
+    self.val = val
+    
+    try:
+      self.t_swigstr_ptr = gdb.lookup_type("struct String").pointer()
+      self.t_doh_base_ptr = gdb.lookup_type("DohBase").pointer()
+    except Exception as err:
+      print_("SwigStringPrinter: Could not retrieve gdb types.\n  %s.\n"%(str(err)))
+
+  def display_hint(self):
+    return 'string'
+
+  def to_string(self):
+    ret = "<invalid>"
+
+    # Conversion taken from Swig Internals manual:
+    # http://peregrine.hpc.uwm.edu/Head-node-docs/swig/2.0.4/Devel/internals.html#7
+    # (*(struct String *)(((DohBase *)s)->data)).str
+    
+    dohbase = None;
+    str_data = None;
+    char_ptr = None;
+    
+    try:
+      dohbase = self.val.reinterpret_cast(self.t_doh_base_ptr).dereference()
+    except Exception as err:
+      print_("SwigStringPrinter: Could not dereference DOHBase*\n");
+      return "<invalid>";
+      
+    try:
+      str_data = dohbase['data'].reinterpret_cast(self.t_swigstr_ptr).dereference()
+    except Exception as err:
+      print_("SwigStringPrinter: Could not dereference struct String*\n");
+      return "<invalid>";
+      
+    try:
+      char_ptr = str_data['str']
+    except Exception as err:
+      print_("SwigStringPrinter: Could not access field (struct String).str\n");
+      return "<invalid>";
+      
+    if char_ptr.is_lazy is True:
+      char_ptr.fetch_lazy ()
+    
+    try:
+      ret = char_ptr.string()
+    except Exception as err:
+      print_("SwigStringPrinter: Could not convert const char* to string\n");
+      return "<invalid>";
+        
+    return ret
+
+class SwigIterator:
+  
+  def __init__(self):
+    
+    self.t_doh_base_ptr = gdb.lookup_type("DohBase").pointer()
+    self.t_string_ptr = gdb.lookup_type("String").pointer()
+    self.t_node_ptr = gdb.lookup_type("Node").pointer()
+    self.t_hash_ptr = gdb.lookup_type("Hash").pointer()
+    self.t_file_ptr = gdb.lookup_type("File").pointer()
+    self.t_void_ptr = gdb.lookup_type("void").pointer()
+
+  def cast_doh(self, doh, name = None):
+                
+    if doh == 0:
+      return doh
+      
+    doh = doh.reinterpret_cast(self.t_doh_base_ptr);
+    
+    val_base = doh.dereference()
+    val_type = val_base['type'].dereference()
+    val_typestr = val_type['objname'].string()
+    
+    if not name == None and val_typestr in cast_black_list:
+      blacklist = cast_black_list[val_typestr]
+      if name in blacklist:
+        return doh
+    
+    if "String" == val_typestr:
+      doh = doh.reinterpret_cast(self.t_string_ptr)
+    elif "File" == val_typestr:
+      doh = doh.reinterpret_cast(self.t_file_ptr)
+    # BUG: GDB Pyhton can not handle cyclic references yet
+    #      so these casts are deactivated
+    elif "Hash" == val_typestr:
+      doh = doh.reinterpret_cast(self.t_hash_ptr)
+    elif "Node" == val_typestr:
+      doh = doh.reinterpret_cast(self.t_node_ptr)
+
+    return doh
+
+class SwigListIterator(SwigIterator):
+
+  def __init__(self, val):
+    SwigIterator.__init__(self);
+
+    try:
+      self.valid = False
+
+      self.val = val.reinterpret_cast(self.t_doh_base_ptr)
+      val_base = self.val.dereference()
+      val_type = val_base['type'].dereference()
+      val_typestr = val_type['objname'].string()
+      #print_("SwigListIterator: constructing iterator for value of type %s"%val_typestr)
+
+      self.t_struct_list_ptr = gdb.lookup_type("struct List").pointer()
+
+      doh_base = self.val.dereference()
+      self.l = doh_base['data'].reinterpret_cast(self.t_struct_list_ptr).dereference()
+
+      self.address = 0
+      self._index = 0
+      self.key = 0
+      self.item = 0
+
+      self.address = self.val.dereference().address
+
+      self.is_first = True
+      self.valid = True
+
+    except Exception as err:
+      print_("SwigListIterator: Construction failed.\n %s.\n"%(str(err)))
+
+  def __iter__(self):
+    return self
+
+  def List_first(self):
+    
+    self.object = None;
+    self._index = 0
+    self.key = 0
+    self.nitems = int(self.l['nitems'])
+    self.items = self.l['items']
+    
+    if self.nitems > 0:
+        self.item = self.items[0]
+    else:
+      self.stop()
+  
+  def List_next(self):
+    self._index = self._index + 1
+    if self._index >= self.nitems:
+      self.stop()
+    else:
+      self.item = self.items[self._index]
+      
+  def next(self):
+
+    if not self.valid:
+      self.stop()
+      
+    if self.is_first:
+      self.is_first = False
+      try:
+        self.List_first()
+      except StopIteration:
+        raise StopIteration
+      except Exception as err:
+        print_("Error during iteration to first node: \n %s \n" %(str(err)))
+        self.stop()
+    else:
+      try:
+        self.List_next()
+      except StopIteration:
+        raise StopIteration
+      except Exception as err:
+        print_("Error during iteration to first node: \n %s \n" %(str(err)))
+        self.stop()
+      
+    key_str = "[%d]"%self._index
+    item = 0
+
+    try:
+      item = self.cast_doh(self.item)
+    except Exception as err:
+      print_("SwigListIterator(%s): Exception during casting of value doh:\n %s\n" % (str(self.address), str(err)) )
+      self.stop()
+
+    return (key_str, item)
+
+  def stop(self):
+    self.is_first = True
+    self.item = 0
+    self.key = 0
+    raise StopIteration      
+
+class SwigHashIterator(SwigIterator):
+
+  def __init__(self, val):
+    SwigIterator.__init__(self);
+
+    try:
+      self.valid = False
+            
+      self.val = val.reinterpret_cast(self.t_doh_base_ptr)
+
+      self.t_struct_hash_ptr = gdb.lookup_type("struct Hash").pointer()
+      self.t_struct_hash_node_ptr = gdb.lookup_type("struct HashNode").pointer()
+
+      doh_base = self.val.dereference()
+      hash_ = doh_base['data'].reinterpret_cast(self.t_struct_hash_ptr).dereference()
+      self.hashtable = hash_['hashtable']
+      self.hashsize = int(hash_['hashsize'])
+      self.nitems = int(hash_['nitems'])      
+
+      self.next_ = 0
+      self.address = 0
+      self.pos = 0;
+      self._current = 0
+      self.item = 0
+      self.key = 0
+      self._index = 0
+      
+      self.address = self.val.dereference().address
+
+      self.is_first = True
+      self.valid = True
+
+    except Exception as err:
+      print_("SwigHashIterator: Construction failed.\n %s.\n"%(str(err)))
+  
+  def __iter__(self):
+    return self
+      
+  def Hash_firstiter(self):
+    self._current = 0;
+    self.item = 0;
+    self.key = 0;
+    self._index = 0;    
+
+    while (self._index < self.hashsize) and (self.hashtable[self._index] == 0):
+      self._index = self._index+1;
+
+    if self._index >= self.hashsize:
+      self.stop();
+
+    self._current = self.hashtable[self._index]
+    self._current = self._current.reinterpret_cast(self.t_struct_hash_node_ptr);
+    self.item = self._current['object'];
+    self.key = self._current['key'];
+
+    self._current = self._current['next'];
+  
+  
+  def Hash_nextiter(self):
+    if self._current == 0:
+      self._index = self._index + 1
+      while (self._index < self.hashsize) and (self.hashtable[self._index] == 0):
+        self._index = self._index + 1
+
+      if self._index >= self.hashsize:
+        self.item = 0;
+        self.key = 0;
+        self._current = 0;
+        self.stop()
+
+      self._current = self.hashtable[self._index];
+
+    self._current = self._current.reinterpret_cast(self.t_struct_hash_node_ptr);
+    self.key = self._current['key'];
+    self.item = self._current['object'];
+
+    self._current = self._current['next'];
+    
+
+  def next(self):
+
+    if not self.valid:
+      self.stop()
+      
+    if self.is_first:
+      self.is_first = False
+      try:
+        self.Hash_firstiter()
+      except StopIteration:
+        raise StopIteration
+      except Exception as err:
+        print_("Error during iteration to first node: \n %s \n" %(str(err)))
+        self.stop()
+    else:
+      try:
+        self.Hash_nextiter()
+      except StopIteration:
+        raise StopIteration
+      except Exception as err:
+        print_("Error during iteration to first node: \n %s \n" %(str(err)))
+        self.stop()
+      
+    key_str = "<err>"
+    item = 0
+    try:
+      string_printer = SwigStringPrinter("String *", self.key)
+      key_str = string_printer.to_string()
+    except Exception as err:
+      print_("SwigHashIterator(%s): Exception during extracting key string:\n %s\n" % (str(self.address), str(err)) )
+      self.stop()
+
+    try:
+      item = self.cast_doh(self.item, key_str)
+      
+    except Exception as err:
+      print_("SwigHashIterator(%s): Exception during casting of value doh:\n %s\n" % (str(self.address), str(err)) )
+      self.stop()
+
+    return (key_str, item)
+  
+  def stop(self):
+    self.is_first = True
+    raise StopIteration      
+
+class AlternateKeyValueIterator():
+
+  def __init__(self, iterable):
+    self.it = iterable.__iter__()
+    self._next = None
+    self.count = -1
+
+  def __iter__(self):
+    return self
+
+  def next(self):
+    if self._next == None:
+      key, value = self.it.next()
+      self._next = value
+      self.count = self.count + 1
+      return ("[%d]"%self.count, key)
+    else:
+      value = self._next
+      self._next = None
+      return ("[%d]"%self.count, value)
+
+class NopIterator:
+  
+  def __init__(self):
+    pass
+  
+  def __iter__(self):
+    return self
+    
+  def next(self):
+    raise StopIteration
+
+class SwigListPrinter:
+  """
+    Pretty print Swig List* types (also ParmList*).
+  """
+    
+  def __init__ (self, typename, val):
+    
+    self.typename = typename
+    self.val = val
+    
+    it = SwigListIterator(val)
+    self.valid = it.valid
+    self.address = it.address
+      
+     
+  def display_hint(self):
+    return 'array'
+
+  def to_string(self):
+    return "%s(%s)" % (str(self.typename), str(self.address))
+        
+  def children(self):
+        
+    if not self.valid:
+      print_("SwigListPrinter: Invalid state.\n")
+      return NopIterator()
+    
+    try:
+      it = SwigListIterator(self.val)
+      return it
+    except Exception as err:
+      print_("SwigListPrinter: Error during creation of children iterator. \n %s \n" %(str(err)))
+      raise err
+
+class SwigHashPrinter:
+  """
+    Pretty print Swig Hash* types (also Node*).
+  """
+    
+  def __init__ (self, typename, val):
+    
+    self.typename = typename
+    self.val = val
+    it = SwigHashIterator(val)
+    self.valid = it.valid
+    self.address = it.address
+    self.level = 0;
+         
+  def display_hint(self):
+    return 'map'
+
+  def to_string(self):
+    return "%s(%s)" % (str(self.typename), str(self.address))
+        
+  def children(self):
+    global GDB_FLATTENED_CHILDREN_WORKAROUND
+    global CHILDREN_MAX_RECURSION_LEVEL
+    
+    if not self.valid:
+      print_("SwigHashPrinter: Invalid state.\n")
+      return NopIterator()
+      
+    if self.level > CHILDREN_MAX_RECURSION_LEVEL:
+      return NopIterator()
+    
+    try:
+      it = SwigHashIterator(self.val)
+      if GDB_FLATTENED_CHILDREN_WORKAROUND:
+        return AlternateKeyValueIterator(it)
+      return it
+    except Exception as err:
+      print_("SwigHashPrinter: Error during creation of children iterator. \n %s \n" %(str(err)))
+      raise err
+      
+class SwigSimplePrinter:
+  def __init__ (self, typename, val):
+    self.typename = typename
+    self.val = val
+    
+  def display_hint(self):
+    return "string"
+
+  def to_string(self):
+    return "%s(%s)"%(self.typename, str(self.val.address))
+  
+class SwigDelegatingPrinter:
+
+  def __init__ (self, typename, val):
+      t_doh_base_ptr = gdb.lookup_type("DohBase").pointer()
+      val_base = val.reinterpret_cast(t_doh_base_ptr).dereference()
+      val_type = val_base['type'].dereference()
+      val_typestr = val_type['objname'].string()
+      self.has_children = False
+      
+      if val_typestr == "Hash":
+        self.delegate = SwigHashPrinter(typename, val)
+        self.has_children = True
+      elif val_typestr == "List":
+        self.delegate = SwigListPrinter(typename, val)
+        self.has_children = True
+      elif val_typestr == "String":
+        self.delegate = SwigStringPrinter(typename, val)
+      else:
+        self.delegate = SwigSimplePrinter(typename, val)
+
+  def display_hint(self):
+    return self.delegate.display_hint()
+
+  def to_string(self):
+    return self.delegate.to_string()
+
+  def children(self):
+    if not self.has_children:
+      return NopIterator()
+      
+    return self.delegate.children()
+
+class RxPrinter(object):
+    def __init__(self, name, function):
+        super(RxPrinter, self).__init__()
+        self.name = name
+        self.function = function
+        self.enabled = True
+
+    def invoke(self, value):
+        if not self.enabled:
+            return None
+        return self.function(self.name, value)
+
+# A pretty-printer that conforms to the "PrettyPrinter" protocol from
+# gdb.printing.  It can also be used directly as an old-style printer.
+class Printer(object):
+    def __init__(self, name):
+        super(Printer, self).__init__()
+        self.name = name
+        self.subprinters = []
+        self.lookup = {}
+        self.enabled = True
+        self.compiled_rx = re.compile('^([a-zA-Z0-9_: *]+)$')
+
+    def add(self, name, function):        
+        if not self.compiled_rx.match(name):
+            raise ValueError, 'error: "%s" does not match' % name
+        
+        printer = RxPrinter(name, function)
+        self.subprinters.append(printer)
+        self.lookup[name] = printer
+        print('Added pretty printer for %s. ' % (name))
+
+    def __call__(self, val):
+        typename = str(val.type)
+        if typename in self.lookup:
+            ret = self.lookup[typename].invoke(val)
+            return ret
+
+        # Cannot find a pretty printer.  Return None.
+        return None
+
+swig_printer = None
+
+def register_swig_printers(obj):
+    global swig_printer
+
+    if obj is None:
+      obj = gdb
+
+    obj.pretty_printers.append(swig_printer)
+
+def build_swig_printer():
+    global swig_printer
+
+    swig_printer = Printer("swig")
+    swig_printer.add('String *', SwigStringPrinter)
+    swig_printer.add('const String *', SwigStringPrinter)
+    swig_printer.add('SwigType *', SwigStringPrinter)
+    swig_printer.add('Hash *', SwigHashPrinter)
+    swig_printer.add('const Hash *', SwigHashPrinter)
+    swig_printer.add('Node *', SwigHashPrinter)
+    swig_printer.add('const Node *', SwigHashPrinter)
+    swig_printer.add('Parm *', SwigHashPrinter)
+    swig_printer.add('const Parm *', SwigHashPrinter)
+    swig_printer.add('List *', SwigListPrinter)
+    swig_printer.add('const List *', SwigListPrinter)
+    swig_printer.add('ParmList *', SwigDelegatingPrinter)
+    swig_printer.add('const ParmList *', SwigDelegatingPrinter)
+    swig_printer.add('File *', SwigDelegatingPrinter)
+    #swig_printer.add('DOH *', SwigDelegatingPrinter)
+    #swig_printer.add('const DOH *', SwigDelegatingPrinter)
+    
+    print_("Loaded swig printers\n");
+
+def enableGdbPrintWorkaround():
+  global GDB_FLATTENED_CHILDREN_WORKAROUND
+  GDB_FLATTENED_CHILDREN_WORKAROUND = True
+
+def setChildrenRecursionLevel(level):
+  global CHILDREN_MAX_RECURSION_LEVEL
+  CHILDREN_MAX_RECURSION_LEVEL = level
+
+build_swig_printer()