This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch] Support gdb --args ld.so progname
- From: Jan Kratochvil <jan dot kratochvil at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Fri, 26 Feb 2010 11:11:32 +0100
- Subject: [patch] Support gdb --args ld.so progname
Hi,
Re: RFC: Verify AT_ENTRY before using it
http://sourceware.org/ml/gdb-patches/2010-02/msg00641.html
# I would find more correct to use "gdb /path/to/this/loader" instead. This
# would be mostly equivalent to local:
# ./gdb -nx -ex 'set breakpoint pending on' -ex 'b main' -ex r --args /lib64/ld-linux-x86-64.so.2 ./gdb -nx
# which currently does not work, though. GDB does not find out it should load
# "./gdb" after ld.so loads the "./gdb" binary.
#
# It is because _r_debug->r_map[0].l_name is forced to be "" by ld.so instead of
# the real executable name.
#
# The real executable name can be found from _dl_argv[0]; -> a different patch.
This is the "different patch".
While the fix "RFC: Verify AT_ENTRY before using it" is sure correct it is even
no longer needed with this patch as one can do the IMO-more-correct (although
less convenient due to the pending breakpoints requirement):
./gdbserver/gdbserver :2222 /lib64/ld-linux-x86-64.so.2 ./gdb -nx
+
./gdb -nx -ex 'target remote localhost:2222' -ex 'set breakpoint pending on' -ex 'b main' -ex c /lib64/ld-linux-x86-64.so.2
For
gdb --args /lib64/ld-linux-x86-64.so.2 gdb.base/interp-load-exec
the program name will show in the shared library list:
From To Syms Read Shared Object Library
0x00000000004003d0 0x00000000004005d8 Yes /.../gdb/testsuite/gdb.base/interp-load-exec
0x0000003000000af0 0x00000030000183d4 Yes /lib64/ld-linux-x86-64.so.2
0x0000003011a03ea0 0x0000003011a442f8 Yes /lib64/libm.so.6
0x0000003009a1e860 0x0000003009b261bc Yes /lib64/libc.so.6
No regressions on {x86_64,x86_64-m32,i686}-fedora12-linux-gnu.
Thanks,
Jan
gdb/
2010-02-26 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix `gdb --args /lib/ld.so progname'.
* solib-svr4.c (svr4_current_sos): New variables buffer_errcode, buffer,
msymbol, ptr_type, ptr_size, buf, status, dl_argv_address,
dl_argv0_address and dl_progname_address. Initialize BUFFER of the
first linkmap entry from inferior "_dl_argv[0]" if it is not EXEC_BFD.
Unify free_so call with the non-first linkmap entry block. Suppress
the warning if BUFFER_ERRCODE is -1.
gdb/testsuite/
2010-02-26 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix `gdb --args /lib/ld.so progname'.
* gdb.base/break-interp.exp (section_get): Move to ...
* lib/gdb.exp (section_get): ... here. Change $tmp basename to
"section_get.tmp". Uncomment "file delete $tmp".
* gdb.base/interp-load-exec.exp: New.
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 4317283..4d6e806 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -1115,6 +1115,15 @@ svr4_current_sos (void)
struct so_list *new = XZALLOC (struct so_list);
struct cleanup *old_chain = make_cleanup (xfree, new);
+ /* 0 means BUFFER contains valid data, -1 means BUFFER is invalid but no
+ warning should be printed, otherwise it is a positive errno code. */
+ int buffer_errcode = EIO;
+
+ /* Maximum bytes size is SO_NAME_MAX_PATH_SIZE - 1 which may not be
+ 0-terminated. It is 0-terminated if the string is shorter. BUFFER
+ can be non-NULL and containing invalid data if BUFFER_ERRCODE != 0. */
+ char *buffer = NULL;
+
new->lm_info = xmalloc (sizeof (struct lm_info));
make_cleanup (xfree, new->lm_info);
@@ -1128,45 +1137,107 @@ svr4_current_sos (void)
lm = LM_NEXT (new);
/* For SVR4 versions, the first entry in the link map is for the
- inferior executable, so we must ignore it. For some versions of
+ inferior executable, so we should ignore it. For some versions of
SVR4, it has no name. For others (Solaris 2.3 for example), it
does have a name, so we can no longer use a missing name to
- decide when to ignore it. */
+ decide when to ignore it.
+
+ In the case of `gdb --args /lib/ld.so progname' execution we should
+ load progname like a library with its symbols. We use GNU ld.so
+ variable `rtld_progname' which maps to `_dl_argv[0]'. `_dl_argv[0]'
+ contains the executable name even when additional ld.so options
+ such as `ld.so --library-path PATH progname' are present. */
+
if (IGNORE_FIRST_LINK_MAP_ENTRY (new) && ldsomap == 0)
{
+ struct minimal_symbol *msymbol;
+ struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
+ size_t ptr_size = TYPE_LENGTH (ptr_type);
+ gdb_byte *buf = alloca (ptr_size);
+ int status = EIO;
+
+ /* Address where `_dl_argv' is located in inferior. */
+ CORE_ADDR dl_argv_address;
+
+ /* Content of the `_dl_argv' variable in inferior, that is
+ address of the `_dl_argv[0]' variable. */
+ CORE_ADDR dl_argv0_address;
+
+ /* Content of the `_dl_argv[0]' variable in inferior, that is
+ address of the start of `_dl_argv[0]' progname string. */
+ CORE_ADDR dl_progname_address;
+
info->main_lm_addr = new->lm_info->lm_addr;
- free_so (new);
+
+ msymbol = lookup_minimal_symbol ("_dl_argv", NULL, NULL);
+ if (msymbol == NULL)
+ {
+ /* Suppress printing an error message on non-GNU ld.so. */
+ buffer_errcode = -1;
+ }
+ else if (MSYMBOL_SIZE (msymbol) == ptr_size)
+ {
+ dl_argv_address = SYMBOL_VALUE_ADDRESS (msymbol);
+
+ status = target_read_memory (dl_argv_address, buf, ptr_size);
+ }
+ if (status == 0)
+ {
+ dl_argv0_address = extract_typed_address (buf, ptr_type);
+
+ status = target_read_memory (dl_argv0_address, buf, ptr_size);
+ }
+ if (status == 0)
+ {
+ dl_progname_address = extract_typed_address (buf, ptr_type);
+
+ target_read_string (dl_progname_address, &buffer,
+ SO_NAME_MAX_PATH_SIZE - 1, &buffer_errcode);
+ }
+ if (buffer_errcode == 0 && exec_bfd)
+ {
+ char name[SO_NAME_MAX_PATH_SIZE];
+
+ strncpy (name, buffer, SO_NAME_MAX_PATH_SIZE - 1);
+ name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+
+ /* Do not duplicate the executable in shared library list. */
+
+ if (strcmp (name, bfd_get_filename (exec_bfd)) == 0)
+ buffer_errcode = -1;
+ }
}
else
{
- int errcode;
- char *buffer;
-
/* Extract this shared object's name. */
target_read_string (LM_NAME (new), &buffer,
- SO_NAME_MAX_PATH_SIZE - 1, &errcode);
- if (errcode != 0)
+ SO_NAME_MAX_PATH_SIZE - 1, &buffer_errcode);
+ }
+
+ if (buffer_errcode != 0)
+ {
+ if (buffer_errcode != -1)
warning (_("Can't read pathname for load map: %s."),
- safe_strerror (errcode));
- else
- {
- strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1);
- new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
- strcpy (new->so_original_name, new->so_name);
- }
- xfree (buffer);
+ safe_strerror (buffer_errcode));
+ }
+ else
+ {
+ strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1);
+ new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+ strcpy (new->so_original_name, new->so_name);
+ }
+ xfree (buffer);
- /* If this entry has no name, or its name matches the name
- for the main executable, don't include it in the list. */
- if (! new->so_name[0]
- || match_main (new->so_name))
- free_so (new);
- else
- {
- new->next = 0;
- *link_ptr = new;
- link_ptr = &new->next;
- }
+ /* If this entry has no name, or its name matches the name
+ for the main executable, don't include it in the list. */
+ if (! new->so_name[0]
+ || match_main (new->so_name))
+ free_so (new);
+ else
+ {
+ new->next = 0;
+ *link_ptr = new;
+ link_ptr = &new->next;
}
/* On Solaris, the dynamic linker is not in the normal list of
diff --git a/gdb/testsuite/gdb.base/break-interp.exp b/gdb/testsuite/gdb.base/break-interp.exp
index e628979..0be99d0 100644
--- a/gdb/testsuite/gdb.base/break-interp.exp
+++ b/gdb/testsuite/gdb.base/break-interp.exp
@@ -42,38 +42,6 @@ if {[build_executable ${test}.exp $binfile_test ${srcfile_test} {}] == -1} {
return -1
}
-# Return the interpreter filename string.
-# Return "" if no interpreter was found.
-proc section_get {exec section} {
- global objdir
- global subdir
- set tmp "${objdir}/${subdir}/break-interp.interp"
- set objcopy_program [transform objcopy]
-
- set command "exec $objcopy_program -O binary --set-section-flags $section=A --change-section-address $section=0 -j $section $exec $tmp"
- verbose -log "command is $command"
- set result [catch $command output]
- verbose -log "result is $result"
- verbose -log "output is $output"
- if {$result == 1} {
- return ""
- }
- set fi [open $tmp]
- fconfigure $fi -translation binary
- set data [read $fi]
- close $fi
- #file delete $tmp
- # .interp has size $len + 1 but .gnu_debuglink contains garbage after \000.
- set len [string first \000 $data]
- if {$len < 0} {
- verbose -log "section $section not found"
- return ""
- }
- set retval [string range $data 0 [expr $len - 1]]
- verbose -log "section $section is <$retval>"
- return $retval
-}
-
# Note: The separate debug info file content build-id/crc32 are not verified
# contrary to the GDB search algorithm skipping non-matching ones.
proc system_debug_get {exec} {
diff --git a/gdb/testsuite/gdb.base/interp-load-exec.exp b/gdb/testsuite/gdb.base/interp-load-exec.exp
new file mode 100644
index 0000000..b311ee8
--- /dev/null
+++ b/gdb/testsuite/gdb.base/interp-load-exec.exp
@@ -0,0 +1,70 @@
+# Copyright 2010 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/>.
+
+if {[is_remote host] || [skip_shlib_tests]} {
+ continue
+}
+
+set testfile "interp-load-exec"
+set srcfile "start.c"
+set executable $testfile
+set binfile ${objdir}/${subdir}/$executable
+
+if {[build_executable ${testfile}.exp $executable $srcfile] == -1} {
+ return -1
+}
+
+set interp_system [section_get $binfile .interp]
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${interp_system}
+
+gdb_test "set args $binfile"
+
+set test "interp: reach foo"
+if {[runto "foo" allow-pending] > 0} {
+ pass $test
+} else {
+ fail $test
+}
+
+set test "interp: executable is in info sharedlibrary"
+gdb_test_multiple "info sharedlibrary" $test {
+ -re "$executable.*$gdb_prompt $" {
+ pass $test
+ }
+}
+
+
+clean_restart $executable
+
+set test "direct: reach foo"
+if {[runto "foo" allow-pending] > 0} {
+ pass $test
+} else {
+ fail $test
+}
+
+set test "direct: executable is not in info sharedlibrary"
+gdb_test_multiple "info sharedlibrary" $test {
+ -re "$executable.*$gdb_prompt $" {
+ fail $test
+ }
+ -re "$gdb_prompt $" {
+ pass $test
+ }
+}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 8c18f33..93d1783 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -3220,3 +3220,35 @@ proc core_find {binfile {deletefiles {}} {arg ""}} {
}
return $destcore
}
+
+# Return the interpreter filename string.
+# Return "" if no interpreter was found.
+proc section_get {exec section} {
+ global objdir
+ global subdir
+ set tmp "${objdir}/${subdir}/section_get.tmp"
+ set objcopy_program [transform objcopy]
+
+ set command "exec $objcopy_program -O binary --set-section-flags $section=A --change-section-address $section=0 -j $section $exec $tmp"
+ verbose -log "command is $command"
+ set result [catch $command output]
+ verbose -log "result is $result"
+ verbose -log "output is $output"
+ if {$result == 1} {
+ return ""
+ }
+ set fi [open $tmp]
+ fconfigure $fi -translation binary
+ set data [read $fi]
+ close $fi
+ file delete $tmp
+ # .interp has size $len + 1 but .gnu_debuglink contains garbage after \000.
+ set len [string first \000 $data]
+ if {$len < 0} {
+ verbose -log "section $section not found"
+ return ""
+ }
+ set retval [string range $data 0 [expr $len - 1]]
+ verbose -log "section $section is <$retval>"
+ return $retval
+}