c5f8fe0a54
one. - Drop gdb-6.3-nonthreaded-wp-20050117.patch as fuzzy + redundant. - Fix callback-mode readline-6.0 regression for CTRL-C. - Fix syscall restarts for amd64->i386 biarch. - Various testsuite results stability fixes. - Fix crash on reading stabs on 64bit (BZ 537837). - archer-jankratochvil-fedora12 commit: 16276c1aad1366b92e687c72cab30192280e1906 - archer-jankratochvil-pie-fedora12 ct: 2ae60b5156d43aabfe5757940eaf7b4370fb05d2
2648 lines
88 KiB
Diff
2648 lines
88 KiB
Diff
http://sourceware.org/gdb/wiki/ProjectArcher
|
||
http://sourceware.org/gdb/wiki/ArcherBranchManagement
|
||
|
||
archer-jankratochvil-pie-fedora12
|
||
GIT snapshot:
|
||
commit 2ae60b5156d43aabfe5757940eaf7b4370fb05d2
|
||
|
||
|
||
diff --git a/gdb/auxv.c b/gdb/auxv.c
|
||
index 7b4ecbe..7df8eb5 100644
|
||
--- a/gdb/auxv.c
|
||
+++ b/gdb/auxv.c
|
||
@@ -25,6 +25,7 @@
|
||
#include "inferior.h"
|
||
#include "valprint.h"
|
||
#include "gdb_assert.h"
|
||
+#include "gdbcore.h"
|
||
|
||
#include "auxv.h"
|
||
#include "elf/common.h"
|
||
@@ -33,15 +34,11 @@
|
||
#include <fcntl.h>
|
||
|
||
|
||
-/* This function is called like a to_xfer_partial hook, but must be
|
||
- called with TARGET_OBJECT_AUXV. It handles access via
|
||
- /proc/PID/auxv, which is a common method for native targets. */
|
||
+/* This function handles access via /proc/PID/auxv, which is a common method
|
||
+ for native targets. */
|
||
|
||
-LONGEST
|
||
-procfs_xfer_auxv (struct target_ops *ops,
|
||
- enum target_object object,
|
||
- const char *annex,
|
||
- gdb_byte *readbuf,
|
||
+static LONGEST
|
||
+procfs_xfer_auxv (gdb_byte *readbuf,
|
||
const gdb_byte *writebuf,
|
||
ULONGEST offset,
|
||
LONGEST len)
|
||
@@ -50,9 +47,6 @@ procfs_xfer_auxv (struct target_ops *ops,
|
||
int fd;
|
||
LONGEST n;
|
||
|
||
- gdb_assert (object == TARGET_OBJECT_AUXV);
|
||
- gdb_assert (readbuf || writebuf);
|
||
-
|
||
pathname = xstrprintf ("/proc/%d/auxv", PIDGET (inferior_ptid));
|
||
fd = open (pathname, writebuf != NULL ? O_WRONLY : O_RDONLY);
|
||
xfree (pathname);
|
||
@@ -72,6 +66,152 @@ procfs_xfer_auxv (struct target_ops *ops,
|
||
return n;
|
||
}
|
||
|
||
+/* This function handles access via ld.so's symbol `_dl_auxv'. */
|
||
+
|
||
+static LONGEST
|
||
+ld_so_xfer_auxv (gdb_byte *readbuf,
|
||
+ const gdb_byte *writebuf,
|
||
+ ULONGEST offset,
|
||
+ LONGEST len)
|
||
+{
|
||
+ struct minimal_symbol *msym;
|
||
+ CORE_ADDR data_address, pointer_address;
|
||
+ struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
|
||
+ size_t ptr_size = TYPE_LENGTH (ptr_type);
|
||
+ size_t auxv_pair_size = 2 * ptr_size;
|
||
+ gdb_byte *ptr_buf = alloca (ptr_size);
|
||
+ LONGEST retval;
|
||
+ size_t block;
|
||
+
|
||
+ msym = lookup_minimal_symbol ("_dl_auxv", NULL, NULL);
|
||
+ if (msym == NULL)
|
||
+ return -1;
|
||
+
|
||
+ if (MSYMBOL_SIZE (msym) != ptr_size)
|
||
+ return -1;
|
||
+
|
||
+ /* POINTER_ADDRESS is a location where the `_dl_auxv' variable resides.
|
||
+ DATA_ADDRESS is the inferior value present in `_dl_auxv', therefore the
|
||
+ real inferior AUXV address. */
|
||
+
|
||
+ pointer_address = SYMBOL_VALUE_ADDRESS (msym);
|
||
+
|
||
+ data_address = read_memory_typed_address (pointer_address, ptr_type);
|
||
+
|
||
+ /* Possibly still not initialized such as during an inferior startup. */
|
||
+ if (data_address == 0)
|
||
+ return -1;
|
||
+
|
||
+ data_address += offset;
|
||
+
|
||
+ if (writebuf != NULL)
|
||
+ {
|
||
+ if (target_write_memory (data_address, writebuf, len) == 0)
|
||
+ return len;
|
||
+ else
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ /* Stop if trying to read past the existing AUXV block. The final AT_NULL
|
||
+ was already returned before. */
|
||
+
|
||
+ if (offset >= auxv_pair_size)
|
||
+ {
|
||
+ if (target_read_memory (data_address - auxv_pair_size, ptr_buf,
|
||
+ ptr_size) != 0)
|
||
+ return -1;
|
||
+
|
||
+ if (extract_typed_address (ptr_buf, ptr_type) == AT_NULL)
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ retval = 0;
|
||
+ block = 0x400;
|
||
+ gdb_assert (block % auxv_pair_size == 0);
|
||
+
|
||
+ while (len > 0)
|
||
+ {
|
||
+ if (block > len)
|
||
+ block = len;
|
||
+
|
||
+ /* Reading sizes smaller than AUXV_PAIR_SIZE is not supported. Tails
|
||
+ unaligned to AUXV_PAIR_SIZE will not be read during a call (they
|
||
+ should be completed during next read with new/extended buffer). */
|
||
+
|
||
+ block &= -auxv_pair_size;
|
||
+ if (block == 0)
|
||
+ return retval;
|
||
+
|
||
+ if (target_read_memory (data_address, readbuf, block) != 0)
|
||
+ {
|
||
+ if (block <= auxv_pair_size)
|
||
+ return retval;
|
||
+
|
||
+ block = auxv_pair_size;
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ data_address += block;
|
||
+ len -= block;
|
||
+
|
||
+ /* Check terminal AT_NULL. This function is being called indefinitely
|
||
+ being extended its READBUF until it returns EOF (0). */
|
||
+
|
||
+ while (block >= auxv_pair_size)
|
||
+ {
|
||
+ retval += auxv_pair_size;
|
||
+
|
||
+ if (extract_typed_address (readbuf, ptr_type) == AT_NULL)
|
||
+ return retval;
|
||
+
|
||
+ readbuf += auxv_pair_size;
|
||
+ block -= auxv_pair_size;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return retval;
|
||
+}
|
||
+
|
||
+/* This function is called like a to_xfer_partial hook, but must be
|
||
+ called with TARGET_OBJECT_AUXV. It handles access to AUXV. */
|
||
+
|
||
+LONGEST
|
||
+memory_xfer_auxv (struct target_ops *ops,
|
||
+ enum target_object object,
|
||
+ const char *annex,
|
||
+ gdb_byte *readbuf,
|
||
+ const gdb_byte *writebuf,
|
||
+ ULONGEST offset,
|
||
+ LONGEST len)
|
||
+{
|
||
+ /* Workaround gdb-7.0 bug where linux_nat_xfer_partial() does
|
||
+ inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid));
|
||
+ and current_inferior() assertion fails not finding the LWP->PID.
|
||
+ It got fixed post-gdb-7.0 by:
|
||
+ Add base multi-executable/process support to GDB.
|
||
+ 40ff0a289e6165aa930af284df5c52162cb0cd5f
|
||
+ by introducing `current_inferior_'. */
|
||
+ struct inferior *inf = find_inferior_pid (ptid_get_pid (inferior_ptid));
|
||
+
|
||
+ gdb_assert (object == TARGET_OBJECT_AUXV);
|
||
+ gdb_assert (readbuf || writebuf);
|
||
+
|
||
+ /* ld_so_xfer_auxv is the only function safe for virtual executables being
|
||
+ executed by valgrind's memcheck. As using ld_so_xfer_auxv is problematic
|
||
+ during inferior startup GDB does call it only for attached processes. */
|
||
+
|
||
+ if (inf == NULL || inf->attach_flag != 0)
|
||
+ {
|
||
+ LONGEST retval;
|
||
+
|
||
+ retval = ld_so_xfer_auxv (readbuf, writebuf, offset, len);
|
||
+ if (retval != -1)
|
||
+ return retval;
|
||
+ }
|
||
+
|
||
+ return procfs_xfer_auxv (readbuf, writebuf, offset, len);
|
||
+}
|
||
+
|
||
/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
|
||
Return 0 if *READPTR is already at the end of the buffer.
|
||
Return -1 if there is insufficient buffer for a whole entry.
|
||
diff --git a/gdb/auxv.h b/gdb/auxv.h
|
||
index 71e6562..87c24ae 100644
|
||
--- a/gdb/auxv.h
|
||
+++ b/gdb/auxv.h
|
||
@@ -43,11 +43,7 @@ extern int target_auxv_search (struct target_ops *ops,
|
||
/* Print the contents of the target's AUXV on the specified file. */
|
||
extern int fprint_target_auxv (struct ui_file *file, struct target_ops *ops);
|
||
|
||
-/* This function is called like a to_xfer_partial hook, but must be
|
||
- called with TARGET_OBJECT_AUXV. It handles access via
|
||
- /proc/PID/auxv, which is a common method for native targets. */
|
||
-
|
||
-extern LONGEST procfs_xfer_auxv (struct target_ops *ops,
|
||
+extern LONGEST memory_xfer_auxv (struct target_ops *ops,
|
||
enum target_object object,
|
||
const char *annex,
|
||
gdb_byte *readbuf,
|
||
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
|
||
index 0f35101..bffc5a6 100644
|
||
--- a/gdb/breakpoint.c
|
||
+++ b/gdb/breakpoint.c
|
||
@@ -4805,7 +4805,8 @@ disable_breakpoints_in_shlibs (void)
|
||
to insert those breakpoints and fail. */
|
||
if (((b->type == bp_breakpoint)
|
||
|| (b->type == bp_hardware_breakpoint)
|
||
- || (b->type == bp_tracepoint))
|
||
+ || (b->type == bp_tracepoint)
|
||
+ || b->type == bp_shlib_event)
|
||
&& !loc->shlib_disabled
|
||
#ifdef PC_SOLIB
|
||
&& PC_SOLIB (loc->address)
|
||
diff --git a/gdb/defs.h b/gdb/defs.h
|
||
index 94674dc..57aaae2 100644
|
||
--- a/gdb/defs.h
|
||
+++ b/gdb/defs.h
|
||
@@ -98,7 +98,20 @@
|
||
/* A byte from the program being debugged. */
|
||
typedef bfd_byte gdb_byte;
|
||
|
||
-/* An address in the program being debugged. Host byte order. */
|
||
+/* An address in the program being debugged. Host byte order.
|
||
+
|
||
+ Its width is the maximum width of all the supported targets. That means
|
||
+ 32-bit target will run on such GDB using 64-bit CORE_ADDR cluttering the
|
||
+ bits 32...63 with random data from internal GDB calculations. GDB currently
|
||
+ in general truncates the address width only when it is being presented/used
|
||
+ externally (such as by the paddress function).
|
||
+
|
||
+ FIXME: This is still not right as any GDB internal comparisons (such as >=)
|
||
+ of CORE_ADDR do not use the properly truncated width. As converting all the
|
||
+ CORE_ADDR operations to width-aware functions is not feasible the way out
|
||
+ could be a width-aware C++ class CORE_ADDR referencing gdbarch as its
|
||
+ constructor parameter. */
|
||
+
|
||
typedef bfd_vma CORE_ADDR;
|
||
|
||
/* The largest CORE_ADDR value. */
|
||
diff --git a/gdb/exec.c b/gdb/exec.c
|
||
index 455151e..67f40d9 100644
|
||
--- a/gdb/exec.c
|
||
+++ b/gdb/exec.c
|
||
@@ -656,8 +656,33 @@ print_section_info (struct target_section_table *t, bfd *abfd)
|
||
wrap_here (" ");
|
||
printf_filtered (_("file type %s.\n"), bfd_get_target (abfd));
|
||
if (abfd == exec_bfd)
|
||
- printf_filtered (_("\tEntry point: %s\n"),
|
||
- paddress (gdbarch, bfd_get_start_address (abfd)));
|
||
+ {
|
||
+ bfd_vma displacement = 0;
|
||
+
|
||
+ for (p = t->sections; p < t->sections_end; p++)
|
||
+ {
|
||
+ asection *asect = p->the_bfd_section;
|
||
+
|
||
+ if ((bfd_get_section_flags (abfd, asect) & (SEC_ALLOC | SEC_LOAD))
|
||
+ != (SEC_ALLOC | SEC_LOAD))
|
||
+ continue;
|
||
+
|
||
+ if (bfd_get_section_vma (abfd, asect) <= abfd->start_address
|
||
+ && abfd->start_address < bfd_get_section_vma (abfd, asect)
|
||
+ + bfd_get_section_size (asect))
|
||
+ {
|
||
+ displacement = p->addr - bfd_get_section_vma (abfd, asect);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ if (p == t->sections_end)
|
||
+ warning (_("Cannot find section for the entry point of %s.\n"),
|
||
+ bfd_get_filename (abfd));
|
||
+
|
||
+ printf_filtered (_("\tEntry point: %s\n"),
|
||
+ paddress (gdbarch, bfd_get_start_address (abfd)
|
||
+ + displacement));
|
||
+ }
|
||
for (p = t->sections; p < t->sections_end; p++)
|
||
{
|
||
printf_filtered ("\t%s", hex_string_custom (p->addr, wid));
|
||
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
|
||
index fab1892..fc0f05d 100644
|
||
--- a/gdb/infcmd.c
|
||
+++ b/gdb/infcmd.c
|
||
@@ -395,22 +395,6 @@ post_create_inferior (struct target_ops *target, int from_tty)
|
||
/* Now that we know the register layout, retrieve current PC. */
|
||
stop_pc = regcache_read_pc (get_current_regcache ());
|
||
|
||
- /* If the solist is global across processes, there's no need to
|
||
- refetch it here. */
|
||
- if (exec_bfd && !gdbarch_has_global_solist (target_gdbarch))
|
||
- {
|
||
- /* Sometimes the platform-specific hook loads initial shared
|
||
- libraries, and sometimes it doesn't. Try to do so first, so
|
||
- that we can add them with the correct value for FROM_TTY.
|
||
- If we made all the inferior hook methods consistent,
|
||
- this call could be removed. */
|
||
-#ifdef SOLIB_ADD
|
||
- SOLIB_ADD (NULL, from_tty, target, auto_solib_add);
|
||
-#else
|
||
- solib_add (NULL, from_tty, target, auto_solib_add);
|
||
-#endif
|
||
- }
|
||
-
|
||
if (exec_bfd)
|
||
{
|
||
/* Create the hooks to handle shared library load and unload
|
||
@@ -418,7 +402,25 @@ post_create_inferior (struct target_ops *target, int from_tty)
|
||
#ifdef SOLIB_CREATE_INFERIOR_HOOK
|
||
SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
|
||
#else
|
||
- solib_create_inferior_hook ();
|
||
+ solib_create_inferior_hook (from_tty);
|
||
+#endif
|
||
+ }
|
||
+
|
||
+ /* If the solist is global across processes, there's no need to
|
||
+ refetch it here. */
|
||
+ if (exec_bfd && !gdbarch_has_global_solist (target_gdbarch))
|
||
+ {
|
||
+ /* Sometimes the platform-specific hook loads initial shared
|
||
+ libraries, and sometimes it doesn't. If it doesn't FROM_TTY will be
|
||
+ incorrectly 0 but such solib targets should be fixed anyway. If we
|
||
+ made all the inferior hook methods consistent, this call could be
|
||
+ removed. Call it only after the solib target has been initialized by
|
||
+ solib_create_inferior_hook. */
|
||
+
|
||
+#ifdef SOLIB_ADD
|
||
+ SOLIB_ADD (NULL, 0, target, auto_solib_add);
|
||
+#else
|
||
+ solib_add (NULL, 0, target, auto_solib_add);
|
||
#endif
|
||
}
|
||
|
||
diff --git a/gdb/infrun.c b/gdb/infrun.c
|
||
index 9d29b15..ed451d5 100644
|
||
--- a/gdb/infrun.c
|
||
+++ b/gdb/infrun.c
|
||
@@ -544,7 +544,7 @@ follow_exec (ptid_t pid, char *execd_pathname)
|
||
#ifdef SOLIB_CREATE_INFERIOR_HOOK
|
||
SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
|
||
#else
|
||
- solib_create_inferior_hook ();
|
||
+ solib_create_inferior_hook (0);
|
||
#endif
|
||
|
||
jit_inferior_created_hook ();
|
||
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
|
||
index 0907f03..1c18782 100644
|
||
--- a/gdb/linux-nat.c
|
||
+++ b/gdb/linux-nat.c
|
||
@@ -4674,7 +4674,7 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object,
|
||
LONGEST xfer;
|
||
|
||
if (object == TARGET_OBJECT_AUXV)
|
||
- return procfs_xfer_auxv (ops, object, annex, readbuf, writebuf,
|
||
+ return memory_xfer_auxv (ops, object, annex, readbuf, writebuf,
|
||
offset, len);
|
||
|
||
if (object == TARGET_OBJECT_OSDATA)
|
||
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
|
||
index 6634703..37770f5 100644
|
||
--- a/gdb/linux-tdep.c
|
||
+++ b/gdb/linux-tdep.c
|
||
@@ -18,12 +18,8 @@
|
||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||
|
||
#include "defs.h"
|
||
-#include "gdbcore.h"
|
||
#include "gdbtypes.h"
|
||
#include "linux-tdep.h"
|
||
-#include "observer.h"
|
||
-
|
||
-#include "elf-bfd.h"
|
||
|
||
/* This function is suitable for architectures that don't
|
||
extend/override the standard siginfo structure. */
|
||
@@ -138,30 +134,3 @@ linux_get_siginfo_type (struct gdbarch *gdbarch)
|
||
|
||
return siginfo_type;
|
||
}
|
||
-
|
||
-/* Observer for the executable_changed event, to check whether the new
|
||
- exec binary is a PIE (Position Independent Executable) specimen, which
|
||
- is currently unsupported. */
|
||
-
|
||
-static void
|
||
-check_is_pie_binary (void)
|
||
-{
|
||
- Elf_Internal_Ehdr *elf_hdr;
|
||
-
|
||
- if (!exec_bfd)
|
||
- return;
|
||
- else if (bfd_get_flavour (exec_bfd) != bfd_target_elf_flavour)
|
||
- return;
|
||
-
|
||
- if (elf_tdata (exec_bfd)->elf_header->e_type == ET_DYN)
|
||
- warning (_("\
|
||
-The current binary is a PIE (Position Independent Executable), which\n\
|
||
-GDB does NOT currently support. Most debugger features will fail if used\n\
|
||
-in this session.\n"));
|
||
-}
|
||
-
|
||
-void
|
||
-_initialize_linux_tdep (void)
|
||
-{
|
||
- observer_attach_executable_changed (check_is_pie_binary);
|
||
-}
|
||
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
|
||
index 0adb045..ea89331 100644
|
||
--- a/gdb/nto-procfs.c
|
||
+++ b/gdb/nto-procfs.c
|
||
@@ -652,7 +652,7 @@ static void
|
||
procfs_post_attach (pid_t pid)
|
||
{
|
||
if (exec_bfd)
|
||
- solib_create_inferior_hook ();
|
||
+ solib_create_inferior_hook (0);
|
||
}
|
||
|
||
static ptid_t
|
||
@@ -1212,7 +1212,7 @@ procfs_create_inferior (struct target_ops *ops, char *exec_file,
|
||
|
||
if (exec_bfd != NULL
|
||
|| (symfile_objfile != NULL && symfile_objfile->obfd != NULL))
|
||
- solib_create_inferior_hook ();
|
||
+ solib_create_inferior_hook (0);
|
||
}
|
||
|
||
static void
|
||
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
|
||
index e5442ca..fb0cea9 100644
|
||
--- a/gdb/objfiles.c
|
||
+++ b/gdb/objfiles.c
|
||
@@ -544,9 +544,10 @@ free_all_objfiles (void)
|
||
}
|
||
|
||
/* Relocate OBJFILE to NEW_OFFSETS. There should be OBJFILE->NUM_SECTIONS
|
||
- entries in new_offsets. */
|
||
-void
|
||
-objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
|
||
+ entries in new_offsets. SEPARATE_DEBUG_OBJFILE is not touched here. */
|
||
+
|
||
+static void
|
||
+objfile_relocate1 (struct objfile *objfile, struct section_offsets *new_offsets)
|
||
{
|
||
struct obj_section *s;
|
||
struct section_offsets *delta =
|
||
@@ -624,6 +625,10 @@ objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
|
||
}
|
||
}
|
||
|
||
+ if (objfile->psymtabs_addrmap)
|
||
+ addrmap_relocate (objfile->psymtabs_addrmap,
|
||
+ ANOFFSET (delta, SECT_OFF_TEXT (objfile)));
|
||
+
|
||
{
|
||
struct partial_symtab *p;
|
||
|
||
@@ -701,6 +706,49 @@ objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
|
||
exec_set_section_address (bfd_get_filename (objfile->obfd), idx,
|
||
obj_section_addr (s));
|
||
}
|
||
+}
|
||
+
|
||
+/* Relocate OBJFILE to NEW_OFFSETS. There should be OBJFILE->NUM_SECTIONS
|
||
+ entries in new_offsets. Process also OBJFILE's SEPARATE_DEBUG_OBJFILE.
|
||
+
|
||
+ The number and ordering of sections does differ between the two objfiles.
|
||
+ Only their names match. Also the file offsets will differ (objfile being
|
||
+ possibly prelinked but separate_debug_objfile is probably not prelinked) but
|
||
+ the in-memory absolute address as specified by NEW_OFFSETS must match both
|
||
+ files. */
|
||
+
|
||
+void
|
||
+objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
|
||
+{
|
||
+ objfile_relocate1 (objfile, new_offsets);
|
||
+
|
||
+ if (objfile->separate_debug_objfile != NULL)
|
||
+ {
|
||
+ struct objfile *debug_objfile = objfile->separate_debug_objfile;
|
||
+ struct section_addr_info *objfile_addrs;
|
||
+ struct section_offsets *new_debug_offsets;
|
||
+ int new_debug_num_sections;
|
||
+ struct cleanup *my_cleanups;
|
||
+
|
||
+ objfile_addrs = build_section_addr_info_from_objfile (objfile);
|
||
+ my_cleanups = make_cleanup (xfree, objfile_addrs);
|
||
+
|
||
+ /* Here OBJFILE_ADDRS contain the correct absolute addresses, the
|
||
+ relative ones must be already created according to debug_objfile. */
|
||
+
|
||
+ addr_info_make_relative (objfile_addrs, debug_objfile->obfd);
|
||
+
|
||
+ gdb_assert (debug_objfile->num_sections
|
||
+ == bfd_count_sections (debug_objfile->obfd));
|
||
+ new_debug_offsets = alloca (SIZEOF_N_SECTION_OFFSETS
|
||
+ (debug_objfile->num_sections));
|
||
+ relative_addr_info_to_section_offsets (new_debug_offsets,
|
||
+ debug_objfile->num_sections,
|
||
+ objfile_addrs);
|
||
+ do_cleanups (my_cleanups);
|
||
+
|
||
+ objfile_relocate1 (debug_objfile, new_debug_offsets);
|
||
+ }
|
||
|
||
/* Relocate breakpoints as necessary, after things are relocated. */
|
||
breakpoint_re_set ();
|
||
diff --git a/gdb/procfs.c b/gdb/procfs.c
|
||
index b569bac..15829c2 100644
|
||
--- a/gdb/procfs.c
|
||
+++ b/gdb/procfs.c
|
||
@@ -4376,7 +4376,7 @@ procfs_xfer_partial (struct target_ops *ops, enum target_object object,
|
||
|
||
#ifdef NEW_PROC_API
|
||
case TARGET_OBJECT_AUXV:
|
||
- return procfs_xfer_auxv (ops, object, annex, readbuf, writebuf,
|
||
+ return memory_xfer_auxv (ops, object, annex, readbuf, writebuf,
|
||
offset, len);
|
||
#endif
|
||
|
||
diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
|
||
index 9428d92..3591168 100644
|
||
--- a/gdb/solib-darwin.c
|
||
+++ b/gdb/solib-darwin.c
|
||
@@ -277,7 +277,7 @@ darwin_special_symbol_handling (void)
|
||
|
||
/* Shared library startup support. See documentation in solib-svr4.c */
|
||
static void
|
||
-darwin_solib_create_inferior_hook (void)
|
||
+darwin_solib_create_inferior_hook (int from_tty)
|
||
{
|
||
struct minimal_symbol *msymbol;
|
||
char **bkpt_namep;
|
||
diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c
|
||
index b8d5528..002c589 100644
|
||
--- a/gdb/solib-frv.c
|
||
+++ b/gdb/solib-frv.c
|
||
@@ -971,7 +971,7 @@ frv_relocate_main_executable (void)
|
||
*/
|
||
|
||
static void
|
||
-frv_solib_create_inferior_hook (void)
|
||
+frv_solib_create_inferior_hook (int from_tty)
|
||
{
|
||
/* Relocate main executable. */
|
||
frv_relocate_main_executable ();
|
||
diff --git a/gdb/solib-irix.c b/gdb/solib-irix.c
|
||
index a0c1cd2..f94f7dc 100644
|
||
--- a/gdb/solib-irix.c
|
||
+++ b/gdb/solib-irix.c
|
||
@@ -386,7 +386,7 @@ enable_break (void)
|
||
|
||
SYNOPSIS
|
||
|
||
- void solib_create_inferior_hook ()
|
||
+ void solib_create_inferior_hook (int from_tty)
|
||
|
||
DESCRIPTION
|
||
|
||
@@ -431,7 +431,7 @@ enable_break (void)
|
||
*/
|
||
|
||
static void
|
||
-irix_solib_create_inferior_hook (void)
|
||
+irix_solib_create_inferior_hook (int from_tty)
|
||
{
|
||
struct inferior *inf;
|
||
struct thread_info *tp;
|
||
diff --git a/gdb/solib-null.c b/gdb/solib-null.c
|
||
index b39ccdb..87f7848 100644
|
||
--- a/gdb/solib-null.c
|
||
+++ b/gdb/solib-null.c
|
||
@@ -32,7 +32,7 @@ null_special_symbol_handling (void)
|
||
}
|
||
|
||
static void
|
||
-null_solib_create_inferior_hook (void)
|
||
+null_solib_create_inferior_hook (int from_tty)
|
||
{
|
||
}
|
||
|
||
diff --git a/gdb/solib-osf.c b/gdb/solib-osf.c
|
||
index c295335..0acc7fb 100644
|
||
--- a/gdb/solib-osf.c
|
||
+++ b/gdb/solib-osf.c
|
||
@@ -306,7 +306,7 @@ osf_clear_solib (void)
|
||
Also, what if child has exit()ed? Must exit loop somehow. */
|
||
|
||
static void
|
||
-osf_solib_create_inferior_hook (void)
|
||
+osf_solib_create_inferior_hook (int from_tty)
|
||
{
|
||
struct inferior *inf;
|
||
struct thread_info *tp;
|
||
diff --git a/gdb/solib-pa64.c b/gdb/solib-pa64.c
|
||
index 637fc1a..16d4010 100644
|
||
--- a/gdb/solib-pa64.c
|
||
+++ b/gdb/solib-pa64.c
|
||
@@ -329,7 +329,7 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
|
||
with shared libraries mapped shareable. */
|
||
|
||
static void
|
||
-pa64_solib_create_inferior_hook (void)
|
||
+pa64_solib_create_inferior_hook (int from_tty)
|
||
{
|
||
struct minimal_symbol *msymbol;
|
||
unsigned int dld_flags, status;
|
||
diff --git a/gdb/solib-som.c b/gdb/solib-som.c
|
||
index 16f00a3..37ac8cd 100644
|
||
--- a/gdb/solib-som.c
|
||
+++ b/gdb/solib-som.c
|
||
@@ -182,7 +182,7 @@ struct {
|
||
means running until the "_start" is called. */
|
||
|
||
static void
|
||
-som_solib_create_inferior_hook (void)
|
||
+som_solib_create_inferior_hook (int from_tty)
|
||
{
|
||
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
|
||
struct minimal_symbol *msymbol;
|
||
diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c
|
||
index 9f06fa9..45e7e69 100644
|
||
--- a/gdb/solib-spu.c
|
||
+++ b/gdb/solib-spu.c
|
||
@@ -52,25 +52,19 @@
|
||
static void
|
||
spu_relocate_main_executable (int spufs_fd)
|
||
{
|
||
- struct objfile *objfile;
|
||
- struct cleanup *old_chain;
|
||
struct section_offsets *new_offsets;
|
||
int i;
|
||
|
||
- for (objfile = symfile_objfile;
|
||
- objfile;
|
||
- objfile = objfile->separate_debug_objfile)
|
||
- {
|
||
- new_offsets = xcalloc (objfile->num_sections,
|
||
- sizeof (struct section_offsets));
|
||
- old_chain = make_cleanup (xfree, new_offsets);
|
||
+ if (symfile_objfile == NULL)
|
||
+ return;
|
||
|
||
- for (i = 0; i < objfile->num_sections; i++)
|
||
- new_offsets->offsets[i] = SPUADDR (spufs_fd, 0);
|
||
+ new_offsets = alloca (symfile_objfile->num_sections
|
||
+ * sizeof (struct section_offsets));
|
||
|
||
- objfile_relocate (objfile, new_offsets);
|
||
- do_cleanups (old_chain);
|
||
- }
|
||
+ for (i = 0; i < symfile_objfile->num_sections; i++)
|
||
+ new_offsets->offsets[i] = SPUADDR (spufs_fd, 0);
|
||
+
|
||
+ objfile_relocate (symfile_objfile, new_offsets);
|
||
}
|
||
|
||
/* When running a stand-alone SPE executable, we may need to skip one more
|
||
@@ -370,7 +364,7 @@ spu_enable_break (struct objfile *objfile)
|
||
|
||
/* Create inferior hook. */
|
||
static void
|
||
-spu_solib_create_inferior_hook (void)
|
||
+spu_solib_create_inferior_hook (int from_tty)
|
||
{
|
||
/* Remove all previously installed solib breakpoints. Both the SVR4
|
||
code and us will re-install all required breakpoints. */
|
||
@@ -401,7 +395,7 @@ spu_solib_create_inferior_hook (void)
|
||
}
|
||
|
||
/* Call SVR4 hook -- this will re-insert the SVR4 solib breakpoints. */
|
||
- svr4_so_ops.solib_create_inferior_hook ();
|
||
+ svr4_so_ops.solib_create_inferior_hook (from_tty);
|
||
|
||
/* If the inferior is statically linked against libspe, we need to install
|
||
our own solib breakpoint right now. Otherwise, it will be installed by
|
||
diff --git a/gdb/solib-sunos.c b/gdb/solib-sunos.c
|
||
index 9b2a470..b2a147d 100644
|
||
--- a/gdb/solib-sunos.c
|
||
+++ b/gdb/solib-sunos.c
|
||
@@ -740,7 +740,7 @@ sunos_special_symbol_handling (void)
|
||
*/
|
||
|
||
static void
|
||
-sunos_solib_create_inferior_hook (void)
|
||
+sunos_solib_create_inferior_hook (int from_tty)
|
||
{
|
||
struct thread_info *tp;
|
||
struct inferior *inf;
|
||
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
|
||
index 68aadc0..efbe717 100644
|
||
--- a/gdb/solib-svr4.c
|
||
+++ b/gdb/solib-svr4.c
|
||
@@ -50,6 +50,7 @@
|
||
|
||
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
|
||
static int svr4_have_link_map_offsets (void);
|
||
+static void svr4_relocate_main_executable (void);
|
||
|
||
/* Link map info to include in an allocated so_list entry */
|
||
|
||
@@ -599,11 +600,12 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr)
|
||
{
|
||
int arch_size, step, sect_size;
|
||
long dyn_tag;
|
||
- CORE_ADDR dyn_ptr, dyn_addr;
|
||
+ CORE_ADDR dyn_ptr;
|
||
gdb_byte *bufend, *bufstart, *buf;
|
||
Elf32_External_Dyn *x_dynp_32;
|
||
Elf64_External_Dyn *x_dynp_64;
|
||
struct bfd_section *sect;
|
||
+ struct target_section *target_section;
|
||
|
||
if (abfd == NULL)
|
||
return 0;
|
||
@@ -619,7 +621,13 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr)
|
||
sect = bfd_get_section_by_name (abfd, ".dynamic");
|
||
if (sect == NULL)
|
||
return 0;
|
||
- dyn_addr = bfd_section_vma (abfd, sect);
|
||
+
|
||
+ for (target_section = target_get_section_table (&exec_ops)->sections;
|
||
+ target_section < target_get_section_table (&exec_ops)->sections_end;
|
||
+ target_section++)
|
||
+ if (sect == target_section->the_bfd_section)
|
||
+ break;
|
||
+ gdb_assert (target_section < target_get_section_table (&exec_ops)->sections_end);
|
||
|
||
/* Read in .dynamic from the BFD. We will get the actual value
|
||
from memory later. */
|
||
@@ -661,7 +669,7 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr)
|
||
CORE_ADDR ptr_addr;
|
||
|
||
ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr;
|
||
- ptr_addr = dyn_addr + (buf - bufstart) + arch_size / 8;
|
||
+ ptr_addr = target_section->addr + (buf - bufstart) + arch_size / 8;
|
||
if (target_read_memory (ptr_addr, ptr_buf, arch_size / 8) == 0)
|
||
dyn_ptr = extract_typed_address (ptr_buf, ptr_type);
|
||
*ptr = dyn_ptr;
|
||
@@ -1258,7 +1266,7 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ)
|
||
*/
|
||
|
||
static int
|
||
-enable_break (struct svr4_info *info)
|
||
+enable_break (struct svr4_info *info, int from_tty)
|
||
{
|
||
struct minimal_symbol *msymbol;
|
||
char **bkpt_namep;
|
||
@@ -1279,7 +1287,7 @@ enable_break (struct svr4_info *info)
|
||
mean r_brk has already been relocated. Assume the dynamic linker
|
||
is the object containing r_brk. */
|
||
|
||
- solib_add (NULL, 0, ¤t_target, auto_solib_add);
|
||
+ solib_add (NULL, from_tty, ¤t_target, auto_solib_add);
|
||
sym_addr = 0;
|
||
if (info->debug_base && solib_svr4_r_map (info) != 0)
|
||
sym_addr = solib_svr4_r_brk (info);
|
||
@@ -1339,6 +1347,11 @@ enable_break (struct svr4_info *info)
|
||
bfd *tmp_bfd = NULL;
|
||
struct target_ops *tmp_bfd_target;
|
||
volatile struct gdb_exception ex;
|
||
+ int addr_bit = gdbarch_addr_bit (target_gdbarch);
|
||
+ CORE_ADDR mask = CORE_ADDR_MAX;
|
||
+
|
||
+ if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
|
||
+ mask = ((CORE_ADDR) 1 << addr_bit) - 1;
|
||
|
||
sym_addr = 0;
|
||
|
||
@@ -1404,7 +1417,7 @@ enable_break (struct svr4_info *info)
|
||
info->debug_loader_name = xstrdup (interp_name);
|
||
info->debug_loader_offset_p = 1;
|
||
info->debug_loader_offset = load_addr;
|
||
- solib_add (NULL, 0, ¤t_target, auto_solib_add);
|
||
+ solib_add (NULL, from_tty, ¤t_target, auto_solib_add);
|
||
}
|
||
|
||
/* Record the relocated start and end address of the dynamic linker
|
||
@@ -1414,16 +1427,20 @@ enable_break (struct svr4_info *info)
|
||
{
|
||
interp_text_sect_low =
|
||
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
|
||
+ interp_text_sect_low &= mask;
|
||
interp_text_sect_high =
|
||
interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
|
||
+ interp_text_sect_high &= mask;
|
||
}
|
||
interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
|
||
if (interp_sect)
|
||
{
|
||
interp_plt_sect_low =
|
||
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
|
||
+ interp_text_sect_low &= mask;
|
||
interp_plt_sect_high =
|
||
interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
|
||
+ interp_text_sect_high &= mask;
|
||
}
|
||
|
||
/* Now try to set a breakpoint in the dynamic linker. */
|
||
@@ -1448,7 +1465,7 @@ enable_break (struct svr4_info *info)
|
||
|
||
if (sym_addr != 0)
|
||
{
|
||
- create_solib_event_breakpoint (target_gdbarch, load_addr + sym_addr);
|
||
+ create_solib_event_breakpoint (target_gdbarch, (load_addr + sym_addr) & mask);
|
||
xfree (interp_name);
|
||
return 1;
|
||
}
|
||
@@ -1517,113 +1534,131 @@ enable_break (struct svr4_info *info)
|
||
static void
|
||
svr4_special_symbol_handling (void)
|
||
{
|
||
+ svr4_relocate_main_executable ();
|
||
}
|
||
|
||
-/* Relocate the main executable. This function should be called upon
|
||
- stopping the inferior process at the entry point to the program.
|
||
- The entry point from BFD is compared to the PC and if they are
|
||
- different, the main executable is relocated by the proper amount.
|
||
+/* Decide if the objfile needs to be relocated. As indicated above,
|
||
+ we will only be here when execution is stopped at the beginning
|
||
+ of the program. Relocation is necessary if the address at which
|
||
+ we are presently stopped differs from the start address stored in
|
||
+ the executable AND there's no interpreter section. The condition
|
||
+ regarding the interpreter section is very important because if
|
||
+ there *is* an interpreter section, execution will begin there
|
||
+ instead. When there is an interpreter section, the start address
|
||
+ is (presumably) used by the interpreter at some point to start
|
||
+ execution of the program.
|
||
+
|
||
+ If there is an interpreter, it is normal for it to be set to an
|
||
+ arbitrary address at the outset. The job of finding it is
|
||
+ handled in enable_break().
|
||
+
|
||
+ So, to summarize, relocations are necessary when there is no
|
||
+ interpreter section and the start address obtained from the
|
||
+ executable is different from the address at which GDB is
|
||
+ currently stopped.
|
||
|
||
- As written it will only attempt to relocate executables which
|
||
- lack interpreter sections. It seems likely that only dynamic
|
||
- linker executables will get relocated, though it should work
|
||
- properly for a position-independent static executable as well. */
|
||
+ [ The astute reader will note that we also test to make sure that
|
||
+ the executable in question has the DYNAMIC flag set. It is my
|
||
+ opinion that this test is unnecessary (undesirable even). It
|
||
+ was added to avoid inadvertent relocation of an executable
|
||
+ whose e_type member in the ELF header is not ET_DYN. There may
|
||
+ be a time in the future when it is desirable to do relocations
|
||
+ on other types of files as well in which case this condition
|
||
+ should either be removed or modified to accomodate the new file
|
||
+ type. (E.g, an ET_EXEC executable which has been built to be
|
||
+ position-independent could safely be relocated by the OS if
|
||
+ desired. It is true that this violates the ABI, but the ABI
|
||
+ has been known to be bent from time to time.) - Kevin, Nov 2000. ]
|
||
+ */
|
||
|
||
-static void
|
||
-svr4_relocate_main_executable (void)
|
||
+static CORE_ADDR
|
||
+svr4_static_exec_displacement (void)
|
||
{
|
||
asection *interp_sect;
|
||
struct regcache *regcache
|
||
= get_thread_arch_regcache (inferior_ptid, target_gdbarch);
|
||
CORE_ADDR pc = regcache_read_pc (regcache);
|
||
|
||
- /* Decide if the objfile needs to be relocated. As indicated above,
|
||
- we will only be here when execution is stopped at the beginning
|
||
- of the program. Relocation is necessary if the address at which
|
||
- we are presently stopped differs from the start address stored in
|
||
- the executable AND there's no interpreter section. The condition
|
||
- regarding the interpreter section is very important because if
|
||
- there *is* an interpreter section, execution will begin there
|
||
- instead. When there is an interpreter section, the start address
|
||
- is (presumably) used by the interpreter at some point to start
|
||
- execution of the program.
|
||
-
|
||
- If there is an interpreter, it is normal for it to be set to an
|
||
- arbitrary address at the outset. The job of finding it is
|
||
- handled in enable_break().
|
||
-
|
||
- So, to summarize, relocations are necessary when there is no
|
||
- interpreter section and the start address obtained from the
|
||
- executable is different from the address at which GDB is
|
||
- currently stopped.
|
||
-
|
||
- [ The astute reader will note that we also test to make sure that
|
||
- the executable in question has the DYNAMIC flag set. It is my
|
||
- opinion that this test is unnecessary (undesirable even). It
|
||
- was added to avoid inadvertent relocation of an executable
|
||
- whose e_type member in the ELF header is not ET_DYN. There may
|
||
- be a time in the future when it is desirable to do relocations
|
||
- on other types of files as well in which case this condition
|
||
- should either be removed or modified to accomodate the new file
|
||
- type. (E.g, an ET_EXEC executable which has been built to be
|
||
- position-independent could safely be relocated by the OS if
|
||
- desired. It is true that this violates the ABI, but the ABI
|
||
- has been known to be bent from time to time.) - Kevin, Nov 2000. ]
|
||
- */
|
||
-
|
||
interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
|
||
if (interp_sect == NULL
|
||
&& (bfd_get_file_flags (exec_bfd) & DYNAMIC) != 0
|
||
&& (exec_entry_point (exec_bfd, &exec_ops) != pc))
|
||
+ return pc - exec_entry_point (exec_bfd, &exec_ops);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* We relocate all of the sections by the same amount. This
|
||
+ behavior is mandated by recent editions of the System V ABI.
|
||
+ According to the System V Application Binary Interface,
|
||
+ Edition 4.1, page 5-5:
|
||
+
|
||
+ ... Though the system chooses virtual addresses for
|
||
+ individual processes, it maintains the segments' relative
|
||
+ positions. Because position-independent code uses relative
|
||
+ addressesing between segments, the difference between
|
||
+ virtual addresses in memory must match the difference
|
||
+ between virtual addresses in the file. The difference
|
||
+ between the virtual address of any segment in memory and
|
||
+ the corresponding virtual address in the file is thus a
|
||
+ single constant value for any one executable or shared
|
||
+ object in a given process. This difference is the base
|
||
+ address. One use of the base address is to relocate the
|
||
+ memory image of the program during dynamic linking.
|
||
+
|
||
+ The same language also appears in Edition 4.0 of the System V
|
||
+ ABI and is left unspecified in some of the earlier editions. */
|
||
+
|
||
+static CORE_ADDR
|
||
+svr4_exec_displacement (void)
|
||
+{
|
||
+ int found;
|
||
+ CORE_ADDR entry_point;
|
||
+
|
||
+ if (exec_bfd == NULL)
|
||
+ return 0;
|
||
+
|
||
+ if (target_auxv_search (¤t_target, AT_ENTRY, &entry_point) == 1)
|
||
+ return entry_point - exec_entry_point (exec_bfd, ¤t_target);
|
||
+
|
||
+ return svr4_static_exec_displacement ();
|
||
+}
|
||
+
|
||
+/* Relocate the main executable. This function should be called upon
|
||
+ stopping the inferior process at the entry point to the program.
|
||
+ The entry point from BFD is compared to the AT_ENTRY of AUXV and if they are
|
||
+ different, the main executable is relocated by the proper amount. */
|
||
+
|
||
+static void
|
||
+svr4_relocate_main_executable (void)
|
||
+{
|
||
+ CORE_ADDR displacement = svr4_exec_displacement ();
|
||
+
|
||
+ /* Even if DISPLACEMENT is 0 still try to relocate it as this is a new
|
||
+ difference of in-memory vs. in-file addresses and we could already
|
||
+ relocate the executable at this function to improper address before. */
|
||
+
|
||
+ if (symfile_objfile)
|
||
{
|
||
- struct cleanup *old_chain;
|
||
struct section_offsets *new_offsets;
|
||
- int i, changed;
|
||
- CORE_ADDR displacement;
|
||
-
|
||
- /* It is necessary to relocate the objfile. The amount to
|
||
- relocate by is simply the address at which we are stopped
|
||
- minus the starting address from the executable.
|
||
-
|
||
- We relocate all of the sections by the same amount. This
|
||
- behavior is mandated by recent editions of the System V ABI.
|
||
- According to the System V Application Binary Interface,
|
||
- Edition 4.1, page 5-5:
|
||
-
|
||
- ... Though the system chooses virtual addresses for
|
||
- individual processes, it maintains the segments' relative
|
||
- positions. Because position-independent code uses relative
|
||
- addressesing between segments, the difference between
|
||
- virtual addresses in memory must match the difference
|
||
- between virtual addresses in the file. The difference
|
||
- between the virtual address of any segment in memory and
|
||
- the corresponding virtual address in the file is thus a
|
||
- single constant value for any one executable or shared
|
||
- object in a given process. This difference is the base
|
||
- address. One use of the base address is to relocate the
|
||
- memory image of the program during dynamic linking.
|
||
-
|
||
- The same language also appears in Edition 4.0 of the System V
|
||
- ABI and is left unspecified in some of the earlier editions. */
|
||
-
|
||
- displacement = pc - exec_entry_point (exec_bfd, &exec_ops);
|
||
- changed = 0;
|
||
-
|
||
- new_offsets = xcalloc (symfile_objfile->num_sections,
|
||
- sizeof (struct section_offsets));
|
||
- old_chain = make_cleanup (xfree, new_offsets);
|
||
+ int i;
|
||
+
|
||
+ new_offsets = alloca (symfile_objfile->num_sections
|
||
+ * sizeof (*new_offsets));
|
||
|
||
for (i = 0; i < symfile_objfile->num_sections; i++)
|
||
- {
|
||
- if (displacement != ANOFFSET (symfile_objfile->section_offsets, i))
|
||
- changed = 1;
|
||
- new_offsets->offsets[i] = displacement;
|
||
- }
|
||
+ new_offsets->offsets[i] = displacement;
|
||
|
||
- if (changed)
|
||
- objfile_relocate (symfile_objfile, new_offsets);
|
||
+ objfile_relocate (symfile_objfile, new_offsets);
|
||
+ }
|
||
+ else if (exec_bfd)
|
||
+ {
|
||
+ asection *asect;
|
||
|
||
- do_cleanups (old_chain);
|
||
+ for (asect = exec_bfd->sections; asect != NULL; asect = asect->next)
|
||
+ exec_set_section_address (bfd_get_filename (exec_bfd), asect->index,
|
||
+ bfd_section_vma (exec_bfd, asect)
|
||
+ + displacement);
|
||
}
|
||
}
|
||
|
||
@@ -1635,7 +1670,7 @@ svr4_relocate_main_executable (void)
|
||
|
||
SYNOPSIS
|
||
|
||
- void svr4_solib_create_inferior_hook ()
|
||
+ void svr4_solib_create_inferior_hook (int from_tty)
|
||
|
||
DESCRIPTION
|
||
|
||
@@ -1680,7 +1715,7 @@ svr4_relocate_main_executable (void)
|
||
*/
|
||
|
||
static void
|
||
-svr4_solib_create_inferior_hook (void)
|
||
+svr4_solib_create_inferior_hook (int from_tty)
|
||
{
|
||
struct inferior *inf;
|
||
struct thread_info *tp;
|
||
@@ -1689,12 +1724,13 @@ svr4_solib_create_inferior_hook (void)
|
||
info = get_svr4_info (PIDGET (inferior_ptid));
|
||
|
||
/* Relocate the main executable if necessary. */
|
||
- svr4_relocate_main_executable ();
|
||
+ if (current_inferior ()->attach_flag == 0)
|
||
+ svr4_relocate_main_executable ();
|
||
|
||
if (!svr4_have_link_map_offsets ())
|
||
return;
|
||
|
||
- if (!enable_break (info))
|
||
+ if (!enable_break (info, from_tty))
|
||
return;
|
||
|
||
#if defined(_SCO_DS)
|
||
@@ -1910,8 +1946,19 @@ elf_lookup_lib_symbol (const struct objfile *objfile,
|
||
const char *name,
|
||
const domain_enum domain)
|
||
{
|
||
- if (objfile->obfd == NULL
|
||
- || scan_dyntag (DT_SYMBOLIC, objfile->obfd, NULL) != 1)
|
||
+ bfd *abfd;
|
||
+
|
||
+ if (objfile == symfile_objfile)
|
||
+ abfd = exec_bfd;
|
||
+ else
|
||
+ {
|
||
+ /* OBJFILE should have been passed as the non-debug one. */
|
||
+ gdb_assert (objfile->separate_debug_objfile_backlink == NULL);
|
||
+
|
||
+ abfd = objfile->obfd;
|
||
+ }
|
||
+
|
||
+ if (abfd == NULL || scan_dyntag (DT_SYMBOLIC, abfd, NULL) != 1)
|
||
return NULL;
|
||
|
||
return lookup_global_symbol_from_objfile (objfile, name, domain);
|
||
diff --git a/gdb/solib-target.c b/gdb/solib-target.c
|
||
index 07415e4..d160a70 100644
|
||
--- a/gdb/solib-target.c
|
||
+++ b/gdb/solib-target.c
|
||
@@ -306,7 +306,7 @@ solib_target_special_symbol_handling (void)
|
||
}
|
||
|
||
static void
|
||
-solib_target_solib_create_inferior_hook (void)
|
||
+solib_target_solib_create_inferior_hook (int from_tty)
|
||
{
|
||
/* Nothing needed. */
|
||
}
|
||
diff --git a/gdb/solib.c b/gdb/solib.c
|
||
index 3574e62..7ea3663 100644
|
||
--- a/gdb/solib.c
|
||
+++ b/gdb/solib.c
|
||
@@ -998,7 +998,7 @@ clear_solib (void)
|
||
|
||
SYNOPSIS
|
||
|
||
- void solib_create_inferior_hook ()
|
||
+ void solib_create_inferior_hook (int from_tty)
|
||
|
||
DESCRIPTION
|
||
|
||
@@ -1008,10 +1008,10 @@ clear_solib (void)
|
||
SOLIB_CREATE_INFERIOR_HOOK. */
|
||
|
||
void
|
||
-solib_create_inferior_hook (void)
|
||
+solib_create_inferior_hook (int from_tty)
|
||
{
|
||
struct target_so_ops *ops = solib_ops (target_gdbarch);
|
||
- ops->solib_create_inferior_hook();
|
||
+ ops->solib_create_inferior_hook (from_tty);
|
||
}
|
||
|
||
/* GLOBAL FUNCTION
|
||
@@ -1087,7 +1087,6 @@ reload_shared_libraries (char *ignored, int from_tty,
|
||
struct cmd_list_element *e)
|
||
{
|
||
no_shared_libraries (NULL, from_tty);
|
||
- solib_add (NULL, from_tty, NULL, auto_solib_add);
|
||
/* Creating inferior hooks here has two purposes. First, if we reload
|
||
shared libraries then the address of solib breakpoint we've computed
|
||
previously might be no longer valid. For example, if we forgot to set
|
||
@@ -1102,9 +1101,19 @@ reload_shared_libraries (char *ignored, int from_tty,
|
||
#ifdef SOLIB_CREATE_INFERIOR_HOOK
|
||
SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
|
||
#else
|
||
- solib_create_inferior_hook ();
|
||
+ solib_create_inferior_hook (from_tty);
|
||
#endif
|
||
}
|
||
+
|
||
+ /* Sometimes the platform-specific hook loads initial shared
|
||
+ libraries, and sometimes it doesn't. If it doesn't FROM_TTY will be
|
||
+ incorrectly 0 but such solib targets should be fixed anyway. If we
|
||
+ made all the inferior hook methods consistent, this call could be
|
||
+ removed. Call it only after the solib target has been initialized by
|
||
+ solib_create_inferior_hook. */
|
||
+
|
||
+ solib_add (NULL, 0, NULL, auto_solib_add);
|
||
+
|
||
/* We have unloaded and then reloaded debug info for all shared libraries.
|
||
However, frames may still reference them, for example a frame's
|
||
unwinder might still point of DWARF FDE structures that are now freed.
|
||
diff --git a/gdb/solib.h b/gdb/solib.h
|
||
index ccc5b63..abe5e19 100644
|
||
--- a/gdb/solib.h
|
||
+++ b/gdb/solib.h
|
||
@@ -41,7 +41,7 @@ extern int solib_read_symbols (struct so_list *, int);
|
||
addresses to which they are linked, and sufficient information to
|
||
read in their symbols at a later time. */
|
||
|
||
-extern void solib_create_inferior_hook (void);
|
||
+extern void solib_create_inferior_hook (int from_tty);
|
||
|
||
/* If ADDR lies in a shared library, return its name. */
|
||
|
||
diff --git a/gdb/solist.h b/gdb/solist.h
|
||
index 005e8f7..9724fe7 100644
|
||
--- a/gdb/solist.h
|
||
+++ b/gdb/solist.h
|
||
@@ -87,7 +87,7 @@ struct target_so_ops
|
||
void (*clear_solib) (void);
|
||
|
||
/* Target dependent code to run after child process fork. */
|
||
- void (*solib_create_inferior_hook) (void);
|
||
+ void (*solib_create_inferior_hook) (int from_tty);
|
||
|
||
/* Do additional symbol handling, lookup, etc. after symbols
|
||
for a shared object have been loaded. */
|
||
diff --git a/gdb/symfile.c b/gdb/symfile.c
|
||
index c31b72a..6d7fa10 100644
|
||
--- a/gdb/symfile.c
|
||
+++ b/gdb/symfile.c
|
||
@@ -536,40 +536,151 @@ place_section (bfd *abfd, asection *sect, void *obj)
|
||
arg->lowest = start_addr + bfd_get_section_size (sect);
|
||
}
|
||
|
||
-/* Parse the user's idea of an offset for dynamic linking, into our idea
|
||
- of how to represent it for fast symbol reading. This is the default
|
||
- version of the sym_fns.sym_offsets function for symbol readers that
|
||
- don't need to do anything special. It allocates a section_offsets table
|
||
- for the objectfile OBJFILE and stuffs ADDR into all of the offsets. */
|
||
+/* Build (allocate and populate) struct section_addr_info with absolute
|
||
+ addresses from OBJFILE->OBFD and OBJFILE->SECTION_OFFSETS. */
|
||
+
|
||
+struct section_addr_info *
|
||
+build_section_addr_info_from_objfile (struct objfile *objfile)
|
||
+{
|
||
+ struct target_section *sections = NULL, *sections_end;
|
||
+ struct target_section *p;
|
||
+ int addr_bit = gdbarch_addr_bit (objfile->gdbarch);
|
||
+ CORE_ADDR mask = CORE_ADDR_MAX;
|
||
+ struct section_addr_info *retval;
|
||
+ struct cleanup *my_cleanups;
|
||
+
|
||
+ if (build_section_table (objfile->obfd, §ions, §ions_end))
|
||
+ error (_("Can't find the file sections in `%s': %s"),
|
||
+ bfd_get_filename (objfile->obfd), bfd_errmsg (bfd_get_error ()));
|
||
+ my_cleanups = make_cleanup (xfree, sections);
|
||
+
|
||
+ if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
|
||
+ mask = ((CORE_ADDR) 1 << addr_bit) - 1;
|
||
+
|
||
+ for (p = sections; p < sections_end; p++)
|
||
+ {
|
||
+ CORE_ADDR baseaddr;
|
||
+
|
||
+ gdb_assert (p->the_bfd_section->index < objfile->num_sections);
|
||
+ baseaddr = ANOFFSET (objfile->section_offsets,
|
||
+ p->the_bfd_section->index);
|
||
+
|
||
+ p->addr = (p->addr + baseaddr) & mask;
|
||
+ p->endaddr = (p->endaddr + baseaddr) & mask;
|
||
+ }
|
||
+
|
||
+ retval = build_section_addr_info_from_section_table (sections, sections_end);
|
||
+
|
||
+ do_cleanups (my_cleanups);
|
||
+
|
||
+ return retval;
|
||
+}
|
||
+
|
||
+/* Store struct section_addr_info as prepared (made relative and with SECTINDEX
|
||
+ filled-in) by addr_info_make_relative into SECTION_OFFSETS of NUM_SECTIONS
|
||
+ entries. */
|
||
|
||
void
|
||
-default_symfile_offsets (struct objfile *objfile,
|
||
- struct section_addr_info *addrs)
|
||
+relative_addr_info_to_section_offsets (struct section_offsets *section_offsets,
|
||
+ int num_sections,
|
||
+ struct section_addr_info *addrs)
|
||
{
|
||
int i;
|
||
|
||
- objfile->num_sections = bfd_count_sections (objfile->obfd);
|
||
- objfile->section_offsets = (struct section_offsets *)
|
||
- obstack_alloc (&objfile->objfile_obstack,
|
||
- SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
|
||
- memset (objfile->section_offsets, 0,
|
||
- SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
|
||
+ memset (section_offsets, 0, SIZEOF_N_SECTION_OFFSETS (num_sections));
|
||
|
||
- /* Now calculate offsets for section that were specified by the
|
||
- caller. */
|
||
+ /* Now calculate offsets for section that were specified by the caller. */
|
||
for (i = 0; i < addrs->num_sections && addrs->other[i].name; i++)
|
||
{
|
||
- struct other_sections *osp ;
|
||
+ struct other_sections *osp;
|
||
|
||
- osp = &addrs->other[i] ;
|
||
+ osp = &addrs->other[i];
|
||
if (osp->addr == 0)
|
||
continue;
|
||
|
||
/* Record all sections in offsets */
|
||
/* The section_offsets in the objfile are here filled in using
|
||
the BFD index. */
|
||
- (objfile->section_offsets)->offsets[osp->sectindex] = osp->addr;
|
||
+ section_offsets->offsets[osp->sectindex] = osp->addr;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Relativize absolute addresses in ADDRS into offsets based on ABFD. Fill-in
|
||
+ also SECTINDEXes there. */
|
||
+
|
||
+void
|
||
+addr_info_make_relative (struct section_addr_info *addrs, bfd *abfd)
|
||
+{
|
||
+ asection *lower_sect;
|
||
+ asection *sect;
|
||
+ CORE_ADDR lower_offset;
|
||
+ int i;
|
||
+
|
||
+ /* Find lowest loadable section to be used as starting point for
|
||
+ continguous sections. FIXME!! won't work without call to find
|
||
+ .text first, but this assumes text is lowest section. */
|
||
+ lower_sect = bfd_get_section_by_name (abfd, ".text");
|
||
+ if (lower_sect == NULL)
|
||
+ bfd_map_over_sections (abfd, find_lowest_section, &lower_sect);
|
||
+ if (lower_sect == NULL)
|
||
+ {
|
||
+ warning (_("no loadable sections found in added symbol-file %s"),
|
||
+ bfd_get_filename (abfd));
|
||
+ lower_offset = 0;
|
||
+ }
|
||
+ else
|
||
+ lower_offset = bfd_section_vma (bfd_get_filename (abfd), lower_sect);
|
||
+
|
||
+ /* Calculate offsets for the loadable sections.
|
||
+ FIXME! Sections must be in order of increasing loadable section
|
||
+ so that contiguous sections can use the lower-offset!!!
|
||
+
|
||
+ Adjust offsets if the segments are not contiguous.
|
||
+ If the section is contiguous, its offset should be set to
|
||
+ the offset of the highest loadable section lower than it
|
||
+ (the loadable section directly below it in memory).
|
||
+ this_offset = lower_offset = lower_addr - lower_orig_addr */
|
||
+
|
||
+ for (i = 0; i < addrs->num_sections && addrs->other[i].name; i++)
|
||
+ {
|
||
+ if (addrs->other[i].addr != 0)
|
||
+ {
|
||
+ sect = bfd_get_section_by_name (abfd, addrs->other[i].name);
|
||
+ if (sect)
|
||
+ {
|
||
+ addrs->other[i].addr -= bfd_section_vma (abfd, sect);
|
||
+ lower_offset = addrs->other[i].addr;
|
||
+ /* This is the index used by BFD. */
|
||
+ addrs->other[i].sectindex = sect->index;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ warning (_("section %s not found in %s"), addrs->other[i].name,
|
||
+ bfd_get_filename (abfd));
|
||
+ addrs->other[i].addr = 0;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ addrs->other[i].addr = lower_offset;
|
||
}
|
||
+}
|
||
+
|
||
+/* Parse the user's idea of an offset for dynamic linking, into our idea
|
||
+ of how to represent it for fast symbol reading. This is the default
|
||
+ version of the sym_fns.sym_offsets function for symbol readers that
|
||
+ don't need to do anything special. It allocates a section_offsets table
|
||
+ for the objectfile OBJFILE and stuffs ADDR into all of the offsets. */
|
||
+
|
||
+void
|
||
+default_symfile_offsets (struct objfile *objfile,
|
||
+ struct section_addr_info *addrs)
|
||
+{
|
||
+ objfile->num_sections = bfd_count_sections (objfile->obfd);
|
||
+ objfile->section_offsets = (struct section_offsets *)
|
||
+ obstack_alloc (&objfile->objfile_obstack,
|
||
+ SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
|
||
+ relative_addr_info_to_section_offsets (objfile->section_offsets,
|
||
+ objfile->num_sections, addrs);
|
||
|
||
/* For relocatable files, all loadable sections will start at zero.
|
||
The zero is meaningless, so try to pick arbitrary addresses such
|
||
@@ -803,65 +914,8 @@ syms_from_objfile (struct objfile *objfile,
|
||
|
||
We no longer warn if the lowest section is not a text segment (as
|
||
happens for the PA64 port. */
|
||
- if (!mainline && addrs && addrs->other[0].name)
|
||
- {
|
||
- asection *lower_sect;
|
||
- asection *sect;
|
||
- CORE_ADDR lower_offset;
|
||
- int i;
|
||
-
|
||
- /* Find lowest loadable section to be used as starting point for
|
||
- continguous sections. FIXME!! won't work without call to find
|
||
- .text first, but this assumes text is lowest section. */
|
||
- lower_sect = bfd_get_section_by_name (objfile->obfd, ".text");
|
||
- if (lower_sect == NULL)
|
||
- bfd_map_over_sections (objfile->obfd, find_lowest_section,
|
||
- &lower_sect);
|
||
- if (lower_sect == NULL)
|
||
- {
|
||
- warning (_("no loadable sections found in added symbol-file %s"),
|
||
- objfile->name);
|
||
- lower_offset = 0;
|
||
- }
|
||
- else
|
||
- lower_offset = bfd_section_vma (objfile->obfd, lower_sect);
|
||
-
|
||
- /* Calculate offsets for the loadable sections.
|
||
- FIXME! Sections must be in order of increasing loadable section
|
||
- so that contiguous sections can use the lower-offset!!!
|
||
-
|
||
- Adjust offsets if the segments are not contiguous.
|
||
- If the section is contiguous, its offset should be set to
|
||
- the offset of the highest loadable section lower than it
|
||
- (the loadable section directly below it in memory).
|
||
- this_offset = lower_offset = lower_addr - lower_orig_addr */
|
||
-
|
||
- for (i = 0; i < addrs->num_sections && addrs->other[i].name; i++)
|
||
- {
|
||
- if (addrs->other[i].addr != 0)
|
||
- {
|
||
- sect = bfd_get_section_by_name (objfile->obfd,
|
||
- addrs->other[i].name);
|
||
- if (sect)
|
||
- {
|
||
- addrs->other[i].addr
|
||
- -= bfd_section_vma (objfile->obfd, sect);
|
||
- lower_offset = addrs->other[i].addr;
|
||
- /* This is the index used by BFD. */
|
||
- addrs->other[i].sectindex = sect->index ;
|
||
- }
|
||
- else
|
||
- {
|
||
- warning (_("section %s not found in %s"),
|
||
- addrs->other[i].name,
|
||
- objfile->name);
|
||
- addrs->other[i].addr = 0;
|
||
- }
|
||
- }
|
||
- else
|
||
- addrs->other[i].addr = lower_offset;
|
||
- }
|
||
- }
|
||
+ if (addrs && addrs->other[0].name)
|
||
+ addr_info_make_relative (addrs, objfile->obfd);
|
||
|
||
/* Initialize symbol reading routines for this objfile, allow complaints to
|
||
appear for this new file, and record how verbose to be, then do the
|
||
@@ -959,7 +1013,6 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd,
|
||
struct objfile *objfile;
|
||
struct partial_symtab *psymtab;
|
||
char *debugfile = NULL;
|
||
- struct section_addr_info *orig_addrs = NULL;
|
||
struct cleanup *my_cleanups;
|
||
const char *name = bfd_get_filename (abfd);
|
||
const int from_tty = add_flags & SYMFILE_VERBOSE;
|
||
@@ -981,12 +1034,6 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd,
|
||
objfile->flags |= OBJF_MAIN;
|
||
discard_cleanups (my_cleanups);
|
||
|
||
- if (addrs)
|
||
- {
|
||
- orig_addrs = copy_section_addr_info (addrs);
|
||
- make_cleanup_free_section_addr_info (orig_addrs);
|
||
- }
|
||
-
|
||
/* We either created a new mapped symbol table, mapped an existing
|
||
symbol table file which has not had initial symbol reading
|
||
performed, or need to read an unmapped symbol table. */
|
||
@@ -1033,18 +1080,17 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd,
|
||
`.gnu_debuglink' may no longer be present with `.note.gnu.build-id'. */
|
||
if (!has_any_debug_symbols (objfile))
|
||
debugfile = find_separate_debug_file (objfile);
|
||
+
|
||
if (debugfile)
|
||
{
|
||
- if (addrs != NULL)
|
||
- {
|
||
- objfile->separate_debug_objfile
|
||
- = symbol_file_add (debugfile, add_flags, orig_addrs, flags);
|
||
- }
|
||
- else
|
||
- {
|
||
- objfile->separate_debug_objfile
|
||
- = symbol_file_add (debugfile, add_flags, NULL, flags);
|
||
- }
|
||
+ struct section_addr_info *objfile_addrs;
|
||
+
|
||
+ objfile_addrs = build_section_addr_info_from_objfile (objfile);
|
||
+ make_cleanup (xfree, objfile_addrs);
|
||
+
|
||
+ objfile->separate_debug_objfile = symbol_file_add (debugfile, add_flags,
|
||
+ objfile_addrs, flags);
|
||
+
|
||
objfile->separate_debug_objfile->separate_debug_objfile_backlink
|
||
= objfile;
|
||
|
||
diff --git a/gdb/symfile.h b/gdb/symfile.h
|
||
index bf9d9e7..bff6bd8 100644
|
||
--- a/gdb/symfile.h
|
||
+++ b/gdb/symfile.h
|
||
@@ -181,6 +181,16 @@ struct sym_fns
|
||
|
||
};
|
||
|
||
+extern struct section_addr_info *
|
||
+ build_section_addr_info_from_objfile (struct objfile *objfile);
|
||
+
|
||
+extern void relative_addr_info_to_section_offsets
|
||
+ (struct section_offsets *section_offsets, int num_sections,
|
||
+ struct section_addr_info *addrs);
|
||
+
|
||
+extern void addr_info_make_relative (struct section_addr_info *addrs,
|
||
+ bfd *abfd);
|
||
+
|
||
/* The default version of sym_fns.sym_offsets for readers that don't
|
||
do anything special. */
|
||
|
||
diff --git a/gdb/symtab.c b/gdb/symtab.c
|
||
index 82e0163..01117e3 100644
|
||
--- a/gdb/symtab.c
|
||
+++ b/gdb/symtab.c
|
||
@@ -1449,7 +1449,12 @@ lookup_objfile_from_block (const struct block *block)
|
||
/* Go through SYMTABS. */
|
||
ALL_SYMTABS (obj, s)
|
||
if (block == BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK))
|
||
- return obj;
|
||
+ {
|
||
+ if (obj->separate_debug_objfile_backlink)
|
||
+ obj = obj->separate_debug_objfile_backlink;
|
||
+
|
||
+ return obj;
|
||
+ }
|
||
|
||
return NULL;
|
||
}
|
||
diff --git a/gdb/testsuite/gdb.base/break-interp-lib.c b/gdb/testsuite/gdb.base/break-interp-lib.c
|
||
new file mode 100644
|
||
index 0000000..9ca943e
|
||
--- /dev/null
|
||
+++ b/gdb/testsuite/gdb.base/break-interp-lib.c
|
||
@@ -0,0 +1,40 @@
|
||
+/* This testcase is part of GDB, the GNU debugger.
|
||
+
|
||
+ Copyright 2009 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/>. */
|
||
+
|
||
+#include <signal.h>
|
||
+#include <unistd.h>
|
||
+#include <assert.h>
|
||
+#include <stdio.h>
|
||
+
|
||
+void
|
||
+libfunc (const char *action)
|
||
+{
|
||
+ assert (action != NULL);
|
||
+
|
||
+ if (strcmp (action, "segv") == 0)
|
||
+ raise (SIGSEGV);
|
||
+
|
||
+ if (strcmp (action, "sleep") == 0)
|
||
+ {
|
||
+ puts ("sleeping");
|
||
+ fflush (stdout);
|
||
+
|
||
+ sleep (60);
|
||
+ }
|
||
+
|
||
+ assert (0);
|
||
+}
|
||
diff --git a/gdb/testsuite/gdb.base/break-interp-main.c b/gdb/testsuite/gdb.base/break-interp-main.c
|
||
new file mode 100644
|
||
index 0000000..e12ec2b
|
||
--- /dev/null
|
||
+++ b/gdb/testsuite/gdb.base/break-interp-main.c
|
||
@@ -0,0 +1,30 @@
|
||
+/* This testcase is part of GDB, the GNU debugger.
|
||
+
|
||
+ Copyright 2009 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/>. */
|
||
+
|
||
+#include <assert.h>
|
||
+
|
||
+extern void libfunc (const char *action);
|
||
+
|
||
+int
|
||
+main (int argc, char **argv)
|
||
+{
|
||
+ assert (argc == 2);
|
||
+
|
||
+ libfunc (argv[1]);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
diff --git a/gdb/testsuite/gdb.base/break-interp.exp b/gdb/testsuite/gdb.base/break-interp.exp
|
||
new file mode 100644
|
||
index 0000000..52f460c
|
||
--- /dev/null
|
||
+++ b/gdb/testsuite/gdb.base/break-interp.exp
|
||
@@ -0,0 +1,545 @@
|
||
+# Copyright 2009 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/>.
|
||
+
|
||
+# This test only works on GNU/Linux.
|
||
+if { ![isnative] || [is_remote host] || ![istarget *-linux*] || [skip_shlib_tests]} {
|
||
+ continue
|
||
+}
|
||
+
|
||
+set test "break-interp"
|
||
+set binprefix ${objdir}/${subdir}/${test}
|
||
+# Only to get the $interp_system name.
|
||
+set srcfile_test "start.c"
|
||
+set binfile_test ${test}-test
|
||
+set binfile_lib ${objdir}/${subdir}/${test}.so
|
||
+set srcfile "${test}-main.c"
|
||
+set srcfile_lib "${test}-lib.c"
|
||
+
|
||
+if [get_compiler_info ${binfile_lib}] {
|
||
+ return -1
|
||
+}
|
||
+
|
||
+# Use -soname so that it is listed with " => " by ldd and this testcase makes
|
||
+# a copy of ${binfile_lib} for each prelink variant.
|
||
+
|
||
+if {[gdb_compile_shlib ${srcdir}/${subdir}/${srcfile_lib} ${binfile_lib} [list debug additional_flags=-Wl,-soname,${test}.so]] != ""} {
|
||
+ return -1
|
||
+}
|
||
+
|
||
+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} {
|
||
+ global debug_root
|
||
+
|
||
+ set exec_build_id_debug [build_id_debug_filename_get $exec]
|
||
+ set debug_base "[file tail $exec].debug"
|
||
+ set exec_dir [file dirname $exec]
|
||
+
|
||
+ # isfile returns 1 even for symlinks to files.
|
||
+ set retval $debug_root/$exec_build_id_debug
|
||
+ if [file isfile $retval] {
|
||
+ return $retval
|
||
+ }
|
||
+ set retval $exec_dir/$debug_base
|
||
+ if [file isfile $retval] {
|
||
+ return $retval
|
||
+ }
|
||
+ set retval $exec_dir/.debug/$debug_base
|
||
+ if [file isfile $retval] {
|
||
+ return $retval
|
||
+ }
|
||
+ set retval $debug_root/$exec_dir/$debug_base
|
||
+ if [file isfile $retval] {
|
||
+ return $retval
|
||
+ }
|
||
+ return ""
|
||
+}
|
||
+
|
||
+gdb_exit
|
||
+gdb_start
|
||
+set debug_root ""
|
||
+set test "show debug-file-directory"
|
||
+gdb_test_multiple $test $test {
|
||
+ -re "The directory where separate debug symbols are searched for is \"(.*)\".\r\n$gdb_prompt $" {
|
||
+ set debug_root $expect_out(1,string)
|
||
+ }
|
||
+}
|
||
+
|
||
+set interp_system [section_get ${objdir}/${subdir}/$binfile_test .interp]
|
||
+set interp_system_debug [system_debug_get $interp_system]
|
||
+verbose -log "$interp_system has debug $interp_system_debug"
|
||
+
|
||
+proc prelinkNO_run {arg} {
|
||
+ set command "exec /usr/sbin/prelink -uN $arg"
|
||
+ verbose -log "command is $command"
|
||
+ set result [catch $command output]
|
||
+ verbose -log "result is $result"
|
||
+ verbose -log "output is $output"
|
||
+ return [list $result $output]
|
||
+}
|
||
+
|
||
+proc prelinkNO {arg {name {}}} {
|
||
+ if {$name == ""} {
|
||
+ set name [file tail $arg]
|
||
+ }
|
||
+ set test "unprelink $name"
|
||
+ set run [prelinkNO_run $arg]
|
||
+ set result [lindex $run 0]
|
||
+ set output [lindex $run 1]
|
||
+ if {$result == 0 && $output == ""} {
|
||
+ verbose -log "$name has been now unprelinked"
|
||
+ set run [prelinkNO_run $arg]
|
||
+ set result [lindex $run 0]
|
||
+ set output [lindex $run 1]
|
||
+ }
|
||
+ # Last line does miss the trailing \n.
|
||
+ if {$result == 1 && [regexp {^(/usr/sbin/prelink: [^ ]* does not have .gnu.prelink_undo section\n?)*$} $output]} {
|
||
+ pass $test
|
||
+ return 1
|
||
+ } else {
|
||
+ fail $test
|
||
+ return 0
|
||
+ }
|
||
+}
|
||
+
|
||
+proc prelinkYES {arg {name ""}} {
|
||
+ if {$name == ""} {
|
||
+ set name [file tail $arg]
|
||
+ }
|
||
+ set test "prelink $name"
|
||
+ set command "exec /usr/sbin/prelink -qNR --no-exec-shield $arg"
|
||
+ verbose -log "command is $command"
|
||
+ set result [catch $command output]
|
||
+ verbose -log "result is $result"
|
||
+ verbose -log "output is $output"
|
||
+ if {$result == 0 && $output == ""} {
|
||
+ pass $test
|
||
+ return 1
|
||
+ } else {
|
||
+ fail $test
|
||
+ return 0
|
||
+ }
|
||
+}
|
||
+
|
||
+# Resolve symlinks.
|
||
+proc symlink_resolve {file} {
|
||
+ set loop 0
|
||
+ while {[file type $file] == "link"} {
|
||
+ set target [file readlink $file]
|
||
+ if {[file pathtype $target] == "relative"} {
|
||
+ set src2 [file dirname $file]/$target
|
||
+ } else {
|
||
+ set src2 $target
|
||
+ }
|
||
+ verbose -log "Resolved symlink $file targetting $target as $src2"
|
||
+ set file $src2
|
||
+
|
||
+ set loop [expr $loop + 1]
|
||
+ if {$loop > 30} {
|
||
+ fail "Looping symlink resolution for $file"
|
||
+ return ""
|
||
+ }
|
||
+ }
|
||
+ return $file
|
||
+}
|
||
+
|
||
+proc copy {src dest} {
|
||
+ set src [symlink_resolve $src]
|
||
+ # Test name would contain build-id hash for symlink-unresolved $src.
|
||
+ set test "copy [file tail $src] to [file tail $dest]"
|
||
+ set command "file copy -force $src $dest"
|
||
+ verbose -log "command is $command"
|
||
+ if [catch $command] {
|
||
+ fail $test
|
||
+ return 0
|
||
+ } else {
|
||
+ pass $test
|
||
+ return 1
|
||
+ }
|
||
+}
|
||
+
|
||
+proc strip_debug {dest} {
|
||
+ set test "strip [file tail $dest]"
|
||
+ set strip_program [transform strip]
|
||
+ set command "exec $strip_program --strip-debug $dest"
|
||
+ verbose -log "command is $command"
|
||
+ if [catch $command] {
|
||
+ fail $test
|
||
+ return 0
|
||
+ } else {
|
||
+ pass $test
|
||
+ return 1
|
||
+ }
|
||
+}
|
||
+
|
||
+# `runto' does not check we stopped really at the function we specified.
|
||
+proc reach {func command} {
|
||
+ global gdb_prompt
|
||
+
|
||
+ if [gdb_breakpoint $func allow-pending] {
|
||
+ set test "reach $func"
|
||
+ gdb_test_multiple $command $test {
|
||
+ -re "Breakpoint \[0-9\]+, $func \\(.*\\) at .*:\[0-9\]+\r\n.*$gdb_prompt $" {
|
||
+ pass $test
|
||
+ }
|
||
+ -re "Breakpoint \[0-9\]+, \[0-9xa-f\]+ in $func \\(\\)( from .*)?\r\n$gdb_prompt $" {
|
||
+ pass $test
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+proc test_core {file} {
|
||
+ global srcdir subdir gdb_prompt
|
||
+
|
||
+ set corefile [core_find $file {} "segv"]
|
||
+ if {$corefile == ""} {
|
||
+ return
|
||
+ }
|
||
+
|
||
+ gdb_exit
|
||
+ gdb_start
|
||
+ # Clear it to never find any separate debug infos in $debug_root.
|
||
+ gdb_test "set debug-file-directory" "" "set debug-file-directory for core"
|
||
+ gdb_reinitialize_dir $srcdir/$subdir
|
||
+ gdb_load $file
|
||
+
|
||
+ # Do not check the binary filename as it may be truncated.
|
||
+ gdb_test "core-file $corefile" "Core was generated by .*\r\n#0 .*" "core loaded"
|
||
+
|
||
+ # Check there is no "argc=can't compute CFA for this frame".
|
||
+ gdb_test "bt" "#\[0-9\]+ +\[^\r\n\]*\\mlibfunc\\M\[^\r\n\]*\r\n#\[0-9\]+ +\[^\r\n\]*\\mmain \\((argc=2,.*)?\\).*" "core main bt"
|
||
+}
|
||
+
|
||
+proc test_attach {file} {
|
||
+ global board_info
|
||
+
|
||
+ gdb_exit
|
||
+
|
||
+ set test "sleep function started"
|
||
+
|
||
+ set command "${file} sleep"
|
||
+ set res [remote_spawn host $command];
|
||
+ if { $res < 0 || $res == "" } {
|
||
+ perror "Spawning $command failed."
|
||
+ fail $test
|
||
+ return
|
||
+ }
|
||
+ set pid [exp_pid -i $res]
|
||
+ gdb_expect {
|
||
+ -re "sleeping\r\n" {
|
||
+ pass $test
|
||
+ }
|
||
+ eof {
|
||
+ fail "$test (eof)"
|
||
+ return
|
||
+ }
|
||
+ timeout {
|
||
+ fail "$test (timeout)"
|
||
+ return
|
||
+ }
|
||
+ }
|
||
+
|
||
+ gdb_exit
|
||
+ gdb_start
|
||
+ gdb_test "attach $pid" "Attaching to process $pid\r\n.*" "attach"
|
||
+ # Check there is no "argc=can't compute CFA for this frame".
|
||
+ gdb_test "bt" "#\[0-9\]+ +\[^\r\n\]*\\mlibfunc\\M\[^\r\n\]*\r\n#\[0-9\]+ +\[^\r\n\]*\\mmain \\((argc=2,.*)?\\).*" "attach main bt"
|
||
+ gdb_exit
|
||
+
|
||
+ remote_exec host "kill -9 $pid"
|
||
+}
|
||
+
|
||
+proc test_ld {file ifmain trynosym} {
|
||
+ global srcdir subdir gdb_prompt
|
||
+
|
||
+ # First test normal `file'-command loaded $FILE with symbols.
|
||
+
|
||
+ gdb_exit
|
||
+ gdb_start
|
||
+ # Clear it to never find any separate debug infos in $debug_root.
|
||
+ gdb_test "set debug-file-directory"
|
||
+ gdb_reinitialize_dir $srcdir/$subdir
|
||
+ gdb_load $file
|
||
+
|
||
+ reach "dl_main" "run segv"
|
||
+
|
||
+ gdb_test "bt" "#0 +\[^\r\n\]*\\mdl_main\\M.*" "dl bt"
|
||
+
|
||
+ if $ifmain {
|
||
+ reach "main" continue
|
||
+
|
||
+ reach "libfunc" continue
|
||
+
|
||
+ # Check there is no "argc=can't compute CFA for this frame".
|
||
+ gdb_test "bt" "#0 +\[^\r\n\]*\\mlibfunc\\M\[^\r\n\]*\r\n#1 +\[^\r\n\]*\\mmain \\((argc=2,.*)?\\).*" "main bt"
|
||
+
|
||
+ test_core $file
|
||
+
|
||
+ test_attach $file
|
||
+ }
|
||
+
|
||
+ if !$trynosym {
|
||
+ return
|
||
+ }
|
||
+
|
||
+ global pf_prefix
|
||
+ set old_ldprefix $pf_prefix
|
||
+ lappend pf_prefix "symbol-less:"
|
||
+
|
||
+ # Test also `exec-file'-command loaded $FILE - therefore without symbols.
|
||
+ # SYMBOL_OBJFILE is not available and only EXEC_BFD must be used.
|
||
+
|
||
+ gdb_exit
|
||
+ gdb_start
|
||
+ # Clear it to never find any separate debug infos in $debug_root.
|
||
+ gdb_test "set debug-file-directory"
|
||
+ gdb_reinitialize_dir $srcdir/$subdir
|
||
+
|
||
+ # Test no (error) message has been printed by `exec-file'.
|
||
+ set escapedfile [string_to_regexp $file]
|
||
+ gdb_test "exec-file $file" "exec-file $escapedfile" "load"
|
||
+
|
||
+ if $ifmain {
|
||
+ reach "dl_main" run
|
||
+
|
||
+ set test "info files"
|
||
+ set entrynohex ""
|
||
+ gdb_test_multiple $test $test {
|
||
+ -re "\r\n\[\t \]*Entry point:\[\t \]*0x(\[0-9a-f\]+)\r\n.*$gdb_prompt $" {
|
||
+ set entrynohex $expect_out(1,string)
|
||
+ pass $test
|
||
+ }
|
||
+ }
|
||
+ if {$entrynohex != ""} {
|
||
+ gdb_test "break *0x$entrynohex" "" "break at entry point"
|
||
+ gdb_test "continue" "\r\nBreakpoint \[0-9\]+, 0x0*$entrynohex in .*" "entry point reached"
|
||
+ }
|
||
+ } else {
|
||
+ # There is no symbol to break at ld.so. Moreover it can exit with an
|
||
+ # error code.
|
||
+ gdb_test "run" "Program exited (normally|with code \[0-9\]+)\\." "ld.so exit"
|
||
+ }
|
||
+
|
||
+ set pf_prefix $old_ldprefix
|
||
+}
|
||
+
|
||
+# Create separate binaries for each testcase - to make the possible reported
|
||
+# problem reproducible after the whole test run finishes.
|
||
+
|
||
+set old_ldprefix $pf_prefix
|
||
+foreach ldprelink {NO YES} {
|
||
+ foreach ldsepdebug {NO IN SEP} {
|
||
+ # Skip running the ldsepdebug test if we do not have system separate
|
||
+ # debug info available.
|
||
+ if {$interp_system_debug == "" && $ldsepdebug == "SEP"} {
|
||
+ continue
|
||
+ }
|
||
+
|
||
+ set ldname "LDprelink${ldprelink}debug${ldsepdebug}"
|
||
+ set interp $binprefix-$ldname
|
||
+
|
||
+ # prelink needs to always prelink all the dependencies to do any file
|
||
+ # modifications of its files. ld.so also needs all the dependencies to
|
||
+ # be prelinked to omit the relocation process. In-memory file offsets
|
||
+ # are not dependent whether ld.so went the prelink way or through the
|
||
+ # relocation process.
|
||
+ #
|
||
+ # For GDB we are not interested whether prelink succeeds as it is
|
||
+ # transparent to GDB. GDB is being tested for differences of file
|
||
+ # offsets vs. in-memory offsets. So we have to prelink even ld.so for
|
||
+ # the BIN modification to happen but we need to restore the original
|
||
+ # possibly unprelinked ld.so to test all the combinations for GDB.
|
||
+ set interp_saved ${interp}-saved
|
||
+
|
||
+ set pf_prefix $old_ldprefix
|
||
+ lappend pf_prefix "$ldname:"
|
||
+
|
||
+ if {$ldsepdebug == "NO"} {
|
||
+ copy $interp_system $interp
|
||
+ # Never call strip-debug before unprelink:
|
||
+ # prelink: ...: Section .note.gnu.build-id created after prelinking
|
||
+ if ![prelinkNO $interp] {
|
||
+ continue
|
||
+ }
|
||
+ strip_debug $interp
|
||
+ } elseif {$ldsepdebug == "IN" && $interp_system_debug == ""} {
|
||
+ copy $interp_system $interp
|
||
+ } elseif {$ldsepdebug == "IN" && $interp_system_debug != ""} {
|
||
+ copy $interp_system $interp
|
||
+ copy $interp_system_debug "${interp}.debug"
|
||
+ # eu-unstrip: DWARF data in '...' not adjusted for prelinking bias; consider prelink -u
|
||
+ if {![prelinkNO $interp] || ![prelinkNO "${interp}.debug"]} {
|
||
+ continue
|
||
+ }
|
||
+ set test "eu-unstrip unprelinked:[file tail $interp_system] + [file tail $interp_system_debug] to [file tail $interp]"
|
||
+ set command "exec eu-unstrip -o $interp $interp ${interp}.debug"
|
||
+ verbose -log "command is $command"
|
||
+ if [catch $command] {
|
||
+ setup_xfail *-*-*
|
||
+ fail $test
|
||
+ continue
|
||
+ } else {
|
||
+ pass $test
|
||
+ }
|
||
+ } elseif {$ldsepdebug == "SEP" && $interp_system_debug == ""} {
|
||
+ copy $interp_system $interp
|
||
+ # eu-unstrip: DWARF data in '...' not adjusted for prelinking bias; consider prelink -u
|
||
+ if ![prelinkNO $interp] {
|
||
+ continue
|
||
+ }
|
||
+ gdb_gnu_strip_debug $interp
|
||
+ } elseif {$ldsepdebug == "SEP" && $interp_system_debug != ""} {
|
||
+ copy $interp_system $interp
|
||
+ copy $interp_system_debug "${interp}.debug"
|
||
+ }
|
||
+
|
||
+ if {$ldsepdebug == "SEP"} {
|
||
+ if ![prelinkNO "${interp}.debug"] {
|
||
+ continue
|
||
+ }
|
||
+ } else {
|
||
+ file delete "${interp}.debug"
|
||
+ }
|
||
+
|
||
+ if ![prelink$ldprelink $interp] {
|
||
+ continue
|
||
+ }
|
||
+ test_ld $interp 0 [expr {$ldsepdebug == "NO"}]
|
||
+
|
||
+ if ![copy $interp $interp_saved] {
|
||
+ continue
|
||
+ }
|
||
+ set old_binprefix $pf_prefix
|
||
+ foreach binprelink {NO YES} {
|
||
+ foreach binsepdebug {NO IN SEP} {
|
||
+ foreach binpie {NO YES} {
|
||
+ # This combination is not possible, non-PIE (fixed address)
|
||
+ # binary cannot be prelinked to any (other) address.
|
||
+ if {$binprelink == "YES" && $binpie == "NO"} {
|
||
+ continue
|
||
+ }
|
||
+
|
||
+ set binname "BINprelink${binprelink}debug${binsepdebug}pie${binpie}"
|
||
+ set exec $binprefix-$binname
|
||
+ set dir ${exec}.d
|
||
+
|
||
+ set pf_prefix $old_binprefix
|
||
+ lappend pf_prefix "$binname:"
|
||
+
|
||
+ set opts "additional_flags=-Wl,--dynamic-linker,$interp,-rpath,$dir"
|
||
+ lappend opts "additional_flags=-Wl,$binfile_lib,-rpath,[file dirname $binfile_lib]"
|
||
+ if {$binsepdebug != "NO"} {
|
||
+ lappend opts {debug}
|
||
+ }
|
||
+ if {$binpie == "YES"} {
|
||
+ lappend opts {additional_flags=-fPIE -pie}
|
||
+ }
|
||
+ if {[build_executable ${test}.exp [file tail $exec] $srcfile $opts] == -1} {
|
||
+ continue;
|
||
+ }
|
||
+ if {$binsepdebug == "SEP"} {
|
||
+ gdb_gnu_strip_debug $exec
|
||
+ # Just a sanity check. As gdb_gnu_strip_debug uses the
|
||
+ # "[file dirname $exec]/.debug/[file tail $exec].debug"
|
||
+ # variant delete the higher-priority exec.debug file.
|
||
+ file delete "$exec.debug"
|
||
+ }
|
||
+
|
||
+ # Supply a self-sufficent directory $dir with the required
|
||
+ # libraries. To make an executable properly prelinked all
|
||
+ # its dependencies on libraries must be also prelinked. If
|
||
+ # some of the system libraries is currently not prelinked
|
||
+ # we have no right to prelink (modify it) at its current
|
||
+ # system place.
|
||
+
|
||
+ file delete -force $dir
|
||
+ file mkdir $dir
|
||
+
|
||
+ set command "ldd $exec"
|
||
+ set result [catch "exec $command" output]
|
||
+ verbose -log "result of $command is $result"
|
||
+ verbose -log "output of $command is $output"
|
||
+ if {$result != 0 || $output == ""} {
|
||
+ fail $command
|
||
+ } else {
|
||
+ pass $command
|
||
+ }
|
||
+
|
||
+ # gdb testsuite will put there also needless -lm.
|
||
+ set test "$command output contains libc"
|
||
+ set libc [regexp -all -inline -line {^.* => (/[^ ]+).*$} $output]
|
||
+ if {[llength $libc] == 0} {
|
||
+ fail $test
|
||
+ } else {
|
||
+ pass $test
|
||
+ }
|
||
+
|
||
+ set dests {}
|
||
+ for {set i 1} {$i < [llength $libc]} {incr i 2} {
|
||
+ set abspath [lindex $libc $i]
|
||
+ set dest "$dir/[file tail $abspath]"
|
||
+ copy $abspath $dest
|
||
+ lappend dests $dest
|
||
+ }
|
||
+
|
||
+ if {[prelink$binprelink "--dynamic-linker=$interp --ld-library-path=$dir $exec $interp [concat $dests]" $exec]
|
||
+ && [copy $interp_saved $interp]} {
|
||
+ test_ld $exec 1 [expr {$binsepdebug == "NO"}]
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ file delete $interp_saved
|
||
+ }
|
||
+}
|
||
+set pf_prefix $old_ldprefix
|
||
diff --git a/gdb/testsuite/gdb.base/corefile.exp b/gdb/testsuite/gdb.base/corefile.exp
|
||
index a1003e1..547a898 100644
|
||
--- a/gdb/testsuite/gdb.base/corefile.exp
|
||
+++ b/gdb/testsuite/gdb.base/corefile.exp
|
||
@@ -42,65 +42,12 @@ if [get_compiler_info ${binfile}] {
|
||
return -1;
|
||
}
|
||
|
||
-# Create a core file named "corefile" rather than just "core", to
|
||
-# avoid problems with sys admin types that like to regularly prune all
|
||
-# files named "core" from the system.
|
||
-#
|
||
-# Arbitrarily try setting the core size limit to "unlimited" since
|
||
-# this does not hurt on systems where the command does not work and
|
||
-# allows us to generate a core on systems where it does.
|
||
-#
|
||
-# Some systems append "core" to the name of the program; others append
|
||
-# the name of the program to "core"; still others (like Linux, as of
|
||
-# May 2003) create cores named "core.PID". In the latter case, we
|
||
-# could have many core files lying around, and it may be difficult to
|
||
-# tell which one is ours, so let's run the program in a subdirectory.
|
||
-set found 0
|
||
-set coredir "${objdir}/${subdir}/coredir.[getpid]"
|
||
-file mkdir $coredir
|
||
-catch "system \"(cd ${coredir}; ulimit -c unlimited; ${binfile}; true) >/dev/null 2>&1\""
|
||
-# remote_exec host "${binfile}"
|
||
-foreach i "${coredir}/core ${coredir}/core.coremaker.c ${binfile}.core" {
|
||
- if [remote_file build exists $i] {
|
||
- remote_exec build "mv $i ${objdir}/${subdir}/corefile"
|
||
- set found 1
|
||
- }
|
||
-}
|
||
-# Check for "core.PID".
|
||
-if { $found == 0 } {
|
||
- set names [glob -nocomplain -directory $coredir core.*]
|
||
- if {[llength $names] == 1} {
|
||
- set corefile [file join $coredir [lindex $names 0]]
|
||
- remote_exec build "mv $corefile ${objdir}/${subdir}/corefile"
|
||
- set found 1
|
||
- }
|
||
-}
|
||
-if { $found == 0 } {
|
||
- # The braindamaged HPUX shell quits after the ulimit -c above
|
||
- # without executing ${binfile}. So we try again without the
|
||
- # ulimit here if we didn't find a core file above.
|
||
- # Oh, I should mention that any "braindamaged" non-Unix system has
|
||
- # the same problem. I like the cd bit too, it's really neat'n stuff.
|
||
- catch "system \"(cd ${objdir}/${subdir}; ${binfile}; true) >/dev/null 2>&1\""
|
||
- foreach i "${objdir}/${subdir}/core ${objdir}/${subdir}/core.coremaker.c ${binfile}.core" {
|
||
- if [remote_file build exists $i] {
|
||
- remote_exec build "mv $i ${objdir}/${subdir}/corefile"
|
||
- set found 1
|
||
- }
|
||
- }
|
||
+set corefile [core_find $binfile {coremmap.data}]
|
||
+if {$corefile == ""} {
|
||
+ return 0;
|
||
}
|
||
|
||
-# Try to clean up after ourselves.
|
||
-remote_file build delete [file join $coredir coremmap.data]
|
||
-remote_exec build "rmdir $coredir"
|
||
-
|
||
-if { $found == 0 } {
|
||
- warning "can't generate a core file - core tests suppressed - check ulimit -c"
|
||
- return 0
|
||
-}
|
||
-
|
||
-#
|
||
-# Test that we can simply startup with a "-core=corefile" command line arg
|
||
+# Test that we can simply startup with a "-core=$corefile" command line arg
|
||
# and recognize that the core file is a valid, usable core file.
|
||
# To do this, we must shutdown the currently running gdb and restart
|
||
# with the -core args. We can't use gdb_start because it looks for
|
||
@@ -114,27 +61,27 @@ if { $found == 0 } {
|
||
|
||
gdb_exit
|
||
if $verbose>1 then {
|
||
- send_user "Spawning $GDB $INTERNAL_GDBFLAGS $GDBFLAGS -core=$objdir/$subdir/corefile\n"
|
||
+ send_user "Spawning $GDB $INTERNAL_GDBFLAGS $GDBFLAGS -core=$corefile\n"
|
||
}
|
||
|
||
set oldtimeout $timeout
|
||
set timeout [expr "$timeout + 60"]
|
||
verbose "Timeout is now $timeout seconds" 2
|
||
-eval "spawn $GDB $INTERNAL_GDBFLAGS $GDBFLAGS -core=$objdir/$subdir/corefile"
|
||
+eval "spawn $GDB $INTERNAL_GDBFLAGS $GDBFLAGS -core=$corefile"
|
||
expect {
|
||
-re "Couldn't find .* registers in core file.*$gdb_prompt $" {
|
||
- fail "args: -core=corefile (couldn't find regs)"
|
||
+ fail "args: -core=[file tail $corefile] (couldn't find regs)"
|
||
}
|
||
-re "Core was generated by .*coremaker.*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" {
|
||
- pass "args: -core=corefile"
|
||
+ pass "args: -core=[file tail $corefile]"
|
||
}
|
||
-re "Core was generated by .*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" {
|
||
- pass "args: -core=corefile (with bad program name)"
|
||
+ pass "args: -core=[file tail $corefile] (with bad program name)"
|
||
}
|
||
-re ".*registers from core file: File in wrong format.* $" {
|
||
- fail "args: -core=corefile (could not read registers from core file)"
|
||
+ fail "args: -core=[file tail $corefile] (could not read registers from core file)"
|
||
}
|
||
- -re ".*$gdb_prompt $" { fail "args: -core=corefile" }
|
||
+ -re ".*$gdb_prompt $" { fail "args: -core=[file tail $corefile]" }
|
||
timeout { fail "(timeout) starting with -core" }
|
||
}
|
||
|
||
@@ -147,22 +94,22 @@ expect {
|
||
close;
|
||
|
||
if $verbose>1 then {
|
||
- send_user "Spawning $GDB $INTERNAL_GDBFLAGS $GDBFLAGS $binfile -core=$objdir/$subdir/corefile\n"
|
||
+ send_user "Spawning $GDB $INTERNAL_GDBFLAGS $GDBFLAGS $binfile -core=$corefile\n"
|
||
}
|
||
|
||
|
||
-eval "spawn $GDB $INTERNAL_GDBFLAGS $GDBFLAGS $binfile -core=$objdir/$subdir/corefile";
|
||
+eval "spawn $GDB $INTERNAL_GDBFLAGS $GDBFLAGS $binfile -core=$corefile";
|
||
expect {
|
||
-re "Core was generated by .*coremaker.*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" {
|
||
- pass "args: execfile -core=corefile"
|
||
+ pass "args: execfile -core=[file tail $corefile]"
|
||
}
|
||
-re "Core was generated by .*\r\n\#0 .*\(\).*\r\n$gdb_prompt $" {
|
||
- pass "args: execfile -core=corefile (with bad program name)"
|
||
+ pass "args: execfile -core=[file tail $corefile] (with bad program name)"
|
||
}
|
||
-re ".*registers from core file: File in wrong format.* $" {
|
||
- fail "args: execfile -core=corefile (could not read registers from core file)"
|
||
+ fail "args: execfile -core=[file tail $corefile] (could not read registers from core file)"
|
||
}
|
||
- -re ".*$gdb_prompt $" { fail "args: execfile -core=corefile" }
|
||
+ -re ".*$gdb_prompt $" { fail "args: execfile -core=[file tail $corefile]" }
|
||
timeout { fail "(timeout) starting with -core" }
|
||
}
|
||
set timeout $oldtimeout
|
||
@@ -178,7 +125,7 @@ gdb_load ${binfile}
|
||
|
||
# Test basic corefile recognition via core-file command.
|
||
|
||
-send_gdb "core-file $objdir/$subdir/corefile\n"
|
||
+send_gdb "core-file $corefile\n"
|
||
gdb_expect {
|
||
-re ".* program is being debugged already.*y or n. $" {
|
||
# gdb_load may connect us to a gdbserver.
|
||
diff --git a/gdb/testsuite/gdb.base/pie-support.c b/gdb/testsuite/gdb.base/pie-support.c
|
||
deleted file mode 100644
|
||
index 63768b9..0000000
|
||
--- a/gdb/testsuite/gdb.base/pie-support.c
|
||
+++ /dev/null
|
||
@@ -1,34 +0,0 @@
|
||
-/* This testcase is part of GDB, the GNU debugger.
|
||
-
|
||
- Copyright 2009 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/>.
|
||
-
|
||
-*/
|
||
-
|
||
-#include <stdio.h>
|
||
-
|
||
-void
|
||
-f1 (int a)
|
||
-{
|
||
- printf ("a = %d\n", a);
|
||
-}
|
||
-
|
||
-int
|
||
-main (int argc, char *argv[])
|
||
-{
|
||
- f1 (1);
|
||
-
|
||
- return 0;
|
||
-}
|
||
diff --git a/gdb/testsuite/gdb.base/pie-support.exp b/gdb/testsuite/gdb.base/pie-support.exp
|
||
deleted file mode 100644
|
||
index 7d118c0..0000000
|
||
--- a/gdb/testsuite/gdb.base/pie-support.exp
|
||
+++ /dev/null
|
||
@@ -1,58 +0,0 @@
|
||
-# Copyright 2009 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/>.
|
||
-
|
||
-set testfile pie-support
|
||
-set srcfile ${testfile}.c
|
||
-set objfile ${objdir}/${subdir}/${testfile}.o
|
||
-set binfile ${objdir}/${subdir}/${testfile}
|
||
-
|
||
-if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objfile}" object {quiet debug additional_flags=-fpie}] != "" } {
|
||
- untested "Couldn't compile test PIE object file."
|
||
- return -1
|
||
-}
|
||
-if { [gdb_compile "${objfile}" "${binfile}" executable {quiet debug additional_flags=-pie}] != "" } {
|
||
- untested "Couldn't compile test PIE binary."
|
||
- return -1
|
||
-}
|
||
-
|
||
-# Get things started.
|
||
-
|
||
-gdb_exit
|
||
-gdb_start
|
||
-gdb_reinitialize_dir $srcdir/$subdir
|
||
-
|
||
-if [is_remote host] {
|
||
- set binfile [remote_download host $binfile]
|
||
- if { $binfile == "" } {
|
||
- untested "Couldn't download remote test binary."
|
||
- return -1
|
||
- }
|
||
-}
|
||
-
|
||
-# The file command used to kill the remote target. For the benefit
|
||
-# of the testsuite, preserve this behavior.
|
||
-send_gdb "kill\n"
|
||
-gdb_expect 120 {
|
||
- -re "Kill the program being debugged. .y or n. $" {
|
||
- send_gdb "y\n"
|
||
- verbose "\t\tKilling previous program being debugged"
|
||
- exp_continue
|
||
- }
|
||
- -re "$gdb_prompt $" {
|
||
- # OK.
|
||
- }
|
||
-}
|
||
-
|
||
-gdb_test "file $binfile" "current binary is a PIE.*" "correctly detected PIE binary"
|
||
diff --git a/gdb/testsuite/gdb.base/valgrind-db-attach.c b/gdb/testsuite/gdb.base/valgrind-db-attach.c
|
||
new file mode 100644
|
||
index 0000000..5faaaac
|
||
--- /dev/null
|
||
+++ b/gdb/testsuite/gdb.base/valgrind-db-attach.c
|
||
@@ -0,0 +1,30 @@
|
||
+/* This testcase is part of GDB, the GNU debugger.
|
||
+
|
||
+ Copyright 2009 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/>. */
|
||
+
|
||
+#include <stdlib.h>
|
||
+
|
||
+int main()
|
||
+{
|
||
+ void *p;
|
||
+
|
||
+ p = malloc (1);
|
||
+ if (p == NULL)
|
||
+ return 1;
|
||
+ free (p);
|
||
+ free (p); /* double-free */
|
||
+ return 0;
|
||
+}
|
||
diff --git a/gdb/testsuite/gdb.base/valgrind-db-attach.exp b/gdb/testsuite/gdb.base/valgrind-db-attach.exp
|
||
new file mode 100644
|
||
index 0000000..ac06fd3
|
||
--- /dev/null
|
||
+++ b/gdb/testsuite/gdb.base/valgrind-db-attach.exp
|
||
@@ -0,0 +1,74 @@
|
||
+# Copyright 2009 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/>.
|
||
+
|
||
+set test valgrind-db-attach
|
||
+set srcfile $test.c
|
||
+set executable $test
|
||
+set binfile ${objdir}/${subdir}/${executable}
|
||
+if {[build_executable $test.exp $executable $srcfile {debug}] == -1} {
|
||
+ return -1
|
||
+}
|
||
+
|
||
+gdb_exit
|
||
+
|
||
+# remote_spawn breaks the command on each whitespace despite possible quoting.
|
||
+# Use backslash-escaped whitespace there instead:
|
||
+
|
||
+set db_command "--db-command=$GDB $INTERNAL_GDBFLAGS $GDBFLAGS [host_info gdb_opts] %f %p"
|
||
+regsub -all " " $db_command "\\ " db_command
|
||
+
|
||
+set test "spawn valgrind"
|
||
+set cmd "valgrind --db-attach=yes $db_command $binfile"
|
||
+set res [remote_spawn host $cmd];
|
||
+if { $res < 0 || $res == "" } {
|
||
+ verbose -log "Spawning $cmd failed."
|
||
+ setup_xfail *-*-*
|
||
+ fail $test
|
||
+ return -1
|
||
+}
|
||
+pass $test
|
||
+# Declare GDB now as running.
|
||
+set gdb_spawn_id -1
|
||
+
|
||
+set test "valgrind started"
|
||
+# The trailing '.' differs for different memcheck versions.
|
||
+gdb_test_multiple "" $test {
|
||
+ -re "Memcheck, a memory error detector\\.?\r\n" {
|
||
+ pass $test
|
||
+ }
|
||
+ -re "valgrind: failed to start tool 'memcheck' for platform '.*': No such file or directory" {
|
||
+ setup_xfail *-*-*
|
||
+ fail $test
|
||
+ return -1
|
||
+ }
|
||
+}
|
||
+
|
||
+set double_free [gdb_get_line_number "double-free"]
|
||
+
|
||
+gdb_test_multiple "" $test {
|
||
+ -re "Invalid free\\(\\) / delete / delete\\\[\\\]\r\n.*: main \\(${srcfile}:$double_free\\)\r\n.*---- Attach to debugger \\? --- \[^\r\n\]* ---- " {
|
||
+ send_gdb "y\r"
|
||
+ }
|
||
+ -re "---- Attach to debugger \\? --- \[^\r\n\]* ---- " {
|
||
+ send_gdb "n\r"
|
||
+ exp_continue
|
||
+ }
|
||
+}
|
||
+
|
||
+# Initialization from default_gdb_start.
|
||
+gdb_test "set height 0"
|
||
+gdb_test "set width 0"
|
||
+
|
||
+gdb_test "bt" "in main \\(.*\\) at .*${srcfile}:$double_free"
|
||
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-ranges.exp b/gdb/testsuite/gdb.dwarf2/dw2-ranges.exp
|
||
index 61e1fe4..9109030 100644
|
||
--- a/gdb/testsuite/gdb.dwarf2/dw2-ranges.exp
|
||
+++ b/gdb/testsuite/gdb.dwarf2/dw2-ranges.exp
|
||
@@ -55,6 +55,12 @@ gdb_start
|
||
gdb_reinitialize_dir $srcdir/$subdir
|
||
gdb_load ${binfile}
|
||
|
||
+# Test also objfile->psymtabs_addrmap relocations for -fPIE -pie builds below.
|
||
+# On some targets it may possibly fail but the program is being started only
|
||
+# for the PIE build so try it anyway.
|
||
+
|
||
+runto_main
|
||
+
|
||
# Correct output:
|
||
# Line 39 of "../.././gdb/testsuite/gdb.dwarf2/dw2-ranges.S" starts at address 0x4 and ends at 0x8.
|
||
# Wrong output:
|
||
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
|
||
index d0c3493..fbf9124 100644
|
||
--- a/gdb/testsuite/lib/gdb.exp
|
||
+++ b/gdb/testsuite/lib/gdb.exp
|
||
@@ -2778,6 +2778,11 @@ proc gdb_gnu_strip_debug { dest args } {
|
||
return 1
|
||
}
|
||
|
||
+ # Workaround PR binutils/10802:
|
||
+ # Preserve the 'x' bit also for PIEs (Position Independent Executables).
|
||
+ set perm [file attributes ${dest} -permissions]
|
||
+ file attributes ${stripped_file} -permissions $perm
|
||
+
|
||
# Get rid of everything but the debug info, and store result in debug_file
|
||
# This will be in the .debug subdirectory, see above.
|
||
set result [catch "exec $strip_to_file_program --only-keep-debug ${dest} -o ${debug_file}" output]
|
||
@@ -2814,7 +2819,12 @@ proc gdb_gnu_strip_debug { dest args } {
|
||
return 1
|
||
}
|
||
|
||
- return 0
|
||
+ # Workaround PR binutils/10802:
|
||
+ # Preserve the 'x' bit also for PIEs (Position Independent Executables).
|
||
+ set perm [file attributes ${stripped_file} -permissions]
|
||
+ file attributes ${dest} -permissions $perm
|
||
+
|
||
+ return 0
|
||
}
|
||
|
||
# Test the output of GDB_COMMAND matches the pattern obtained
|
||
@@ -3043,3 +3053,70 @@ if {[info exists TRANSCRIPT]} {
|
||
return [uplevel real_send_gdb $args]
|
||
}
|
||
}
|
||
+
|
||
+proc core_find {binfile {deletefiles {}} {arg ""}} {
|
||
+ global objdir subdir
|
||
+
|
||
+ set destcore "$binfile.core"
|
||
+ file delete $destcore
|
||
+
|
||
+ # Create a core file named "$destcore" rather than just "core", to
|
||
+ # avoid problems with sys admin types that like to regularly prune all
|
||
+ # files named "core" from the system.
|
||
+ #
|
||
+ # Arbitrarily try setting the core size limit to "unlimited" since
|
||
+ # this does not hurt on systems where the command does not work and
|
||
+ # allows us to generate a core on systems where it does.
|
||
+ #
|
||
+ # Some systems append "core" to the name of the program; others append
|
||
+ # the name of the program to "core"; still others (like Linux, as of
|
||
+ # May 2003) create cores named "core.PID". In the latter case, we
|
||
+ # could have many core files lying around, and it may be difficult to
|
||
+ # tell which one is ours, so let's run the program in a subdirectory.
|
||
+ set found 0
|
||
+ set coredir "${objdir}/${subdir}/coredir.[getpid]"
|
||
+ file mkdir $coredir
|
||
+ catch "system \"(cd ${coredir}; ulimit -c unlimited; ${binfile} ${arg}; true) >/dev/null 2>&1\""
|
||
+ # remote_exec host "${binfile}"
|
||
+ foreach i "${coredir}/core ${coredir}/core.coremaker.c ${binfile}.core" {
|
||
+ if [remote_file build exists $i] {
|
||
+ remote_exec build "mv $i $destcore"
|
||
+ set found 1
|
||
+ }
|
||
+ }
|
||
+ # Check for "core.PID".
|
||
+ if { $found == 0 } {
|
||
+ set names [glob -nocomplain -directory $coredir core.*]
|
||
+ if {[llength $names] == 1} {
|
||
+ set corefile [file join $coredir [lindex $names 0]]
|
||
+ remote_exec build "mv $corefile $destcore"
|
||
+ set found 1
|
||
+ }
|
||
+ }
|
||
+ if { $found == 0 } {
|
||
+ # The braindamaged HPUX shell quits after the ulimit -c above
|
||
+ # without executing ${binfile}. So we try again without the
|
||
+ # ulimit here if we didn't find a core file above.
|
||
+ # Oh, I should mention that any "braindamaged" non-Unix system has
|
||
+ # the same problem. I like the cd bit too, it's really neat'n stuff.
|
||
+ catch "system \"(cd ${objdir}/${subdir}; ${binfile}; true) >/dev/null 2>&1\""
|
||
+ foreach i "${objdir}/${subdir}/core ${objdir}/${subdir}/core.coremaker.c ${binfile}.core" {
|
||
+ if [remote_file build exists $i] {
|
||
+ remote_exec build "mv $i $destcore"
|
||
+ set found 1
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ # Try to clean up after ourselves.
|
||
+ foreach deletefile $deletefiles {
|
||
+ remote_file build delete [file join $coredir $deletefile]
|
||
+ }
|
||
+ remote_exec build "rmdir $coredir"
|
||
+
|
||
+ if { $found == 0 } {
|
||
+ warning "can't generate a core file - core tests suppressed - check ulimit -c"
|
||
+ return ""
|
||
+ }
|
||
+ return $destcore
|
||
+}
|