This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]