This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Using STL containers with GDB


Hi,

	I use gdb at work for some time now. We currently develop a
multiplatform software which heavily use STL templates. As a result,
it's always difficult to me to debug such code.

	I tried to find a way to debug more efficiently by using gdb scripts
that were able to dump std::vector or std::list, but it was always
painful.

	So, yesterday, I decided myself to look at the code of GDB. After a
quick look, I wrote this patch. I know that it's not very clean, and
that it makes many assumptions about STL containers, and that it cannot
be considered as a long term feature for GDB, but, believe me, it's very
very usefull !

	Now, I can look at the content of list, vector, set, map, multiset,
multimap and string simply with the classic "print" command of GDB.

	Two switchs and a parameter are introduced :

 * set print stl on / set print stl off
default is off. Controls the type of dumping (classic or "easy")

 * set print stl_array_compatible on / set print stl_array_compatible
off
default is on. Controls the kind of formating of STL container when stl
print is on.

 * set print stllimit N
 set the maximum number of items we could dump when printing an STL
container to N. 0 means unlimited

	I hope it could be useful for someone.

Sincerely
Vincent Benony

--- gdb-6.8/gdb/cp-valprint.c	2008-01-01 23:53:09.000000000 +0100
+++ gdb-6.8-patched/gdb/cp-valprint.c	2008-04-22 11:37:25.000000000 +0200
@@ -36,6 +36,10 @@
 #include "valprint.h"
 #include "cp-support.h"
 #include "language.h"
+#include "block.h"
+#include "gdbcore.h"
+#include "value.h"
+#include "expression.h"
 
 /* Controls printing of vtbl's */
 int vtblprint;
@@ -70,6 +74,36 @@
 		    value);
 }
 
+/* Controls printing of STL containers */
+int stlprint;
+static void
+show_stlprint (struct ui_file *file, int from_tty,
+               struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("\
+Printing of STL containers is %s.\n"),
+		    value);
+}
+
+int stlprintcompatible;
+static void
+show_stlprintcompatible (struct ui_file *file, int from_tty,
+               struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("\
+Compatible printing of STL containers  is %s.\n"),
+		    value);
+}
+
+int stllimit;
+static void
+show_stllimit (struct ui_file *file, int from_tty,
+               struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("\
+Maximum elements of STL containers is set to %s.\n"), (stllimit == 0 || stllimit == (unsigned int)-1) ? "unlimited" : value);
+}
+
 
 static struct obstack dont_print_vb_obstack;
 static struct obstack dont_print_statmem_obstack;
@@ -148,6 +182,494 @@
    DONT_PRINT is an array of baseclass types that we
    should not print, or zero if called from top level.  */
 
+int
+get_stl_inner_type (struct type *type, char *inner_type_name)
+{
+  int level = 1;
+  char *pname = type->main_type->name;
+
+  while (*pname && *pname != '<') pname++;
+  if (*pname == 0)
+  {
+    // This is not a template !
+    *inner_type_name = 0;
+    return 0;
+  }
+
+  pname++;
+
+  while (!(level == 1 && *pname == ','))
+  {
+    if (*pname == '<') level++;
+    else if (*pname == '>') level--;
+    if (!(level == 1 && *pname == ',')) *inner_type_name++ = *pname++;
+  }
+  *inner_type_name = 0;
+
+  return 1;
+}
+
+int
+get_stl_inner_type_pair (struct type *type, char *inner_type_key, char *inner_type_value)
+{
+  int level = 1;
+  char *pname = type->main_type->name;
+
+  while (*pname && *pname != '<') pname++;
+  if (*pname == 0)
+  {
+    // This is not a template !
+    *inner_type_key   = 0;
+    *inner_type_value = 0;
+    return 0;
+  }
+
+  pname++;
+
+  while (!(level == 1 && *pname == ','))
+  {
+    if (*pname == '<') level++;
+    else if (*pname == '>') level--;
+    if (!(level == 1 && *pname == ',')) *inner_type_key++ = *pname++;
+  }
+  *inner_type_key = 0;
+
+  if (*pname == ',')
+  {
+    pname++;
+    while (!(level == 1 && *pname == ','))
+    {
+      if (*pname == '<') level++;
+      else if (*pname == '>') level--;
+      if (!(level == 1 && *pname == ',')) *inner_type_value++ = *pname++;
+    }
+    *inner_type_value = 0;
+  }
+
+  return 1;
+}
+
+struct type *
+cp_get_type(char * name, struct block * block)
+{
+    struct type *type;
+    struct type *ptr_type;
+    char *rname = (char *)malloc(strlen(name) + 1);
+    char *old   = rname;
+    int  nbPtrs = 0;
+
+    strcpy(rname, name);
+    if (!strncmp(rname, "const ", 6)) rname += 6;
+    while (rname[strlen(rname) - 1] == '*')
+    {
+      nbPtrs++;
+      rname[strlen(rname) - 1] = 0;
+    }
+
+    while (rname[strlen(rname) - 1] == ' ')
+    {
+      rname[strlen(rname) - 1] = 0;
+    }
+
+    type = lookup_typename(rname, block, 1);
+    while (nbPtrs--)
+    {
+      ptr_type = NULL;
+      make_pointer_type(type, &ptr_type);
+      type = ptr_type;
+    }
+
+    free(old);
+    return type;
+}
+
+void
+cp_print_stl_vector(struct type *type, CORE_ADDR address,
+                    struct ui_file *stream, int format, int recurse,
+                    enum val_prettyprint pretty)
+{
+  char                *inner_name;
+  CORE_ADDR           pc;
+  struct frame_info   *current_frame;
+  struct type         *void_type;
+  struct type         *inner_type;
+  struct block        *block;
+  int                 ptr_size;
+  unsigned int        idx;
+  CORE_ADDR           begin;
+  CORE_ADDR           end;
+  gdb_byte            *b;
+
+  inner_name = (char *)malloc(strlen(type->main_type->name) + 1);
+
+  if (get_stl_inner_type(type, inner_name))
+  {
+    if (!stlprintcompatible) fprintf_filtered (stream, "vector<%s>", inner_name);
+    fprintf_filtered (stream, "{");
+    if (pretty) fprintf_filtered (stream, "\n");
+    current_frame = get_current_frame ();
+    pc            = get_frame_address_in_block (current_frame);
+    block         = block_for_pc (pc);
+    inner_type    = cp_get_type (inner_name, block);
+    void_type     = cp_get_type("void *", block);
+    ptr_size      = TYPE_LENGTH(void_type);
+
+    if (inner_type == NULL)
+    {
+      if (pretty) print_spaces_filtered (2 + 2 * recurse, stream);
+      fprintf_filtered (stream, "  // no information for type %s\n", inner_name);
+    }
+    else
+    {
+      idx   = 0;
+      begin = (CORE_ADDR)read_memory_integer (address,            ptr_size);
+      end   = (CORE_ADDR)read_memory_integer (address + ptr_size, ptr_size);
+      b     = (gdb_byte *)malloc(TYPE_LENGTH(inner_type));
+      while (begin != end)
+      {
+        if (idx >= stllimit)
+        {
+            fprintf_filtered (stream, "...");
+            break;
+        }
+        if (pretty) print_spaces_filtered (2 + 2 * recurse, stream);
+        if (!stlprintcompatible) fprintf_filtered(stream, "[%d] = ", idx++);
+        read_memory(begin, b, TYPE_LENGTH(inner_type));
+        c_val_print(inner_type, b, 0, begin, stream, format, 0, recurse + 1, pretty);
+        begin += TYPE_LENGTH(inner_type);
+        if (begin != end) fprintf_filtered(stream, ", ");
+        if (pretty)
+        {
+          fprintf_filtered(stream, "\n");
+        }
+      }
+      free(b);
+    }
+    if (pretty) print_spaces_filtered (2 * recurse, stream);
+    fprintf_filtered (stream, "}");
+    if (recurse == 0) fprintf_filtered (stream, "\n");
+  }
+
+  free(inner_name);
+}
+
+void
+cp_print_stl_list(struct type *type, CORE_ADDR address,
+                  struct ui_file *stream, int format, int recurse,
+                  enum val_prettyprint pretty)
+{
+  char                *inner_name;
+  CORE_ADDR           pc;
+  CORE_ADDR           node;
+  CORE_ADDR           data_ptr;
+  struct frame_info   *current_frame;
+  struct type         *inner_type;
+  struct type         *void_type;
+  struct block        *block;
+  int                 ptr_size;
+  unsigned int        idx;
+  gdb_byte            *b;
+
+  inner_name = (char *)malloc(strlen(type->main_type->name) + 1);
+
+  if (get_stl_inner_type(type, inner_name))
+  {
+    if (!stlprintcompatible) fprintf_filtered (stream, "list<%s>", inner_name);
+    fprintf_filtered (stream, "{");
+    if (pretty) fprintf_filtered (stream, "\n");
+    current_frame = get_current_frame ();
+    pc            = get_frame_address_in_block (current_frame);
+    block         = block_for_pc (pc);
+    inner_type    = cp_get_type (inner_name, block);
+    void_type     = cp_get_type("void *", block);
+    ptr_size      = TYPE_LENGTH(void_type);
+
+    if (inner_type == NULL)
+    {
+      if (pretty) print_spaces_filtered (2 + 2 * recurse, stream);
+      fprintf_filtered (stream, "  // no information for type %s\n", inner_name);
+    }
+    else
+    {
+      idx  = 0;
+      node = (CORE_ADDR)read_memory_integer (address, ptr_size);
+      b    = (gdb_byte *)malloc(TYPE_LENGTH(inner_type));
+      do
+      {
+        if (idx >= stllimit)
+        {
+            fprintf_filtered (stream, "...");
+            break;
+        }
+        data_ptr = (CORE_ADDR)(node + ptr_size * 2);
+        if (pretty) print_spaces_filtered (2 + 2 * recurse, stream);
+        if (!stlprintcompatible) fprintf_filtered(stream, "[%d] = ", idx++);
+        read_memory(data_ptr, b, TYPE_LENGTH(inner_type));
+        c_val_print(inner_type, b, 0, data_ptr, stream, format, 0, recurse + 1, pretty);
+        node = (CORE_ADDR)read_memory_integer (node, ptr_size);
+        if (node != address) fprintf_filtered(stream, ", ");
+        if (pretty)
+        {
+          fprintf_filtered(stream, "\n");
+        }
+      } while (node != address);
+      free(b);
+    }
+    if (pretty) print_spaces_filtered (2 * recurse, stream);
+    fprintf_filtered (stream, "}");
+    if (recurse == 0) fprintf_filtered (stream, "\n");
+  }
+
+  free(inner_name);
+}
+
+#define TREE_PARENT(A) ((CORE_ADDR)read_memory_integer ((A) + 1 * ptr_size, ptr_size))
+#define TREE_LEFT(A)   ((CORE_ADDR)read_memory_integer ((A) + 2 * ptr_size, ptr_size))
+#define TREE_RIGHT(A)  ((CORE_ADDR)read_memory_integer ((A) + 3 * ptr_size, ptr_size))
+
+void
+cp_print_stl_set(struct type *type, CORE_ADDR address,
+                 struct ui_file *stream, int format, int recurse,
+                 enum val_prettyprint pretty)
+{
+  char                *inner_name;
+  CORE_ADDR           pc;
+  CORE_ADDR           node;
+  CORE_ADDR           left;
+  CORE_ADDR           tmp_node;
+  CORE_ADDR           data_ptr;
+  struct frame_info   *current_frame;
+  struct type         *inner_type;
+  struct type         *void_type;
+  struct block        *block;
+  int                 ptr_size;
+  unsigned int        idx;
+  int                 count;
+  gdb_byte            *b;
+
+  inner_name = (char *)malloc(strlen(type->main_type->name) + 1);
+
+  if (get_stl_inner_type(type, inner_name))
+  {
+    if (!stlprintcompatible) fprintf_filtered (stream, "set<%s>", inner_name);
+    fprintf_filtered (stream, "{");
+    if (pretty) fprintf_filtered (stream, "\n");
+    current_frame = get_current_frame ();
+    pc            = get_frame_address_in_block (current_frame);
+    block         = block_for_pc (pc);
+    inner_type    = cp_get_type (inner_name, block);
+    void_type     = cp_get_type("void *", block);
+    ptr_size      = TYPE_LENGTH(void_type);
+
+    if (inner_type == NULL)
+    {
+      if (pretty) print_spaces_filtered (2 + 2 * recurse, stream);
+      fprintf_filtered (stream, "  // no information for type %s\n", inner_name);
+    }
+    else
+    {
+      b     = (gdb_byte *)malloc(TYPE_LENGTH(inner_type));
+      node  = (CORE_ADDR)read_memory_integer (address + 3 * ptr_size, ptr_size);
+      count = (int)read_memory_integer(address + 5 * ptr_size, ptr_size);
+      for (idx=0; idx<count; idx++)
+      {
+        if (idx >= stllimit)
+        {
+            fprintf_filtered (stream, "...");
+            break;
+        }
+        data_ptr = (CORE_ADDR)(node + ptr_size * 4);
+        if (pretty) print_spaces_filtered (2 + 2 * recurse, stream);
+        if (!stlprintcompatible) fprintf_filtered(stream, "[%d] = ", idx);
+        read_memory(data_ptr, b, TYPE_LENGTH(inner_type));
+        c_val_print(inner_type, b, 0, data_ptr, stream, format, 0, recurse + 1, pretty);
+
+        if (TREE_RIGHT(node) != 0)
+        {
+          node = TREE_RIGHT(node);
+          while ((left = TREE_LEFT(node)))
+          {
+            node = left;
+          }
+        }
+        else
+        {
+          tmp_node = TREE_PARENT(node);
+          while (node == TREE_RIGHT(node))
+          {
+            node     = tmp_node;
+            tmp_node = TREE_PARENT(node);
+          }
+          if (TREE_RIGHT(node) != tmp_node)
+          {
+            node = tmp_node;
+          }
+        }
+
+        if (idx != count - 1) fprintf_filtered(stream, ", ");
+        if (pretty)
+        {
+          fprintf_filtered(stream, "\n");
+        }
+      }
+      free(b);
+    }
+    if (pretty) print_spaces_filtered (2 * recurse, stream);
+    fprintf_filtered (stream, "}");
+    if (recurse == 0) fprintf_filtered (stream, "\n");
+  }
+
+  free(inner_name);
+}
+
+void
+cp_print_stl_map(struct type *type, CORE_ADDR address,
+                 struct ui_file *stream, int format, int recurse,
+                 enum val_prettyprint pretty)
+{
+  char                *inner_key;
+  char                *inner_value;
+  CORE_ADDR           pc;
+  CORE_ADDR           node;
+  CORE_ADDR           left;
+  CORE_ADDR           tmp_node;
+  CORE_ADDR           data_ptr;
+  struct frame_info   *current_frame;
+  struct type         *inner_type_key;
+  struct type         *inner_type_value;
+  struct type         *void_type;
+  struct block        *block;
+  int                 ptr_size;
+  unsigned int        idx;
+  int                 count;
+  gdb_byte            *b_key;
+  gdb_byte            *b_value;
+
+  inner_key   = (char *)malloc(strlen(type->main_type->name) + 1);
+  inner_value = (char *)malloc(strlen(type->main_type->name) + 1);
+
+  if (get_stl_inner_type_pair(type, inner_key, inner_value))
+  {
+    if (!stlprintcompatible) fprintf_filtered (stream, "map<%s, %s>", inner_key, inner_value);
+    fprintf_filtered (stream, "{");
+    if (pretty) fprintf_filtered (stream, "\n");
+    current_frame    = get_current_frame ();
+    pc               = get_frame_address_in_block (current_frame);
+    block            = block_for_pc (pc);
+    inner_type_key   = cp_get_type (inner_key,   block);
+    inner_type_value = cp_get_type (inner_value, block);
+    void_type        = cp_get_type("void *", block);
+    ptr_size         = TYPE_LENGTH(void_type);
+
+    if (inner_type_key == NULL || inner_type_value == NULL)
+    {
+      if (pretty) print_spaces_filtered (2 + 2 * recurse, stream);
+      fprintf_filtered (stream, "  // no information for type std::pair<%s, %s>\n", inner_key, inner_value);
+    }
+    else
+    {
+      b_key   = (gdb_byte *)malloc(TYPE_LENGTH(inner_type_key));
+      b_value = (gdb_byte *)malloc(TYPE_LENGTH(inner_type_value));
+      node    = (CORE_ADDR)read_memory_integer (address + 3 * ptr_size, ptr_size);
+      count   = (int)read_memory_integer(address + 5 * ptr_size, ptr_size);
+      for (idx=0; idx<count; idx++)
+      {
+        if (idx >= stllimit)
+        {
+            fprintf_filtered (stream, "...");
+            break;
+        }
+        data_ptr = (CORE_ADDR)(node + ptr_size * 4);
+        read_memory(data_ptr,            b_key,   TYPE_LENGTH(inner_type_key));
+        read_memory(data_ptr + ptr_size, b_value, TYPE_LENGTH(inner_type_value));
+
+        if (pretty) print_spaces_filtered (2 + 2 * recurse, stream);
+        if (!stlprintcompatible) fprintf_filtered(stream, "[%d] = ", idx);
+        fprintf_filtered (stream, "{");
+        if (pretty) fprintf_filtered(stream, "\n");
+
+        if (pretty) print_spaces_filtered (4 + 2 * recurse, stream);
+        if (!stlprintcompatible)
+        {
+          fprintf_filtered(stream, "key ");
+          if (pretty) fprintf_filtered(stream, "  ");
+          fprintf_filtered(stream, "= ");
+        }
+        c_val_print(inner_type_key,   b_key,   0, data_ptr, stream, format, 0, recurse + 3, pretty);
+        if (pretty) fprintf_filtered(stream, ",\n"); else fprintf_filtered(stream, ", ");
+        if (pretty) print_spaces_filtered (4 + 2 * recurse, stream);
+        if (!stlprintcompatible)
+        {
+          fprintf_filtered(stream, "value = ");
+        }
+        c_val_print(inner_type_value, b_value, 0, data_ptr, stream, format, 0, recurse + 3, pretty);
+        if (pretty) fprintf_filtered(stream, "\n");
+
+        if (pretty) print_spaces_filtered (4 + 2 * recurse, stream);
+        fprintf_filtered(stream, "}");
+
+        if (TREE_RIGHT(node) != 0)
+        {
+          node = TREE_RIGHT(node);
+          while ((left = TREE_LEFT(node)))
+          {
+            node = left;
+          }
+        }
+        else
+        {
+          tmp_node = TREE_PARENT(node);
+          while (node == TREE_RIGHT(node))
+          {
+            node     = tmp_node;
+            tmp_node = TREE_PARENT(node);
+          }
+          if (TREE_RIGHT(node) != tmp_node)
+          {
+            node = tmp_node;
+          }
+        }
+
+        if (idx != count - 1) fprintf_filtered(stream, ", ");
+        if (pretty)
+        {
+          fprintf_filtered(stream, "\n");
+        }
+      }
+      free(b_key);
+      free(b_value);
+    }
+    if (pretty) print_spaces_filtered (2 * recurse, stream);
+    fprintf_filtered (stream, "}");
+    if (recurse == 0) fprintf_filtered (stream, "\n");
+  }
+
+  free(inner_key);
+  free(inner_value);
+}
+
+void
+cp_print_stl_string(struct type *type, CORE_ADDR address,
+                    struct ui_file *stream, int format, int recurse,
+                    enum val_prettyprint pretty)
+{
+  struct type         *char_type;
+  struct frame_info   *current_frame;
+  struct block        *block;
+  int                 ptr_size;
+  int                 pc;
+  CORE_ADDR           string_ptr;
+
+  current_frame    = get_current_frame ();
+  pc               = get_frame_address_in_block (current_frame);
+  block            = block_for_pc (pc);
+  char_type        = cp_get_type("char *", block);
+  ptr_size         = TYPE_LENGTH(char_type);
+
+  string_ptr = read_memory_integer (address, ptr_size);
+  val_print_string (string_ptr, -1, 1, stream);
+}
+
 void
 cp_print_value_fields (struct type *type, struct type *real_type,
 		       const gdb_byte *valaddr, int offset, CORE_ADDR address,
@@ -161,6 +683,35 @@
 
   CHECK_TYPEDEF (type);
 
+  if (stlprint)
+  {
+    if (!strncmp(type->main_type->name, "std::vector<", 12))
+    {
+      cp_print_stl_vector(type, address, stream, format, recurse, pretty);
+      return;
+    }
+    if (!strncmp(type->main_type->name, "std::list<", 10))
+    {
+      cp_print_stl_list(type, address, stream, format, recurse, pretty);
+      return;
+    }
+    if (!strncmp(type->main_type->name, "std::set<", 9) || !strncmp(type->main_type->name, "std::multiset<", 14))
+    {
+      cp_print_stl_set(type, address, stream, format, recurse, pretty);
+      return;
+    }
+    if (!strncmp(type->main_type->name, "std::map<", 9) || !strncmp(type->main_type->name, "std::multimap<", 14))
+    {
+      cp_print_stl_map(type, address, stream, format, recurse, pretty);
+      return;
+    }
+    if (!strncmp(type->main_type->name, "std::basic_string<char,", 23))
+    {
+      cp_print_stl_string(type, address, stream, format, recurse, pretty);
+      return;
+    }
+  }
+
   fprintf_filtered (stream, "{");
   len = TYPE_NFIELDS (type);
   n_baseclasses = TYPE_N_BASECLASSES (type);
@@ -608,6 +1159,32 @@
 			   show_objectprint,
 			   &setprintlist, &showprintlist);
 
+  add_setshow_boolean_cmd ("stl", class_support, &stlprint, _("\
+Set printing of STL containers."), _("\
+Show printing of STL containers."), NULL,
+			   NULL,
+			   show_stlprint,
+			   &setprintlist, &showprintlist);
+  stlprint = 0;
+
+  add_setshow_boolean_cmd ("stl_array_compatible", class_support, &stlprintcompatible, _("\
+Set compatibility with classic arrays while printing STL containers."), _("\
+Show compatibility of STL containers printing."), NULL,
+			   NULL,
+			   show_stlprintcompatible,
+			   &setprintlist, &showprintlist);
+  stlprintcompatible = 1;
+
+  add_setshow_uinteger_cmd ("stllimit", class_support,
+                            &stllimit,
+                            _("Set the maximum number of elements to display in STL containers."),
+                            _("Show the maximum number of elements to display in STL containers."),
+                            _("Show the maximum number of elements to display in STL containers. Zero is unlimited."),
+                            NULL,
+                            show_stllimit,
+                            &setprintlist, &showprintlist);
+  stllimit = 50;
+
   /* Give people the defaults which they are used to.  */
   objectprint = 0;
   vtblprint = 0;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]