Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* Using STL containers with GDB
@ 2008-04-22 12:29 Vincent Benony
  2008-04-22 14:41 ` Daniel Jacobowitz
  2008-04-22 22:13 ` Nick Roberts
  0 siblings, 2 replies; 14+ messages in thread
From: Vincent Benony @ 2008-04-22 12:29 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1275 bytes --]

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


[-- Attachment #2: gdb-6.8-stl.patch --]
[-- Type: text/x-patch, Size: 19720 bytes --]

--- 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;

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL containers with GDB
  2008-04-22 12:29 Using STL containers with GDB Vincent Benony
@ 2008-04-22 14:41 ` Daniel Jacobowitz
  2008-04-22 14:49   ` Vincent Benony
  2008-04-22 22:13 ` Nick Roberts
  1 sibling, 1 reply; 14+ messages in thread
From: Daniel Jacobowitz @ 2008-04-22 14:41 UTC (permalink / raw)
  To: Vincent Benony; +Cc: gdb-patches

On Tue, Apr 22, 2008 at 11:39:59AM +0200, Vincent Benony wrote:
> 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 !

Thanks for doing this.  As for a long term solution, please take a
look at the in-progress Python branch, in Volodya's git repository.
STL support is a big missing feature, but we'd like to add it by
external scripts so that they can be distributed along with the
library, modified without recompiling GDB, and so forth.  I think
Vladimir's got it printing std::vector already.

I really hope we'll have it included in the next release!

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL containers with GDB
  2008-04-22 14:41 ` Daniel Jacobowitz
@ 2008-04-22 14:49   ` Vincent Benony
  2008-04-22 17:51     ` Thiago Jung Bauermann
  0 siblings, 1 reply; 14+ messages in thread
From: Vincent Benony @ 2008-04-22 14:49 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gdb-patches


> Thanks for doing this.  As for a long term solution, please take a
> look at the in-progress Python branch, in Volodya's git repository.
> STL support is a big missing feature, but we'd like to add it by
> external scripts so that they can be distributed along with the
> library, modified without recompiling GDB, and so forth.  I think
> Vladimir's got it printing std::vector already.
> 
> I really hope we'll have it included in the next release!
> 

Thank you for the information, I tought this projet was aborted, but
it's a great news that a python scripting support is planned for GDB !
This will be a cleaner solution to have those features implemented in
external libs.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL containers with GDB
  2008-04-22 14:49   ` Vincent Benony
@ 2008-04-22 17:51     ` Thiago Jung Bauermann
  2008-04-22 18:37       ` Vladimir Prus
  0 siblings, 1 reply; 14+ messages in thread
From: Thiago Jung Bauermann @ 2008-04-22 17:51 UTC (permalink / raw)
  To: Vincent Benony; +Cc: Daniel Jacobowitz, gdb-patches

On Tue, 2008-04-22 at 14:28 +0200, Vincent Benony wrote:
> > Thanks for doing this.  As for a long term solution, please take a
> > look at the in-progress Python branch, in Volodya's git repository.
<snip>
> > I really hope we'll have it included in the next release!
> > 
> 
> Thank you for the information, I tought this projet was aborted, but
> it's a great news that a python scripting support is planned for GDB !
> This will be a cleaner solution to have those features implemented in
> external libs.

FYI, I'm thinking of preparing patches with the code from the git
repository by the weekend, or early next week (Tromey and Volodya, if
you have other plans I'm fine, just let me know, also if you want to do
the patches yourselves I'm fine too :-D ) and post them as RFC to this
list.

We'll know then if you folks think we've been taking the right direction
and if there are use cases we are not covering with the current features
(probably). All is input welcome!

Of course you are all free to peek at the git repository at any time as
well. :-)
-- 
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL containers with GDB
  2008-04-22 17:51     ` Thiago Jung Bauermann
@ 2008-04-22 18:37       ` Vladimir Prus
  0 siblings, 0 replies; 14+ messages in thread
From: Vladimir Prus @ 2008-04-22 18:37 UTC (permalink / raw)
  To: gdb-patches

Thiago Jung Bauermann wrote:

> On Tue, 2008-04-22 at 14:28 +0200, Vincent Benony wrote:
>> > Thanks for doing this.  As for a long term solution, please take a
>> > look at the in-progress Python branch, in Volodya's git repository.
> <snip>
>> > I really hope we'll have it included in the next release!
>> > 
>> 
>> Thank you for the information, I tought this projet was aborted, but
>> it's a great news that a python scripting support is planned for GDB !
>> This will be a cleaner solution to have those features implemented in
>> external libs.
> 
> FYI, I'm thinking of preparing patches with the code from the git
> repository by the weekend, or early next week (Tromey and Volodya, if
> you have other plans I'm fine, just let me know, also if you want to do
> the patches yourselves I'm fine too :-D ) and post them as RFC to this
> list.

I expect to have MI dynamic varobjs done in an hour. I mostly care about MI,
but the visualizer classes I have in mind can be easily wrapper in some
functions callable from cli.

- Volodya



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL containers with GDB
  2008-04-22 12:29 Using STL containers with GDB Vincent Benony
  2008-04-22 14:41 ` Daniel Jacobowitz
@ 2008-04-22 22:13 ` Nick Roberts
  2008-04-22 22:56   ` Daniel Jacobowitz
  1 sibling, 1 reply; 14+ messages in thread
From: Nick Roberts @ 2008-04-22 22:13 UTC (permalink / raw)
  To: Vincent Benony; +Cc: gdb-patches

 > 	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.

The Python branch appears to work for executables compiled with Gcc only.  I'm
curious to know if this approach will work for executables built using other
compilers?

-- 
Nick                                           http://www.inet.net.nz/~nickrob


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL containers with GDB
  2008-04-22 22:13 ` Nick Roberts
@ 2008-04-22 22:56   ` Daniel Jacobowitz
  2008-04-23  6:49     ` Vincent Bénony
  0 siblings, 1 reply; 14+ messages in thread
From: Daniel Jacobowitz @ 2008-04-22 22:56 UTC (permalink / raw)
  To: Nick Roberts; +Cc: Vincent Benony, gdb-patches

On Wed, Apr 23, 2008 at 09:35:09AM +1200, Nick Roberts wrote:
>  > 	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.
> 
> The Python branch appears to work for executables compiled with Gcc only.  I'm
> curious to know if this approach will work for executables built using other
> compilers?

Vincent's implementation has the layout of the GNU STL implementation
hardcoded into it - so even less portable than the Python
implementation, which uses the field names.

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL containers with GDB
  2008-04-22 22:56   ` Daniel Jacobowitz
@ 2008-04-23  6:49     ` Vincent Bénony
  2008-04-23  8:53       ` Eli Zaretskii
  2008-04-23 10:12       ` Nick Roberts
  0 siblings, 2 replies; 14+ messages in thread
From: Vincent Bénony @ 2008-04-23  6:49 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: Nick Roberts, gdb-patches


Le 22 avr. 08 à 23:51, Daniel Jacobowitz a écrit :
>>
>> The Python branch appears to work for executables compiled with Gcc  
>> only.  I'm
>> curious to know if this approach will work for executables built  
>> using other
>> compilers?
>
> Vincent's implementation has the layout of the GNU STL implementation
> hardcoded into it - so even less portable than the Python
> implementation, which uses the field names.

You are right, this patch is very hardcoded. I assume that fields of  
STL containers are always in the same order. I ask GDB the size of  
"void *", and I compute fields offsets using this information to read  
things I need. If you use another compiler, but with GNU STL headers,  
this patch *should* continue to work...

The reason why I do not use fields name is that I had some problems  
with GDB parser: my first approach was to use GDB scripts, but there  
were many problems, like no recursive dump (an std::list into an  
std::vector for example), and I was unable to cast a pointer into a  
type that was a template, I mean GDB parser was able to parse a  
expression like

  (gdb) p (struct Something*) pointer

but not something like

  (gdb) p (std::list<int> *) pointer

  So, you should see my patch as a quick an ugly way of using GDB to  
debug program that use STL container today, but not a patch to be  
included into GDB for future releases.

  My idea was first to consider having GDB call some kind of external  
script in particular situation, and this seems to be the goal of  
Python scripting system, and that's why I feel very enthusiast about  
this project.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL containers with GDB
  2008-04-23  6:49     ` Vincent Bénony
@ 2008-04-23  8:53       ` Eli Zaretskii
  2008-04-23  9:29         ` BENONY Vincent
  2008-04-23 10:12       ` Nick Roberts
  1 sibling, 1 reply; 14+ messages in thread
From: Eli Zaretskii @ 2008-04-23  8:53 UTC (permalink / raw)
  To: Vincent Bénony; +Cc: drow, nickrob, gdb-patches

> Cc: Nick Roberts <nickrob@snap.net.nz>,  gdb-patches@sourceware.org
> From: =?ISO-8859-1?Q?Vincent_B=E9nony?= <vbenony@nordnet.fr>
> Date: Wed, 23 Apr 2008 07:48:22 +0200
> 
> I mean GDB parser was able to parse a expression like
> 
>   (gdb) p (struct Something*) pointer
> 
> but not something like
> 
>   (gdb) p (std::list<int> *) pointer

Does it work if you quote the problematic parts, like this:

  (gdb) p ('std::list<int>' *) pointer

?


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL containers with GDB
  2008-04-23  8:53       ` Eli Zaretskii
@ 2008-04-23  9:29         ` BENONY Vincent
  0 siblings, 0 replies; 14+ messages in thread
From: BENONY Vincent @ 2008-04-23  9:29 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: drow, nickrob, gdb-patches

Eli Zaretskii a écrit :
>> Cc: Nick Roberts <nickrob@snap.net.nz>,  gdb-patches@sourceware.org
>> From: =?ISO-8859-1?Q?Vincent_B=E9nony?= <vbenony@nordnet.fr>
>> Date: Wed, 23 Apr 2008 07:48:22 +0200
>>
>> I mean GDB parser was able to parse a expression like
>>
>>   (gdb) p (struct Something*) pointer
>>
>> but not something like
>>
>>   (gdb) p (std::list<int> *) pointer
> 
> Does it work if you quote the problematic parts, like this:
> 
>   (gdb) p ('std::list<int>' *) pointer
> 
> ?
> 

I saw a trick like this somewhere, but sadly it doesn't work for me.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL containers with GDB
  2008-04-23  6:49     ` Vincent Bénony
  2008-04-23  8:53       ` Eli Zaretskii
@ 2008-04-23 10:12       ` Nick Roberts
  2008-04-23 12:22         ` Daniel Jacobowitz
  1 sibling, 1 reply; 14+ messages in thread
From: Nick Roberts @ 2008-04-23 10:12 UTC (permalink / raw)
  To: Vincent Bénony; +Cc: Daniel Jacobowitz, gdb-patches

 > >> The Python branch appears to work for executables compiled with Gcc  
 > >> only.  I'm
 > >> curious to know if this approach will work for executables built  
 > >> using other
 > >> compilers?
 > >
 > > Vincent's implementation has the layout of the GNU STL implementation
 > > hardcoded into it - so even less portable than the Python
 > > implementation, which uses the field names.
 > 
 > You are right, this patch is very hardcoded. I assume that fields of  
 > STL containers are always in the same order. I ask GDB the size of  
 > "void *", and I compute fields offsets using this information to read  
 > things I need. If you use another compiler, but with GNU STL headers,  
 > this patch *should* continue to work...

Thar's what I wonder: would your approach, implemented as a Python script,
give the best of both worlds?

-- 
Nick                                           http://www.inet.net.nz/~nickrob


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL containers with GDB
  2008-04-23 10:12       ` Nick Roberts
@ 2008-04-23 12:22         ` Daniel Jacobowitz
  0 siblings, 0 replies; 14+ messages in thread
From: Daniel Jacobowitz @ 2008-04-23 12:22 UTC (permalink / raw)
  To: Nick Roberts; +Cc: Vincent Bénony, gdb-patches

On Wed, Apr 23, 2008 at 08:54:58PM +1200, Nick Roberts wrote:
>  > You are right, this patch is very hardcoded. I assume that fields of  
>  > STL containers are always in the same order. I ask GDB the size of  
>  > "void *", and I compute fields offsets using this information to read  
>  > things I need. If you use another compiler, but with GNU STL headers,  
>  > this patch *should* continue to work...
> 
> Thar's what I wonder: would your approach, implemented as a Python script,
> give the best of both worlds?

If you're talking about another compiler, in what way is this better
than doing it by field name?

If you're using the GNU STL, you'll get the same field names and class
layout regardless of the compiler.  If you're not, then both the field
names and class layout will be different.

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Using STL Containers With GDB
  2009-05-27 20:27 Using STL Containers With GDB Ken Lauterbach
@ 2009-05-27 21:24 ` Paul Pluzhnikov
  0 siblings, 0 replies; 14+ messages in thread
From: Paul Pluzhnikov @ 2009-05-27 21:24 UTC (permalink / raw)
  To: Ken Lauterbach; +Cc: gdb-patches

On Wed, May 27, 2009 at 1:27 PM, Ken Lauterbach <lauterb@panix.com> wrote:

> Recently I took the changes that Vincent Benony submitted last year and then
> modified them to get them to work with RH 3.2.3 GCC.

FYI,

Merging of GDB with embedded Python and associated STL
pretty-printers into mainline GDB is in final stages.
You might get significantly better mileage from that.

The latest sources are in git://sourceware.org/git/archer.git
Also http://sourceware.org/gdb/wiki/ProjectArcher

Cheers,
-- 
Paul Pluzhnikov


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Using STL Containers With GDB
@ 2009-05-27 20:27 Ken Lauterbach
  2009-05-27 21:24 ` Paul Pluzhnikov
  0 siblings, 1 reply; 14+ messages in thread
From: Ken Lauterbach @ 2009-05-27 20:27 UTC (permalink / raw)
  To: gdb-patches; +Cc: Ken Lauterbach

Hi,
Recently I took the changes that Vincent Benony submitted last year and 
then modified them to get them to work with RH 3.2.3 GCC. I am aware of 
all the issues that were raised by Vincent and others in the original 
posts, I am just submitting this in case someone else finds it useful.
Below is the new/modified code, including Vincent's changes as well.

Regards,
Ken Lauterbach


#include "block.h"
#include "gdbcore.h"
#include "value.h"
#include "expression.h"

#include "ctype.h" //isdigit()


/* 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);
}
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)
{
     // remove const from type
     // causes seg fault later otherwise

     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);
}

int
inner_name_is_pointer(
char *inner_name
){
     int len = strlen(inner_name);
     if ( len > 0 && inner_name[len-1] == '*' ){
         return 1;
     }

     return 0;
}

#define VTABLE_PREFIX_LEN 4

struct type *
get_real_inner_type2(
char *inner_name2,
struct block        *block,
CORE_ADDR addr
)
{
     struct type      *inner_type2 = 0;
     struct type      *real_inner_type2 = 0;
     struct main_type *main_type = 0;
     char             *real_name2 = 0;

     inner_type2 = cp_get_type (inner_name2, block);
     main_type = inner_type2->main_type;
     if ( main_type->nfields > 0 && 0 == strncmp(main_type->fields[0].name,"_vptr.",6) ){
             struct minimal_symbol *msymbol;
             gdb_byte            *b2 = 0;
             CORE_ADDR addr2 = 0;
             char * fullname = 0;
             char * shortname = 0;

             read_memory(addr, (gdb_byte *) &addr2, sizeof addr2);
             msymbol  = lookup_minimal_symbol_by_pc(addr2);
             if ( msymbol ){
                 fullname = DEPRECATED_SYMBOL_NAME(msymbol);
                 shortname = fullname + VTABLE_PREFIX_LEN; //this should be _ZTV
                 for ( ; *shortname && isdigit(*shortname) ; shortname++ ){} // get rid of digits, like 9 or 13

                 //fprintf(stderr,"found _vptr %s %s %s\n", main_type->fields[0].name,fullname,shortname);

                 inner_type2 = cp_get_type(shortname, block);
             }
      }


     return inner_type2;
}


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;
   char                *inner_name2;
   CORE_ADDR           pc;
   CORE_ADDR           node;
   CORE_ADDR           next_node;
   CORE_ADDR           head_node;
   CORE_ADDR           data_ptr;
   CORE_ADDR           data_ptr2;
  struct frame_info   *current_frame;
   struct type         *inner_type;
   struct type         *inner_type2 = 0;
   struct type         *void_type;
   struct block        *block;
   int                 ptr_size;
   unsigned int        idx;
   gdb_byte            *b;
   gdb_byte            *b2 = 0;

   inner_name  = (char *)malloc(strlen(type->main_type->name) + 1);
   inner_name2 = (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
     {
       if ( inner_name_is_pointer(inner_name)) {

           strcpy(inner_name2,inner_name);
           inner_name2[strlen(inner_name2)-1] = 0;

           //fprintf_filtered (stream, "inner type is pointer\n");
       }
       idx       = 0;
       head_node = (CORE_ADDR)read_memory_integer (address, ptr_size);
       node      = (CORE_ADDR)read_memory_integer (head_node, 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);
         }
         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 ( inner_name_is_pointer(inner_name) ){
             //data_ptr2 = unpack_pointer( inner_type2, b);
             memcpy(&data_ptr2, b, sizeof(CORE_ADDR));

             inner_type2 =  get_real_inner_type2(inner_name2,block,data_ptr2);

             b2 = (gdb_byte *)malloc(TYPE_LENGTH(inner_type2));

             read_memory(data_ptr2, b2, TYPE_LENGTH(inner_type2));
             fprintf_filtered(stream," <%s> = ",inner_type2->main_type->name);
             c_val_print(inner_type2, b2, 0, data_ptr2, stream, format, 0, recurse + 1, pretty);
             free(b2);
             b2 = 0;
         }
         node = (CORE_ADDR)read_memory_integer (node, ptr_size);
         if (node != head_node) fprintf_filtered(stream, ", ");
         if (pretty)
         {
           fprintf_filtered(stream, "\n");
         }
       } while (node != head_node);
       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))

static const int  gRbTreeHeadOffset = 0;
static const int  gRbTreeNodeOffset = 2;
static const int  gRbTreeCountOffset = 1;
static const int  gRbTreeDataPointerOffset = 4;

//static int  gValueOffset = 0;


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           head;
   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));

       head    = (CORE_ADDR)read_memory_integer (address + gRbTreeHeadOffset * ptr_size, ptr_size);
       node    = (CORE_ADDR)read_memory_integer (head +  gRbTreeNodeOffset * ptr_size, ptr_size);
       count   = (int)read_memory_integer(address + gRbTreeCountOffset * ptr_size, ptr_size);

       for (idx=0; idx<count; idx++)
       {
         if (idx >= stllimit)
         {
             fprintf_filtered (stream, "...");
             break;
         }
         data_ptr = (CORE_ADDR)(node + ptr_size * gRbTreeDataPointerOffset);
         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(tmp_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           head;
   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;
   int                 key_len;
   int                 val_len;

   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
     {
       key_len = TYPE_LENGTH(inner_type_key);
       val_len = TYPE_LENGTH(inner_type_value);

       b_key   = (gdb_byte *)malloc(key_len);
       b_value = (gdb_byte *)malloc(val_len);
       head    = (CORE_ADDR)read_memory_integer (address + gRbTreeHeadOffset * ptr_size, ptr_size);
       node    = (CORE_ADDR)read_memory_integer (head +  gRbTreeNodeOffset * ptr_size, ptr_size);
       count   = (int)read_memory_integer(address + gRbTreeCountOffset * ptr_size, ptr_size);
       for (idx=0; idx<count; idx++)
       {
         if (idx >= stllimit)
         {
             fprintf_filtered (stream, "...");
             break;
         }
         data_ptr = (CORE_ADDR)(node + ptr_size * gRbTreeDataPointerOffset);
         read_memory(data_ptr,             b_key, key_len);
         read_memory(data_ptr + key_len, b_value, val_len);

         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 + key_len,  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(tmp_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);
}



   CHECK_TYPEDEF (type);
   if ( stlprint && type->main_type->name )
   {
       // comment out certain stl types for now
       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) ||
           !strncmp(type->main_type->name, "std::string", 11) )
       {
           cp_print_stl_string(type, address, stream, format, recurse, pretty);
           return;
       }
   }

   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;





^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2009-05-27 21:24 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-04-22 12:29 Using STL containers with GDB Vincent Benony
2008-04-22 14:41 ` Daniel Jacobowitz
2008-04-22 14:49   ` Vincent Benony
2008-04-22 17:51     ` Thiago Jung Bauermann
2008-04-22 18:37       ` Vladimir Prus
2008-04-22 22:13 ` Nick Roberts
2008-04-22 22:56   ` Daniel Jacobowitz
2008-04-23  6:49     ` Vincent Bénony
2008-04-23  8:53       ` Eli Zaretskii
2008-04-23  9:29         ` BENONY Vincent
2008-04-23 10:12       ` Nick Roberts
2008-04-23 12:22         ` Daniel Jacobowitz
2009-05-27 20:27 Using STL Containers With GDB Ken Lauterbach
2009-05-27 21:24 ` Paul Pluzhnikov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox