Fix crashes on dangling display expressions.
	* ada-lang.c (ada_operator_check): New function.
	(ada_exp_descriptor): Fill-in the field operator_check.
	* c-lang.c (exp_descriptor_c): Fill-in the field operator_check.
	* jv-lang.c (exp_descriptor_java): Likewise.
	* m2-lang.c (exp_descriptor_modula2): Likewise.
	* scm-lang.c (exp_descriptor_scm): Likewise.
	* parse.c (exp_descriptor_standard): Likewise.
	(operator_check_standard): New function.
	(exp_iterate, exp_uses_objfile_iter, exp_uses_objfile): New functions.
	* parser-defs.h (struct exp_descriptor): New field operator_check.
	(operator_check_standard, exp_uses_objfile): New declarations.
	* printcmd.c: Remove the inclusion of solib.h.
	(display_uses_solib_p): Remove the function.
	(clear_dangling_display_expressions): Call lookup_objfile_from_block
	and exp_uses_objfile instead of display_uses_solib_p.
	* solist.h (struct so_list) <objfile>: New comment.
	* symtab.c (lookup_objfile_from_block): Remove the static qualifier.
	* symtab.h (lookup_objfile_from_block): New declaration.
	(struct general_symbol_info) <obj_section>: Extend the comment.

gdb/testsuite/
	Fix crashes on dangling display expressions.
	* gdb.base/solib-display.exp: Call gdb_gnu_strip_debug if LIBSEPDEBUG
	is SEP.
	(lib_flags): Remove the "debug" keyword.
	(libsepdebug): New variable for iterating new loop.
	(save_pf_prefix): New variable wrapping the loop.
	(sep_lib_flags): New variable derived from LIB_FLAGS.  Use it.
	* lib/gdb.exp (gdb_gnu_strip_debug): Document the return code.
This commit is contained in:
Jan Kratochvil 2010-04-22 23:15:43 +00:00
parent 793b0ff8d7
commit c0201579c8
15 changed files with 355 additions and 114 deletions

View file

@ -1,3 +1,26 @@
2010-04-22 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix crashes on dangling display expressions.
* ada-lang.c (ada_operator_check): New function.
(ada_exp_descriptor): Fill-in the field operator_check.
* c-lang.c (exp_descriptor_c): Fill-in the field operator_check.
* jv-lang.c (exp_descriptor_java): Likewise.
* m2-lang.c (exp_descriptor_modula2): Likewise.
* scm-lang.c (exp_descriptor_scm): Likewise.
* parse.c (exp_descriptor_standard): Likewise.
(operator_check_standard): New function.
(exp_iterate, exp_uses_objfile_iter, exp_uses_objfile): New functions.
* parser-defs.h (struct exp_descriptor): New field operator_check.
(operator_check_standard, exp_uses_objfile): New declarations.
* printcmd.c: Remove the inclusion of solib.h.
(display_uses_solib_p): Remove the function.
(clear_dangling_display_expressions): Call lookup_objfile_from_block
and exp_uses_objfile instead of display_uses_solib_p.
* solist.h (struct so_list) <objfile>: New comment.
* symtab.c (lookup_objfile_from_block): Remove the static qualifier.
* symtab.h (lookup_objfile_from_block): New declaration.
(struct general_symbol_info) <obj_section>: Extend the comment.
2010-04-22 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>

View file

@ -10887,6 +10887,36 @@ ada_operator_length (struct expression *exp, int pc, int *oplenp, int *argsp)
}
}
/* Implementation of the exp_descriptor method operator_check. */
static int
ada_operator_check (struct expression *exp, int pos,
int (*objfile_func) (struct objfile *objfile, void *data),
void *data)
{
const union exp_element *const elts = exp->elts;
struct type *type = NULL;
switch (elts[pos].opcode)
{
case UNOP_IN_RANGE:
case UNOP_QUAL:
type = elts[pos + 1].type;
break;
default:
return operator_check_standard (exp, pos, objfile_func, data);
}
/* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL. */
if (type && TYPE_OBJFILE (type)
&& (*objfile_func) (TYPE_OBJFILE (type), data))
return 1;
return 0;
}
static char *
ada_op_name (enum exp_opcode opcode)
{
@ -11275,6 +11305,7 @@ parse (void)
static const struct exp_descriptor ada_exp_descriptor = {
ada_print_subexp,
ada_operator_length,
ada_operator_check,
ada_op_name,
ada_dump_subexp_body,
ada_evaluate_subexp

View file

@ -1139,6 +1139,7 @@ static const struct exp_descriptor exp_descriptor_c =
{
print_subexp_standard,
operator_length_standard,
operator_check_standard,
op_name_standard,
dump_subexp_body_standard,
evaluate_subexp_c

View file

@ -1162,6 +1162,7 @@ const struct exp_descriptor exp_descriptor_java =
{
print_subexp_standard,
operator_length_standard,
operator_check_standard,
op_name_standard,
dump_subexp_body_standard,
evaluate_subexp_java

View file

@ -356,6 +356,7 @@ const struct exp_descriptor exp_descriptor_modula2 =
{
print_subexp_standard,
operator_length_standard,
operator_check_standard,
op_name_standard,
dump_subexp_body_standard,
evaluate_subexp_modula2

View file

@ -62,6 +62,7 @@ const struct exp_descriptor exp_descriptor_standard =
{
print_subexp_standard,
operator_length_standard,
operator_check_standard,
op_name_standard,
dump_subexp_body_standard,
evaluate_subexp_standard
@ -1373,6 +1374,150 @@ parser_fprintf (FILE *x, const char *y, ...)
va_end (args);
}
/* Implementation of the exp_descriptor method operator_check. */
int
operator_check_standard (struct expression *exp, int pos,
int (*objfile_func) (struct objfile *objfile,
void *data),
void *data)
{
const union exp_element *const elts = exp->elts;
struct type *type = NULL;
struct objfile *objfile = NULL;
/* Extended operators should have been already handled by exp_descriptor
iterate method of its specific language. */
gdb_assert (elts[pos].opcode < OP_EXTENDED0);
/* Track the callers of write_exp_elt_type for this table. */
switch (elts[pos].opcode)
{
case BINOP_VAL:
case OP_COMPLEX:
case OP_DECFLOAT:
case OP_DOUBLE:
case OP_LONG:
case OP_SCOPE:
case OP_TYPE:
case UNOP_CAST:
case UNOP_DYNAMIC_CAST:
case UNOP_REINTERPRET_CAST:
case UNOP_MAX:
case UNOP_MEMVAL:
case UNOP_MIN:
type = elts[pos + 1].type;
break;
case TYPE_INSTANCE:
{
LONGEST arg, nargs = elts[pos + 1].longconst;
for (arg = 0; arg < nargs; arg++)
{
struct type *type = elts[pos + 2 + arg].type;
struct objfile *objfile = TYPE_OBJFILE (type);
if (objfile && (*objfile_func) (objfile, data))
return 1;
}
}
break;
case UNOP_MEMVAL_TLS:
objfile = elts[pos + 1].objfile;
type = elts[pos + 2].type;
break;
case OP_VAR_VALUE:
{
const struct block *const block = elts[pos + 1].block;
const struct symbol *const symbol = elts[pos + 2].symbol;
/* Check objfile where the variable itself is placed.
SYMBOL_OBJ_SECTION (symbol) may be NULL. */
if ((*objfile_func) (SYMBOL_SYMTAB (symbol)->objfile, data))
return 1;
/* Check objfile where is placed the code touching the variable. */
objfile = lookup_objfile_from_block (block);
type = SYMBOL_TYPE (symbol);
}
break;
}
/* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL. */
if (type && TYPE_OBJFILE (type)
&& (*objfile_func) (TYPE_OBJFILE (type), data))
return 1;
if (objfile && (*objfile_func) (objfile, data))
return 1;
return 0;
}
/* Call OBJFILE_FUNC for any TYPE and OBJFILE found being referenced by EXP.
The functions are never called with NULL OBJFILE. Functions get passed an
arbitrary caller supplied DATA pointer. If any of the functions returns
non-zero value then (any other) non-zero value is immediately returned to
the caller. Otherwise zero is returned after iterating through whole EXP.
*/
static int
exp_iterate (struct expression *exp,
int (*objfile_func) (struct objfile *objfile, void *data),
void *data)
{
int endpos;
const union exp_element *const elts = exp->elts;
for (endpos = exp->nelts; endpos > 0; )
{
int pos, args, oplen = 0;
exp->language_defn->la_exp_desc->operator_length (exp, endpos,
&oplen, &args);
gdb_assert (oplen > 0);
pos = endpos - oplen;
if (exp->language_defn->la_exp_desc->operator_check (exp, pos,
objfile_func, data))
return 1;
endpos = pos;
}
return 0;
}
/* Helper for exp_uses_objfile. */
static int
exp_uses_objfile_iter (struct objfile *exp_objfile, void *objfile_voidp)
{
struct objfile *objfile = objfile_voidp;
if (exp_objfile->separate_debug_objfile_backlink)
exp_objfile = exp_objfile->separate_debug_objfile_backlink;
return exp_objfile == objfile;
}
/* Return 1 if EXP uses OBJFILE (and will become dangling when OBJFILE
is unloaded), otherwise return 0. OBJFILE must not be a separate debug info
file. */
int
exp_uses_objfile (struct expression *exp, struct objfile *objfile)
{
gdb_assert (objfile->separate_debug_objfile_backlink == NULL);
return exp_iterate (exp, exp_uses_objfile_iter, objfile);
}
void
_initialize_parse (void)
{

View file

@ -192,6 +192,11 @@ extern void operator_length (struct expression *, int, int *, int *);
extern void operator_length_standard (struct expression *, int, int *, int *);
extern int operator_check_standard (struct expression *exp, int pos,
int (*objfile_func)
(struct objfile *objfile, void *data),
void *data);
extern char *op_name_standard (enum exp_opcode);
extern struct type *follow_types (struct type *);
@ -270,6 +275,19 @@ struct exp_descriptor
the number of subexpressions it takes. */
void (*operator_length) (struct expression*, int, int*, int *);
/* Call TYPE_FUNC and OBJFILE_FUNC for any TYPE and OBJFILE found being
referenced by the single operator of EXP at position POS. Operator
parameters are located at positive (POS + number) offsets in EXP.
The functions should never be called with NULL TYPE or NULL OBJFILE.
Functions should get passed an arbitrary caller supplied DATA pointer.
If any of the functions returns non-zero value then (any other) non-zero
value should be immediately returned to the caller. Otherwise zero
should be returned. */
int (*operator_check) (struct expression *exp, int pos,
int (*objfile_func) (struct objfile *objfile,
void *data),
void *data);
/* Name of this operator for dumping purposes. */
char *(*op_name) (enum exp_opcode);
@ -302,4 +320,6 @@ extern void print_subexp_standard (struct expression *, int *,
extern void parser_fprintf (FILE *, const char *, ...) ATTR_FORMAT (printf, 2 ,3);
extern int exp_uses_objfile (struct expression *exp, struct objfile *objfile);
#endif /* PARSER_DEFS_H */

View file

@ -46,7 +46,6 @@
#include "exceptions.h"
#include "observer.h"
#include "solist.h"
#include "solib.h"
#include "parser-defs.h"
#include "charset.h"
#include "arch-utils.h"
@ -1891,51 +1890,6 @@ disable_display_command (char *args, int from_tty)
}
}
/* Return 1 if D uses SOLIB (and will become dangling when SOLIB
is unloaded), otherwise return 0. */
static int
display_uses_solib_p (const struct display *d,
const struct so_list *solib)
{
int endpos;
struct expression *const exp = d->exp;
const union exp_element *const elts = exp->elts;
if (d->block != NULL
&& d->pspace == solib->pspace
&& solib_contains_address_p (solib, d->block->startaddr))
return 1;
for (endpos = exp->nelts; endpos > 0; )
{
int i, args, oplen = 0;
exp->language_defn->la_exp_desc->operator_length (exp, endpos,
&oplen, &args);
gdb_assert (oplen > 0);
i = endpos - oplen;
if (elts[i].opcode == OP_VAR_VALUE)
{
const struct block *const block = elts[i + 1].block;
const struct symbol *const symbol = elts[i + 2].symbol;
if (block != NULL
&& solib_contains_address_p (solib,
block->startaddr))
return 1;
/* SYMBOL_OBJ_SECTION (symbol) may be NULL. */
if (SYMBOL_SYMTAB (symbol)->objfile == solib->objfile)
return 1;
}
endpos -= oplen;
}
return 0;
}
/* display_chain items point to blocks and expressions. Some expressions in
turn may point to symbols.
Both symbols and blocks are obstack_alloc'd on objfile_stack, and are
@ -1947,17 +1901,28 @@ display_uses_solib_p (const struct display *d,
static void
clear_dangling_display_expressions (struct so_list *solib)
{
struct objfile *objfile = solib->objfile;
struct display *d;
struct objfile *objfile = NULL;
for (d = display_chain; d; d = d->next)
/* With no symbol file we cannot have a block or expression from it. */
if (objfile == NULL)
return;
if (objfile->separate_debug_objfile_backlink)
objfile = objfile->separate_debug_objfile_backlink;
gdb_assert (objfile->pspace == solib->pspace);
for (d = display_chain; d != NULL; d = d->next)
{
if (d->exp && display_uses_solib_p (d, solib))
{
xfree (d->exp);
d->exp = NULL;
d->block = NULL;
}
if (d->pspace != solib->pspace)
continue;
if (lookup_objfile_from_block (d->block) == objfile
|| (d->exp && exp_uses_objfile (d->exp, objfile)))
{
xfree (d->exp);
d->exp = NULL;
d->block = NULL;
}
}
}

View file

@ -231,6 +231,7 @@ const struct exp_descriptor exp_descriptor_scm =
{
print_subexp_standard,
operator_length_standard,
operator_check_standard,
op_name_standard,
dump_subexp_body_standard,
evaluate_exp

View file

@ -63,7 +63,12 @@ struct so_list
bfd *abfd;
char symbols_loaded; /* flag: symbols read in yet? */
struct objfile *objfile; /* objfile for loaded lib */
/* objfile with symbols for a loaded library. Target memory is read from
ABFD. OBJFILE may be NULL either before symbols have been loaded, if
the file cannot be found or after the command "nosharedlibrary". */
struct objfile *objfile;
struct target_section *sections;
struct target_section *sections_end;

View file

@ -1150,7 +1150,7 @@ lookup_symbol_aux_local (const char *name, const struct block *block,
/* Look up OBJFILE to BLOCK. */
static struct objfile *
struct objfile *
lookup_objfile_from_block (const struct block *block)
{
struct objfile *obj;

View file

@ -148,7 +148,7 @@ struct general_symbol_info
short section;
/* The section associated with this symbol. */
/* The section associated with this symbol. It can be NULL. */
struct obj_section *obj_section;
};
@ -1207,4 +1207,6 @@ int producer_is_realview (const char *producer);
void fixup_section (struct general_symbol_info *ginfo,
CORE_ADDR addr, struct objfile *objfile);
struct objfile *lookup_objfile_from_block (const struct block *block);
#endif /* !defined(SYMTAB_H) */

View file

@ -1,3 +1,14 @@
2010-04-22 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix crashes on dangling display expressions.
* gdb.base/solib-display.exp: Call gdb_gnu_strip_debug if LIBSEPDEBUG
is SEP.
(lib_flags): Remove the "debug" keyword.
(libsepdebug): New variable for iterating new loop.
(save_pf_prefix): New variable wrapping the loop.
(sep_lib_flags): New variable derived from LIB_FLAGS. Use it.
* lib/gdb.exp (gdb_gnu_strip_debug): Document the return code.
2010-04-22 Pierre Muller <muller@ics.u-strasbg.fr>
* gdb.threads/watchthreads.exp: Change to obtain consistent output.

View file

@ -36,7 +36,7 @@ if { [skip_shlib_tests] || [is_remote target] } {
set libname "solib-display-lib"
set srcfile_lib ${srcdir}/${subdir}/${libname}.c
set binfile_lib ${objdir}/${subdir}/${libname}.so
set lib_flags [list debug]
set lib_flags {}
# Binary file.
set testfile "solib-display-main"
set srcfile ${srcdir}/${subdir}/${testfile}.c
@ -48,60 +48,92 @@ if [get_compiler_info ${binfile}] {
return -1
}
if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib} $lib_flags] != ""
|| [gdb_compile ${srcfile} ${binfile} executable $bin_flags] != "" } {
untested "Could not compile $binfile_lib or $binfile."
return -1
set save_pf_prefix $pf_prefix
# SEP must be last for the possible `unsupported' error path.
foreach libsepdebug {NO IN SEP} {
set pf_prefix $save_pf_prefix
lappend pf_prefix "$libsepdebug:"
set sep_lib_flags $lib_flags
if {$libsepdebug != "NO"} {
lappend sep_lib_flags {debug}
}
if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib} $sep_lib_flags] != ""
|| [gdb_compile ${srcfile} ${binfile} executable $bin_flags] != "" } {
untested "Could not compile $binfile_lib or $binfile."
return -1
}
if {$libsepdebug == "SEP"} {
if {[gdb_gnu_strip_debug $binfile_lib] != 0} {
unsupported "Could not split debug of $binfile_lib."
return
} else {
pass "split solib"
}
}
clean_restart $executable
if ![runto_main] then {
fail "Can't run to main"
return 0
}
gdb_test "display a_global" "1: a_global = 41"
gdb_test "display b_global" "2: b_global = 42"
gdb_test "display c_global" "3: c_global = 43"
if { [gdb_start_cmd] < 0 } {
fail "Can't run to main (2)"
continue
}
gdb_test "" "3: c_global = 43\\r\\n2: b_global = 42\\r\\n1: a_global = 41" "after rerun"
# Now rebuild the library without b_global
if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib} \
"$sep_lib_flags additional_flags=-DNO_B_GLOBAL"] != ""} {
fail "Can't rebuild $binfile_lib"
}
if {$libsepdebug == "SEP"} {
set test "split solib second time"
if {[gdb_gnu_strip_debug $binfile_lib] != 0} {
fail $test
continue
} else {
pass $test
}
}
if { [gdb_start_cmd] < 0 } {
fail "Can't run to main (3)"
continue
}
gdb_test "" "3: c_global = 43\\r\\nwarning: .*b_global.*\\r\\n1: a_global = 41" "after rerun (2)"
# Now verify that displays which are not in the shared library
# are not cleared permaturely.
gdb_test "break [gdb_get_line_number "break here" ${testfile}.c]" \
".*Breakpoint.* at .*"
gdb_test "continue"
gdb_test "display main_global" "4: main_global = 44"
gdb_test "display a_local" "5: a_local = 45"
gdb_test "display a_static" "6: a_static = 46"
if { [gdb_start_cmd] < 0 } {
fail "Can't run to main (4)"
continue
}
gdb_test "" "6: a_static = 46\\r\\n4: main_global = 44\\r\\n.*"
gdb_test "break [gdb_get_line_number "break here" ${testfile}.c]" \
".*Breakpoint.* at .*"
gdb_test "continue" "6: a_static = 46\\r\\n5: a_local = 45\\r\\n4: main_global = 44\\r\\n.*"
}
clean_restart ${executable}
if ![runto_main] then {
fail "Can't run to main"
return 0
}
gdb_test "display a_global" "1: a_global = 41"
gdb_test "display b_global" "2: b_global = 42"
gdb_test "display c_global" "3: c_global = 43"
if { [gdb_start_cmd] < 0 } {
fail "Can't run to main (2)"
return 0
}
gdb_test "" "3: c_global = 43\\r\\n2: b_global = 42\\r\\n1: a_global = 41" "after rerun"
# Now rebuild the library without b_global
if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib} \
"$lib_flags additional_flags=-DNO_B_GLOBAL"] != ""} {
fail "Can't rebuild $binfile_lib"
}
if { [gdb_start_cmd] < 0 } {
fail "Can't run to main (3)"
return 0
}
gdb_test "" "3: c_global = 43\\r\\nwarning: .*b_global.*\\r\\n1: a_global = 41" "after rerun"
# Now verify that displays which are not in the shared library
# are not cleared permaturely.
gdb_test "break [gdb_get_line_number "break here" ${testfile}.c]" \
".*Breakpoint.* at .*"
gdb_test "continue"
gdb_test "display main_global" "4: main_global = 44"
gdb_test "display a_local" "5: a_local = 45"
gdb_test "display a_static" "6: a_static = 46"
if { [gdb_start_cmd] < 0 } {
fail "Can't run to main (4)"
return 0
}
gdb_test "" "6: a_static = 46\\r\\n4: main_global = 44\\r\\n.*"
gdb_test "break [gdb_get_line_number "break here" ${testfile}.c]" \
".*Breakpoint.* at .*"
gdb_test "continue" "6: a_static = 46\\r\\n5: a_local = 45\\r\\n4: main_global = 44\\r\\n.*"
set pf_prefix $save_pf_prefix

View file

@ -2896,6 +2896,9 @@ proc build_id_debug_filename_get { exec } {
# Create stripped files for DEST, replacing it. If ARGS is passed, it is a
# list of optional flags. The only currently supported flag is no-main,
# which removes the symbol entry for main from the separate debug file.
#
# Function returns zero on success. Function will return non-zero failure code
# on some targets not supporting separate debug info (such as i386-msdos).
proc gdb_gnu_strip_debug { dest args } {