This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Using STL Containers With GDB
- From: Ken Lauterbach <lauterb at panix dot com>
- To: gdb-patches at sourceware dot org
- Cc: Ken Lauterbach <lauterb at panix dot com>
- Date: Wed, 27 May 2009 16:27:38 -0400 (EDT)
- Subject: Using STL Containers With GDB
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;