Using STL Containers With GDB

Ken Lauterbach lauterb@panix.com
Wed May 27 20:27:00 GMT 2009


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;






More information about the Gdb-patches mailing list