title: examining memory in gdb pretty-printer
body: <p>I'm trying to figure out how GDB pretty printing works in order to create some pretty printers that will display data structures in a more compact, readable form, but the documentation seems pretty thin.  As a starting exercise, I tried to create a pretty printer for a sockaddr_in -- instead of printing umpteen different union variations in an unreadable form, just print it in normal dotted notation.</p>
  
  <p>I put the following in my <code>.gdbinit</code> file:</p>
  
  <pre><code>python
  class sockaddr_in_Printer(object):
      "Print a sockaddr_in"
      def __init__(self, val):
          self.val = val
      def to_string(self):
          addr = self.val['sin_addr'].address().cast(gdb.lookup_type("unsigned char *"))
          port = self.val['sin_port'].address().cast(gdb.lookup_type("unsigned char *"))
          rv = "" + addr.dereference()
          for x in range(0,3):
              addr += 1
              rv += "."
              rv += addr.dereference()
          pnum = port.dereference() * 256
          port += 1
          pnum += port.dereference()
          rv += ":"
          rv += pnum
          return rv;
  def find_pp(val):
      if val.type.tag == 'sockaddr_in':
          return sockaddr_in_Printer(val)
      return None
  gdb.pretty_printers.append(find_pp)
  end
  </code></pre>
  
  <p>This seems to load ok, but when I try to print a sockaddr_in, I get an opaque error message:</p>
  
  <pre><code>(gdb) p srcaddr
  Python Exception &lt;type 'exceptions.RuntimeError'&gt; Value is not callable (not TYPE_CODE_FUNC).: 
  $2 = 
  (gdb)
  </code></pre>
  
  <p>Any ideas as to what is going wrong?</p>
  
  <p>Anyone have any good pointers to documentation about writing/using/debugging gdb pretty printing functions?  Much of the above is cribbed from examples found around the web, as that appears to be the only 'documentation' available.</p>
  
  <p><strong>edit</strong></p>
  
  <p>changing the addr/port stuff to</p>
  
  <pre><code> addr = self.val['sin_addr'].address.cast(gdb.lookup_type("unsigned char").pointer())
   port = self.val['sin_port'].address.cast(gdb.lookup_type("unsigned char").pointer())
  </code></pre>
  
  <p>fixes that exception, but leads to</p>
  
  <pre><code>(gdb) p src
  Python Exception &lt;class 'gdb.error'&gt; Argument to arithmetic operation not a number or boolean.: 
  $1 = 
  </code></pre>
  
  <p>..still no line number info to indicate where the problem is.</p>
  
  <p><strong>edit</strong></p>
  
  <p>after lots of random twiddling of the code, I figured out that I need:</p>
  
  <pre><code>python
  class sockaddr_in_Printer(object):
      "Print a sockaddr_in"
      def __init__(self, val):
          self.val = val
      def to_string(self):
          ptr_type = gdb.lookup_type("unsigned char").pointer()
          addr = self.val['sin_addr'].address.cast(ptr_type)
          port = self.val['sin_port'].address.cast(ptr_type)
          rv = str(int(addr.dereference()))
          for x in range(0,3):
              addr += 1
              rv += "."
              rv += str(int(addr.dereference()))
          pnum = port.dereference() * 256
          port += 1
          pnum += port.dereference()
          rv += ":"
          rv += str(pnum)
          return rv;
  def find_pp(val):
      if val.type.tag == 'sockaddr_in':
          return sockaddr_in_Printer(val)
      return None
  gdb.pretty_printers.append(find_pp)
  end
  </code></pre>