Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* 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
* 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

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 --
2009-05-27 20:27 Using STL Containers With GDB Ken Lauterbach
2009-05-27 21:24 ` Paul Pluzhnikov
  -- strict thread matches above, loose matches on Subject: below --
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

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