Browse Source

gdb: Add a directory of files with gdb macros

* gdb/: Directory to contain files with GDB macros. Organised by topic into
  separate files.
* gdb/lib.txt: General OS API and Quagga lib macros:
  (def_ntohs) convert big-endian short to host order.
  (def_ntohl) convert big-endian long to host order.
  (walk_route_table_next) Walk to next route_node in a table, according
  to given top and current node arguments.
  (walk_route_table) walk the given route table dumping non-null info pointers,
  from the given root node.
  (dump_timeval) timeval to human readable output
  (dump_s_addr) Print IP address of given pointer to a (struct in_addr).s_addr
  (dump_s6_addr) Ditto for IPv6.
  (dump_prefix4) Dump a Quagga (struct prefix_ipv4 *)
  (dump_prefix6) Dump (struct prefix_ipv6 *)
  (dump_prefix) Dump a (struct prefix *).
  (rn_next_{down,up}) left-down and up-and-right walks of a route_table
  from a given route_node.
* gdb/ospfd.txt: ospfd specific gdb macros, depends on gdb/lib.txt
  (dump_ospf_lsa_flags) LSA flags to text.
  (dump_ospf_lsa_data) dump the data of a (struct lsa_header *) argument.
  (dump_ospf_lsa) Dump the details of a (struct ospf_lsa *)
  (walk_ospf_lsdb) Go through an LSDB, rooted at the
  given (struct route_node *), and dump LSA details.
  (ospf_backbone_lsdb_top) Get the LSDB top pointer for the given LSA type.
Paul Jakma 5 years ago
parent
commit
5bcbc3f588
2 changed files with 432 additions and 0 deletions
  1. 295 0
      gdb/lib.txt
  2. 137 0
      gdb/ospf.txt

+ 295 - 0
gdb/lib.txt

@@ -0,0 +1,295 @@
+# GDB macros for use with Quagga.
+#
+# Macros in this file are not daemon specific. E.g., OS or Quagga library
+# APIs.
+#
+# The macro file can be loaded with 'source <filename>'. They can then be
+# called by the user. Macros that explore more complicated structs generally
+# take pointer arguments.
+#
+# E.g.:
+# 
+# (gdb) source ~paul/code/quagga/gdb/lib.txt
+# (gdb) break bgp_packet.c:613
+# Breakpoint 3 at 0x7fa883033a32: file bgp_packet.c, line 613.
+# (gdb) cont
+# ...
+# (gdb) cont
+# Breakpoint 3, bgp_write_packet (peer=0x7fa885199080) at bgp_packet.c:614
+# 614                     if (CHECK_FLAG (adv->binfo->peer->cap,PEER_CAP_RESTART_RCV)
+# (gdb) dump_prefix4  &adv->rn->p
+# IPv4:10.1.1.0/24
+# (gdb) dump_prefix  &adv->rn->p
+# IPv4:10.1.1.0/24
+#
+
+
+define def_ntohs
+ set $data = (char *)$arg0
+ set $i = 0
+ 
+ set $_  = $data[$i++] << 8
+ set $_ += $data[$i++]
+end
+document def_ntohs
+Read a 2-byte short at the given pointed to area as big-endian and 
+return it in $_
+
+Argument: Pointer to a 2-byte, big-endian short word.
+Returns: Integer value of that word in $_
+end
+
+define def_ntohl
+ set $data = (char *)$arg0
+ set $i = 0
+ 
+ set $_  = $data[$i++] << 24
+ set $_ += $data[$i++] << 16
+ set $_ += $data[$i++] << 8
+ set $_ += $data[$i++]
+end
+document def_ntohl
+Read a 4-byte integer at the given pointed to area as big-endian and 
+return it in $_
+
+Argument: Pointer to a big-endian 4-byte word.
+Returns: Integer value of that word in $_
+end
+
+# NB: This is in more complicated iterative form, rather than more
+# conventional and simpler recursive form, because GDB has a recursion limit
+# on macro calls (I think).
+define walk_route_table_next
+  # callee saves
+  set $_top = $top
+  set $_node = $node
+  set $_prevl = $prevl
+  
+  set $top = (struct route_node *)$arg0
+  set $node = (struct route_node *)$arg1
+  set $prevl = $node
+  
+  # first try left
+  #echo try left\n
+  set $node = $prevl->link[0]
+  
+  # otherwise try right
+  if ($node == 0)
+    #echo left null, try right\n
+    set $node = $prevl->link[1]
+  end
+  
+  # otherwise go up, till we find the first right that
+  # we havn't been to yet
+  if ($node == 0)
+    set $node = $prevl
+    while ($node != $top)
+       #echo right null, try up and right\n
+       
+       set $prevl = $node
+       set $parent = $node->parent
+       set $node = $parent->link[1]
+       
+       if ($node != 0 && $node != $prevl)
+         #echo found node \n
+         loop_break
+       end
+       
+       #echo go up\n
+       set $node = $parent       
+    end
+  end
+  
+  #printf "next node: 0x%x\n", $node
+  
+  set $_ = $node
+  
+  set $top = $_top
+  set $node = $_node
+  set $prevl = $_prevl
+end
+document walk_route_table_next
+Return the next node to visit in the given route_table (or subset of) and
+the given current node.
+
+Arguments:
+1st: (struct route_node *) to the top of the route_table to walk
+2nd: (struct route_node *) to the current node
+
+Returns: The (struct route_node *) for the next to visit in $_
+end
+
+define walk_route_table
+  set $_visited = $visited
+  set $_node = $node
+  set $top = $_top
+  
+  set $node = (struct route_node *)$arg0
+  set $top = (struct route_node *)$arg0
+  set $visited = 0
+  
+  while ($node != 0)
+    printf "Node: 0x%x", $node
+
+    if ($node->info != 0)
+      printf "\tinfo: 0x%x", $node->info
+      set $visited = $visited + 1
+    end
+    
+    printf "\n"
+    
+    walk_route_table_next $top $node
+    set $node = $_
+    
+    # we've gotten back to the top, finish
+    if ($node == $top)
+      set $node = 0
+    end
+  end
+  printf "Visited: %u\n", $visited
+  
+  set $top = $_top
+  set $visited = $_visited
+  set $node = $_node
+end
+
+document walk_route_table
+Walk through a routing table (or subset thereof) and dump all the non-null
+(struct route_node *)->info pointers.
+
+Argument: A lib/thread.h::(struct route_node *) pointing to the route_node
+under which all data should be dumped
+end
+
+define dump_timeval 
+  set $tv = (struct timeval *)$arg0
+  set $day = 3600*24
+  
+  if $tv->tv_sec > $day
+    printf "%d days, ", $tv->tv_sec / $day
+  end
+  if $tv->tv_sec > 3600
+    printf "%dh", $tv->tv_sec / 3600
+  end
+  if ($tv->tv_sec % 3600) > 60
+    printf "%dm", ($tv->tv_sec % 3600) / 60
+  end
+  printf "%d", $tv->tv_sec % 3600 % 60
+  if $tv->tv_usec != 0
+    printf ".%06d", $tv->tv_usec
+  end
+  printf "s"
+end
+document dump_timeval
+Human readable dump of a (struct timeval *) argument
+end
+
+define dump_s_addr
+  set $addr = (char *)$arg0
+  
+  printf "%d.%d.%d.%d", $addr[0], $addr[1], $addr[2], $addr[3]
+end
+
+define dump_s6_addr
+  set $a6 = (char *)$arg0
+  set $field = 0
+  
+  while ($field < 16)
+    set $i1 = $field++
+    set $i2 = $field++
+    
+    printf "%x%x", $a6[$i1], $a6[$i2]
+    
+    if ($field > 2 && ($field % 4 == 0))
+      printf ":"
+    end
+  end
+end
+document dump_s6_addr
+Interpret the memory starting at given address as an IPv6 s6_addr and
+print in human readable form.
+end
+
+define dump_prefix4
+  set $p = (struct prefix *) $arg0
+  echo IPv4:
+  dump_s_addr &($p->u.prefix4)
+  printf "/%d\n", $p->prefixlen
+end
+document dump_prefix4
+Textual dump of a (struct prefix4 *) argument.
+end
+
+define dump_prefix6
+  set $p = (struct prefix *) $arg0
+  echo IPv6:
+  dump_s6_addr &($p->u.prefix6)
+  printf "/%d\n", $p->prefixlen
+end
+document dump_prefix6
+Textual dump of a (struct prefix6 *) argument.
+end
+
+define dump_prefix
+  set $p = $arg0
+  
+  if ($p->family == 2)
+    dump_prefix4 $p
+  end
+  if ($p->family == 10)
+    dump_prefix6 $p
+  end
+end
+document dump_prefix
+Human readable dump of a (struct prefix *) argument.
+end
+
+define rn_next_down
+  set $node = $arg0
+  while ($node != 0)
+    print/x $node
+    if ($node->link[0] != 0)
+      set $node = $node->link[0]
+    else
+      set $node = $node->link[1]
+    end
+  end
+end
+
+document rn_next_down
+Walk left-down a given route table, dumping locations of route_nodes
+
+Argument: A single (struct route_node *).
+end
+
+define rn_next_up
+  set $top = (struct route_node *)$arg0
+  set $node = (struct route_node *)$arg1
+  
+  while ($node != $top)
+    echo walk up\n
+    
+    set $prevl = $node
+    set $parent = $node->parent
+    set $node = $parent->link[1]
+    
+    if ($node != 0 && $node != $prevl)
+      echo found a node\n
+      loop_break
+    end
+    
+    echo going up\n
+    set $node = $parent
+  end
+  output/x $node
+  echo \n
+end
+
+document rn_next_up
+Walk up-and-right from the given route_node to the next valid route_node
+which is not the given "top" route_node
+
+Arguments:
+1st: A (struct route_node *) to the top of the route table.
+2nd: The (struct route_node *) to walk up from
+end

+ 137 - 0
gdb/ospf.txt

@@ -0,0 +1,137 @@
+# GDB macros for use with Quagga.
+#
+# Macros in this file are specific to ospfd/. Definitions here depend on the
+# lib.txt macros file, which must also be loaed.
+#
+# The macro file can be loaded with 'source <filename>'. They can then be   
+# called by the user. Macros that explore more complicated structs generally
+# take pointer arguments. 
+
+define dump_ospf_lsa_flags
+  set $flags = $arg0
+  
+  printf "%u: ", $flags
+  
+  if $flags & 0x1
+    echo Self,
+  end
+  if $flags & 0x2
+    echo Self-checked,
+  end
+  if $flags & 0x4
+    echo Recvd,
+  end
+  if $flags & 0x8
+    echo Apprvd,
+  end
+  if $flags & 0x10
+    echo Discard,
+  end
+  if $flags & 0x20
+    echo Local-Xlt,
+  end
+  if $flags & 0x40
+    echo Premature-Aged,
+  end
+  if $flags & 0x40
+    echo In-Maxage,
+  end
+  echo \n
+end
+
+define dump_ospf_lsa_data
+  set $lsad = (struct lsa_header *)$arg0
+  
+  echo ID / AdvRtr:  \t\t
+  dump_s_addr &$lsad->id.s_addr
+  echo \ : \ 
+  dump_s_addr &$lsad->adv_router.s_addr
+  echo \n
+  
+  def_ntohs &$lsad->ls_age
+  printf "Type: %2u Age: %4u,", $lsad->type, $_
+  
+  def_ntohs &$lsad->length
+  printf " length: %2u", $_
+  
+  def_ntohl &$lsad->ls_seqnum
+  printf " Seqnum: 0x%08x", $_
+  
+  def_ntohs &$lsad->checksum
+  printf " csum: 0x%04x\n", $_
+  
+  # return the age
+  def_ntohs &$lsad->ls_age
+end
+
+define dump_ospf_lsa
+  set $lsa = (struct ospf_lsa *)$arg0
+  
+  #print/x *$lsa
+  
+  dump_ospf_lsa_data $lsa->data
+  
+  set $relage = $_ + (relative_time.tv_sec - $lsa->tv_recv.tv_sec)
+  printf "Relative age: %4u\n", $relage
+  
+  dump_ospf_lsa_flags $lsa->flags
+  
+  echo tv_recv: \ 
+  dump_timeval &$lsa->tv_recv
+  echo \ tv_orig: \ 
+  dump_timeval &$lsa->tv_orig
+  echo \n
+  
+  printf "lock %2u", $lsa->lock
+  printf " stat %2d", $lsa->stat
+  printf " rtx count: %u", $lsa->retransmit_counter
+  printf " rfsh list: %d", $lsa->refresh_list
+  printf "\n\n"
+end
+
+define walk_ospf_lsdb
+  set $node = (struct route_node *)$arg0
+  set $top = (struct route_node *)$arg0
+  set $visited = 0
+  
+  while ($node != 0)
+    set $prevl = $node
+    
+    if ($node->info != 0)
+      dump_ospf_lsa $node->info
+      set $visited = $visited + 1
+    end
+    
+    walk_route_table_next $top $node
+    set $node = $_
+    
+    # we've gotten back to the top, finish
+    if ($node == $top)
+      set $node = 0
+    end
+  end
+  printf "Visited: %u\n", $visited
+end
+
+document walk_ospf_lsdb
+Walk through an OSPF LSDB (or subset thereof) and dump all the LSAs
+contained there-in.
+
+Argument: A (struct route_node *) pointing to the top of the
+LSDB route-table which should be dumped.
+end
+
+define ospf_backbone_lsdb_top
+  set $type = $arg0
+  
+  set $ospf = ospf_master->ospf->head->data
+  
+  output/x ((struct ospf *)$ospf)->backbone->lsdb->type[$type]->db->top
+  echo \n
+end
+document ospf_backbone_lsdb_top
+Dump location of the LSDB in the backbone area for the given LSA type
+
+Argument: Integer LSA type
+end
+