summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2016-09-19 15:44:04 +0100
committerPedro Alves <palves@redhat.com>2016-09-19 15:44:04 +0100
commit763ac59c4ecbed8305c03666db1235dbd52f6d3e (patch)
treeaf87f375cdb29fd2606d203ad30627540558d194
parent2387dd904938566f5d1d6df6670b5dec9dd3f463 (diff)
downloadbinutils-gdb-763ac59c4ecbed8305c03666db1235dbd52f6d3e.tar.gz
Fix C++ and PLTs (PR 17201, PR17199 ?)
-rw-r--r--gdb/linespec.c22
-rw-r--r--gdb/testsuite/gdb.base/break-trampoline-solib.c20
-rw-r--r--gdb/testsuite/gdb.base/break-trampoline.c24
-rw-r--r--gdb/testsuite/gdb.base/break-trampoline.exp162
4 files changed, 228 insertions, 0 deletions
diff --git a/gdb/linespec.c b/gdb/linespec.c
index ccedec8841a..e203fbeeced 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -3651,10 +3651,26 @@ struct collect_minsyms
/* The list_mode setting from the initial call. */
int list_mode;
+ /* If WANT_TRAMPOLINE is set, ignore mst_text @plt symbols, thus
+ collecting only the corresponding mst_solib_trampoline
+ symbol. */
+ int want_trampoline;
+
/* The resulting symbols. */
VEC (bound_minimal_symbol_d) *msyms;
};
+static int
+name_is_plt (const char *name)
+{
+ size_t len = strlen (name);
+
+ if (len > 4 && strcmp (name + len - 4, "@plt") == 0)
+ return 1;
+
+ return 0;
+}
+
/* A helper function to classify a minimal_symbol_type according to
priority. */
@@ -3701,6 +3717,11 @@ add_minsym (struct minimal_symbol *minsym, void *d)
struct collect_minsyms *info = (struct collect_minsyms *) d;
bound_minimal_symbol_d mo;
+ if (info->want_trampoline
+ && MSYMBOL_TYPE (minsym) == mst_text
+ && name_is_plt (MSYMBOL_LINKAGE_NAME (minsym)))
+ return;
+
mo.minsym = minsym;
mo.objfile = info->objfile;
@@ -3767,6 +3788,7 @@ search_minsyms_for_name (struct collect_info *info, const char *name,
local.funfirstline = info->state->funfirstline;
local.list_mode = info->state->list_mode;
local.symtab = symtab;
+ local.want_trampoline = !name_is_plt (name);
cleanup = make_cleanup (VEC_cleanup (bound_minimal_symbol_d), &local.msyms);
diff --git a/gdb/testsuite/gdb.base/break-trampoline-solib.c b/gdb/testsuite/gdb.base/break-trampoline-solib.c
new file mode 100644
index 00000000000..9f52d0b8466
--- /dev/null
+++ b/gdb/testsuite/gdb.base/break-trampoline-solib.c
@@ -0,0 +1,20 @@
+/* Copyright 2016 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+int
+foo (void)
+{
+ return 0; /* in dso */
+}
diff --git a/gdb/testsuite/gdb.base/break-trampoline.c b/gdb/testsuite/gdb.base/break-trampoline.c
new file mode 100644
index 00000000000..c81db336ea1
--- /dev/null
+++ b/gdb/testsuite/gdb.base/break-trampoline.c
@@ -0,0 +1,24 @@
+/* Copyright 2016 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Shared library entry point. */
+extern int foo (void);
+
+int
+main (void)
+{
+ foo ();
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/break-trampoline.exp b/gdb/testsuite/gdb.base/break-trampoline.exp
new file mode 100644
index 00000000000..e2907dc6a38
--- /dev/null
+++ b/gdb/testsuite/gdb.base/break-trampoline.exp
@@ -0,0 +1,162 @@
+# Copyright 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Exercise various corner cases around plt symbols:
+#
+# - Make sure that setting a breakpoint on "foo" in a shared library
+# does not end up with a location set in foo@plt if the shared
+# library is loaded. Instead the foo@plt location is replaced by
+# the "foo" function in the shared library.
+#
+if { [skip_shlib_tests] } {
+ return 0
+}
+
+standard_testfile break-trampoline.c break-trampoline-solib.c
+set exec_src ${srcdir}/${subdir}/${srcfile}
+set lib_src ${srcdir}/${subdir}/${srcfile2}
+
+# Test both C and C++.
+
+proc do_test {lang} {
+ global exec_src lib_src binfile gdb_prompt
+ global hex decimal
+
+ set lib [standard_output_file break-trampoline-solib-$lang.so]
+ set lib_opts [list debug $lang]
+
+ set binfile [standard_output_file break-trampoline-$lang]
+ set exec_opts [list debug $lang shlib=${lib}]
+
+ if [get_compiler_info] {
+ return -1
+ }
+
+ if { [gdb_compile_shlib ${lib_src} ${lib} $lib_opts] != ""
+ || [gdb_compile ${exec_src} ${binfile} executable $exec_opts] != ""} {
+ untested "Could not compile $lib or $binfile."
+ return -1
+ }
+
+ set any "\[^\r\n\]*"
+ set ws "\[ \t\]*"
+
+ if {$lang == "c++"} {
+ set foo_plt "foo()@plt"
+ set foo_sym "foo()"
+ } else {
+ set foo_plt "foo@plt"
+ set foo_sym "foo"
+ }
+ set foo_plt_re [string_to_regexp $foo_plt]
+ set foo_sym_re [string_to_regexp $foo_sym]
+
+ with_test_prefix "set break before run" {
+ clean_restart ${binfile}
+ gdb_load_shlib ${lib}
+
+ gdb_test "break foo" "Breakpoint 1 at $hex"
+
+ set test "info breakpoints before run"
+ gdb_test_multiple "info breakpoints" $test {
+ -re "breakpoint${any}<${foo_plt_re}>\r\n$gdb_prompt $" {
+ pass $test
+ }
+ }
+
+ gdb_run_cmd
+ set test "run to foo"
+ gdb_test_multiple "" $test {
+ -re "foo \\(\\) at ${any}${lib_src}:${decimal}\r\n.*$gdb_prompt $" {
+ pass $test
+ }
+ }
+
+ set test "info breakpoints, foo resolved"
+ gdb_test_multiple "info breakpoints" $test {
+ -re "${foo_plt_re}.*$gdb_prompt $" {
+ fail "$test (PR 17201)"
+ }
+ -re "breakpoint${ws}${any}y${any}in ${foo_sym_re} at ${any}${lib_src}:${decimal}\r\n.*hit 1 time.*$gdb_prompt $" {
+ pass $test
+ }
+ }
+ }
+
+ # Test that setting a breakpoint on the plt symbol directly does
+ # not end up resolved to the text symbol in the dso.
+ with_test_prefix "set breat at plt before run" {
+ clean_restart ${binfile}
+ gdb_load_shlib ${lib}
+
+ gdb_test "break ${foo_plt}" "Breakpoint 1 at $hex"
+
+ set test "info breakpoints before run"
+ gdb_test_multiple "info breakpoints" $test {
+ -re "breakpoint${any}<$foo_plt_re>\r\n$gdb_prompt $" {
+ pass $test
+ }
+ }
+
+ set test "run to foo@plt"
+ gdb_run_cmd
+ gdb_test_multiple "" $test {
+ -re "in ${foo_plt_re}.*$gdb_prompt $" {
+ pass $test
+ }
+ }
+
+ set test "info breakpoints after run"
+ gdb_test_multiple "info breakpoints" $test {
+ -re "breakpoint${any}<${foo_plt_re}>\r\n.*hit 1 time.*$gdb_prompt $" {
+ pass $test
+ }
+ }
+ }
+
+ with_test_prefix "set break after run" {
+ clean_restart ${binfile}
+ gdb_load_shlib ${lib}
+
+ if ![runto_main] {
+ return 0
+ }
+
+ # Set up breakpoints.
+ set test "break foo"
+ gdb_test_multiple "break foo" $test {
+ -re "2 locations.*$gdb_prompt $" {
+ fail "$test (PR 17201)"
+ }
+ -re "Breakpoint 2 at $hex: file .*$lib_src, line.*$gdb_prompt $" {
+ pass $test
+ }
+ }
+
+ set test "info breakpoints"
+ gdb_test_multiple "info breakpoints" $test {
+ -re "${foo_plt_re}.*$gdb_prompt $" {
+ fail "$test (PR 17201)"
+ }
+ -re "breakpoint${any} in ${foo_sym_re} at ${any}$lib_src:${any}\r\n$gdb_prompt $" {
+ pass $test
+ }
+ }
+ }
+}
+
+foreach_with_prefix language {c c++} {
+ do_test $language
+}