diff options
-rw-r--r-- | gdb/ChangeLog | 23 | ||||
-rw-r--r-- | gdb/ada-lang.c | 31 | ||||
-rw-r--r-- | gdb/c-lang.c | 1 | ||||
-rw-r--r-- | gdb/jv-lang.c | 1 | ||||
-rw-r--r-- | gdb/m2-lang.c | 1 | ||||
-rw-r--r-- | gdb/parse.c | 145 | ||||
-rw-r--r-- | gdb/parser-defs.h | 20 | ||||
-rw-r--r-- | gdb/printcmd.c | 73 | ||||
-rw-r--r-- | gdb/scm-lang.c | 1 | ||||
-rw-r--r-- | gdb/solist.h | 7 | ||||
-rw-r--r-- | gdb/symtab.c | 2 | ||||
-rw-r--r-- | gdb/symtab.h | 4 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 11 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/solib-display.exp | 146 | ||||
-rw-r--r-- | gdb/testsuite/lib/gdb.exp | 3 |
15 files changed, 355 insertions, 114 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 42571e6..e0e3353 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -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> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index abc9c9f..9da0609 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -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 diff --git a/gdb/c-lang.c b/gdb/c-lang.c index fefd675..805c572 100644 --- a/gdb/c-lang.c +++ b/gdb/c-lang.c @@ -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 diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c index 6c449ef..b911724 100644 --- a/gdb/jv-lang.c +++ b/gdb/jv-lang.c @@ -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 diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c index 80e9bf9..3057774 100644 --- a/gdb/m2-lang.c +++ b/gdb/m2-lang.c @@ -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 diff --git a/gdb/parse.c b/gdb/parse.c index aabc461..51e1550 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -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) { diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h index c4eb1a0..a37bbca 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -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 */ diff --git a/gdb/printcmd.c b/gdb/printcmd.c index be6a8a5..735b043 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -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; + } } } diff --git a/gdb/scm-lang.c b/gdb/scm-lang.c index 5898aad..23e5f22 100644 --- a/gdb/scm-lang.c +++ b/gdb/scm-lang.c @@ -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 diff --git a/gdb/solist.h b/gdb/solist.h index 77eb2ae..bcba0ad 100644 --- a/gdb/solist.h +++ b/gdb/solist.h @@ -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; diff --git a/gdb/symtab.c b/gdb/symtab.c index 29142da..28084e7 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -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; diff --git a/gdb/symtab.h b/gdb/symtab.h index a0da0db..115c8ba 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -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) */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 6bbacf0..025e50d 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -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. diff --git a/gdb/testsuite/gdb.base/solib-display.exp b/gdb/testsuite/gdb.base/solib-display.exp index 42a48d0..9ee2633 100644 --- a/gdb/testsuite/gdb.base/solib-display.exp +++ b/gdb/testsuite/gdb.base/solib-display.exp @@ -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 diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 19126a4..3a1fad3 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -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 } { |