PR 20569, segv in follow_exec

The following testcases make GDB crash whenever an invalid sysroot is
provided, when GDB is unable to find a valid path to the symbol file:

 gdb.base/catch-syscall.exp
 gdb.base/execl-update-breakpoints.exp
 gdb.base/foll-exec-mode.exp
 gdb.base/foll-exec.exp
 gdb.base/foll-vfork.exp
 gdb.base/pie-execl.exp
 gdb.multi/bkpt-multi-exec.exp
 gdb.python/py-finish-breakpoint.exp
 gdb.threads/execl.exp
 gdb.threads/non-ldr-exc-1.exp
 gdb.threads/non-ldr-exc-2.exp
 gdb.threads/non-ldr-exc-3.exp
 gdb.threads/non-ldr-exc-4.exp
 gdb.threads/thread-execl.exp

The immediate cause of the segv is that follow_exec is passing a NULL
argument (the result of exec_file_find) to strlen.

However, the problem is deeper than that: follow_exec simply isn't
prepared for the case where sysroot translation fails to locate the
new executable.  Actually all callers of exec_file_find have bugs due
to confusion between host and target pathnames.  This commit attempts
to fix all that.

In terms of the testcases that were formerly segv'ing, GDB now prints
a warning but continues execution of the new program, so that the
tests now mostly FAIL instead.  You could argue the FAILs are due to a
legitimate problem with the test environment setting up the sysroot
translation incorrectly.

A new representative test is added which exercises the ne wwarning
code path even with native testing.

Tested on x86_64 Fedora 23, native and gdbserver.

gdb/ChangeLog:
2016-10-25  Sandra Loosemore  <sandra@codesourcery.com>
	    Luis Machado  <lgustavo@codesourcery.com>
	    Pedro Alves  <palves@redhat.com>

	PR gdb/20569
	* exceptions.c (exception_print_same): Moved here from exec.c.
	* exceptions.h (exception_print_same): Declare.
	* exec.h: Include "symfile-add-flags.h".
	(try_open_exec_file): New declaration.
	* exec.c (exception_print_same): Moved to exceptions.c.
	(try_open_exec_file): New function.
	(exec_file_locate_attach): Rename exec_file and full_exec_path
	variables to avoid confusion between target and host pathnames.
	Move pathname processing logic to exec_file_find.  Do not return
	early if pathname lookup fails; Call try_open_exec_file.
	* infrun.c (follow_exec): Split and rename execd_pathname variable
	to avoid confusion between target and host pathnames.  Warn if
	pathname lookup fails.  Pass target pathname to
	target_follow_exec, not hostpathname.  Call try_open_exec_file.
	* main.c (symbol_file_add_main_adapter): New function.
	(captured_main_1): Use it.
	* solib-svr4.c (open_symbol_file_object): Adjust to pass
	symfile_add_flags to symbol_file_add_main.
	* solib.c (exec_file_find): Incorporate fallback logic for relative
	pathnames formerly in exec_file_locate_attach.
	* symfile.c (symbol_file_add_main, symbol_file_add_main_1):
	Replace 'from_tty' parameter with a symfile_add_file.
	(symbol_file_command): Adjust to pass symfile_add_flags to
	symbol_file_add_main.
	* symfile.h (symbol_file_add_main): Replace 'from_tty' parameter
	with a symfile_add_file.

gdb/testsuite/ChangeLog:
2016-10-25  Luis Machado  <lgustavo@codesourcery.com>

	* gdb.base/exec-invalid-sysroot.exp: New file.
This commit is contained in:
Sandra Loosemore 2016-10-26 12:12:01 -05:00 committed by Pedro Alves
parent b15cc25cbe
commit ecf45d2cc7
14 changed files with 277 additions and 121 deletions

View file

@ -1077,15 +1077,17 @@ show_follow_exec_mode_string (struct ui_file *file, int from_tty,
fprintf_filtered (file, _("Follow exec mode is \"%s\".\n"), value);
}
/* EXECD_PATHNAME is assumed to be non-NULL. */
/* EXEC_FILE_TARGET is assumed to be non-NULL. */
static void
follow_exec (ptid_t ptid, char *execd_pathname)
follow_exec (ptid_t ptid, char *exec_file_target)
{
struct thread_info *th, *tmp;
struct inferior *inf = current_inferior ();
int pid = ptid_get_pid (ptid);
ptid_t process_ptid;
char *exec_file_host;
struct cleanup *old_chain;
/* This is an exec event that we actually wish to pay attention to.
Refresh our symbol table to the newly exec'd program, remove any
@ -1155,7 +1157,7 @@ follow_exec (ptid_t ptid, char *execd_pathname)
process_ptid = pid_to_ptid (pid);
printf_unfiltered (_("%s is executing new program: %s\n"),
target_pid_to_str (process_ptid),
execd_pathname);
exec_file_target);
/* We've followed the inferior through an exec. Therefore, the
inferior has essentially been killed & reborn. */
@ -1164,14 +1166,17 @@ follow_exec (ptid_t ptid, char *execd_pathname)
breakpoint_init_inferior (inf_execd);
if (*gdb_sysroot != '\0')
{
char *name = exec_file_find (execd_pathname, NULL);
exec_file_host = exec_file_find (exec_file_target, NULL);
old_chain = make_cleanup (xfree, exec_file_host);
execd_pathname = (char *) alloca (strlen (name) + 1);
strcpy (execd_pathname, name);
xfree (name);
}
/* If we were unable to map the executable target pathname onto a host
pathname, tell the user that. Otherwise GDB's subsequent behavior
is confusing. Maybe it would even be better to stop at this point
so that the user can specify a file manually before continuing. */
if (exec_file_host == NULL)
warning (_("Could not load symbols for executable %s.\n"
"Do you need \"set sysroot\"?"),
exec_file_target);
/* Reset the shared library package. This ensures that we get a
shlib event when the child reaches "_start", at which point the
@ -1193,7 +1198,7 @@ follow_exec (ptid_t ptid, char *execd_pathname)
inf = add_inferior_with_spaces ();
inf->pid = pid;
target_follow_exec (inf, execd_pathname);
target_follow_exec (inf, exec_file_target);
set_current_inferior (inf);
set_current_program_space (inf->pspace);
@ -1212,21 +1217,14 @@ follow_exec (ptid_t ptid, char *execd_pathname)
gdb_assert (current_program_space == inf->pspace);
/* That a.out is now the one to use. */
exec_file_attach (execd_pathname, 0);
/* Attempt to open the exec file. SYMFILE_DEFER_BP_RESET is used
because the proper displacement for a PIE (Position Independent
Executable) main symbol file will only be computed by
solib_create_inferior_hook below. breakpoint_re_set would fail
to insert the breakpoints with the zero displacement. */
try_open_exec_file (exec_file_host, inf, SYMFILE_DEFER_BP_RESET);
/* SYMFILE_DEFER_BP_RESET is used as the proper displacement for PIE
(Position Independent Executable) main symbol file will get applied by
solib_create_inferior_hook below. breakpoint_re_set would fail to insert
the breakpoints with the zero displacement. */
symbol_file_add (execd_pathname,
(inf->symfile_flags
| SYMFILE_MAINLINE | SYMFILE_DEFER_BP_RESET),
NULL, 0);
if ((inf->symfile_flags & SYMFILE_NO_READ) == 0)
set_initial_language ();
do_cleanups (old_chain);
/* If the target can specify a description, read it. Must do this
after flipping to the new executable (because the target supplied