Revert the previous 7 commits of: Validate binary before use
ddc98fbf2f
Create empty nat/linux-maps.[ch] and common/target-utils.[ch]6e5b4429db
Move gdb_regex* to common/f7af1fcd75
Prepare linux_find_memory_regions_full & co. for move9904185cfd
Move linux_find_memory_regions_full & co.700ca40f6f
gdbserver build-id attribute generatorca5268b6be
Validate symbol file using build-id0a94970d66
Tests for validate symbol file using build-id gdb/ChangeLog 2015-07-15 Jan Kratochvil <jan.kratochvil@redhat.com> Revert the previous 6 commits: Create empty nat/linux-maps.[ch] and common/target-utils.[ch]. Move gdb_regex* to common/ Prepare linux_find_memory_regions_full & co. for move Move linux_find_memory_regions_full & co. gdbserver build-id attribute generator Validate symbol file using build-id gdb/gdbserver/ChangeLog 2015-07-15 Jan Kratochvil <jan.kratochvil@redhat.com> Revert the previous 3 commits: Move gdb_regex* to common/ Move linux_find_memory_regions_full & co. gdbserver build-id attribute generator gdb/doc/ChangeLog 2015-07-15 Jan Kratochvil <jan.kratochvil@redhat.com> Revert the previous 2 commits: gdbserver build-id attribute generator Validate symbol file using build-id gdb/testsuite/ChangeLog 2015-07-15 Jan Kratochvil <jan.kratochvil@redhat.com> Revert the previous commit: Tests for validate symbol file using build-id.
This commit is contained in:
parent
0a94970d66
commit
db1ff28b60
|
@ -1,3 +1,13 @@
|
|||
2015-07-15 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Revert the previous 6 commits:
|
||||
Create empty nat/linux-maps.[ch] and common/target-utils.[ch].
|
||||
Move gdb_regex* to common/
|
||||
Prepare linux_find_memory_regions_full & co. for move
|
||||
Move linux_find_memory_regions_full & co.
|
||||
gdbserver build-id attribute generator
|
||||
Validate symbol file using build-id
|
||||
|
||||
2015-07-15 Aleksandar Ristovski <aristovski@qnx.com
|
||||
Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
|
|
|
@ -903,7 +903,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
|
|||
# right, it is probably easiest just to list .h files here directly.
|
||||
|
||||
HFILES_NO_SRCDIR = \
|
||||
common/gdb_signals.h nat/gdb_thread_db.h common/gdb_vecs.h nat/linux-maps.h \
|
||||
common/gdb_signals.h nat/gdb_thread_db.h common/gdb_vecs.h \
|
||||
common/x86-xstate.h nat/linux-ptrace.h nat/mips-linux-watch.h \
|
||||
proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \
|
||||
ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
|
||||
|
@ -937,7 +937,7 @@ extension.h extension-priv.h \
|
|||
build-id.h buildsym.h valprint.h \
|
||||
typeprint.h mi/mi-getopt.h mi/mi-parse.h mi/mi-console.h \
|
||||
mi/mi-out.h mi/mi-main.h mi/mi-common.h mi/mi-cmds.h linux-nat.h \
|
||||
complaints.h gdb_proc_service.h common/gdb_regex.h xtensa-tdep.h inf-loop.h \
|
||||
complaints.h gdb_proc_service.h gdb_regex.h xtensa-tdep.h inf-loop.h \
|
||||
common/gdb_wait.h common/gdb_assert.h solib.h ppc-tdep.h cp-support.h glibc-tdep.h \
|
||||
interps.h auxv.h gdbcmd.h tramp-frame.h mipsnbsd-tdep.h \
|
||||
amd64-linux-tdep.h linespec.h i387-tdep.h mn10300-tdep.h \
|
||||
|
@ -983,7 +983,7 @@ common/common-debug.h common/cleanups.h common/gdb_setjmp.h \
|
|||
common/common-exceptions.h target/target.h common/symbol.h \
|
||||
common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \
|
||||
common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h \
|
||||
nat/linux-namespaces.h target/target-utils.h
|
||||
nat/linux-namespaces.h
|
||||
|
||||
# Header files that already have srcdir in them, or which are in objdir.
|
||||
|
||||
|
@ -1083,8 +1083,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
|
|||
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
|
||||
format.o registry.o btrace.o record-btrace.o waitstatus.o \
|
||||
print-utils.o rsp-low.o errors.o common-debug.o debug.o \
|
||||
common-exceptions.o btrace-common.o fileio.o target-utils.o \
|
||||
gdb_regex.o \
|
||||
common-exceptions.o btrace-common.o fileio.o \
|
||||
$(SUBDIR_GCC_COMPILE_OBS)
|
||||
|
||||
TSOBS = inflow.o
|
||||
|
@ -2222,10 +2221,6 @@ common-agent.o: $(srcdir)/common/agent.c
|
|||
$(COMPILE) $(srcdir)/common/agent.c
|
||||
$(POSTCOMPILE)
|
||||
|
||||
linux-maps.o: ${srcdir}/nat/linux-maps.c
|
||||
$(COMPILE) $(srcdir)/nat/linux-maps.c
|
||||
$(POSTCOMPILE)
|
||||
|
||||
vec.o: ${srcdir}/common/vec.c
|
||||
$(COMPILE) $(srcdir)/common/vec.c
|
||||
$(POSTCOMPILE)
|
||||
|
@ -2242,10 +2237,6 @@ errors.o: ${srcdir}/common/errors.c
|
|||
$(COMPILE) $(srcdir)/common/errors.c
|
||||
$(POSTCOMPILE)
|
||||
|
||||
target-utils.o: ${srcdir}/target/target-utils.c
|
||||
$(COMPILE) $(srcdir)/target/target-utils.c
|
||||
$(POSTCOMPILE)
|
||||
|
||||
common-debug.o: ${srcdir}/common/common-debug.c
|
||||
$(COMPILE) $(srcdir)/common/common-debug.c
|
||||
$(POSTCOMPILE)
|
||||
|
@ -2273,10 +2264,6 @@ btrace-common.o: ${srcdir}/common/btrace-common.c
|
|||
fileio.o: ${srcdir}/common/fileio.c
|
||||
$(COMPILE) $(srcdir)/common/fileio.c
|
||||
$(POSTCOMPILE)
|
||||
|
||||
gdb_regex.o: ${srcdir}/common/gdb_regex.c
|
||||
$(COMPILE) $(srcdir)/common/gdb_regex.c
|
||||
$(POSTCOMPILE)
|
||||
#
|
||||
# gdb/target/ dependencies
|
||||
#
|
||||
|
|
14
gdb/NEWS
14
gdb/NEWS
|
@ -5,20 +5,6 @@
|
|||
|
||||
* Support for tracepoints on aarch64-linux was added in GDBserver.
|
||||
|
||||
* New options
|
||||
|
||||
set validate-build-id (on|off)
|
||||
show validate-build-id
|
||||
Inferior shared library and symbol file may contain unique build-id.
|
||||
If both build-ids are present but they do not match then this setting
|
||||
enables (off) or disables (on) loading of such symbol file.
|
||||
|
||||
* New features in the GDB remote stub, GDBserver
|
||||
|
||||
** library-list-svr4 contains also optional attribute 'build-id' for
|
||||
each library. GDB does not load library with build-id that
|
||||
does not match such attribute.
|
||||
|
||||
*** Changes in GDB 7.10
|
||||
|
||||
* Support for process record-replay and reverse debugging on aarch64*-linux*
|
||||
|
|
|
@ -44,33 +44,4 @@ gdb_cv_func_sigsetjmp=yes, gdb_cv_func_sigsetjmp=no)])
|
|||
if test $gdb_cv_func_sigsetjmp = yes; then
|
||||
AC_DEFINE(HAVE_SIGSETJMP, 1, [Define if sigsetjmp is available. ])
|
||||
fi
|
||||
|
||||
# Assume we'll default to using the included libiberty regex.
|
||||
gdb_use_included_regex=yes
|
||||
|
||||
# However, if the system regex is GNU regex, then default to *not*
|
||||
# using the included regex.
|
||||
AC_CACHE_CHECK(
|
||||
[for GNU regex],
|
||||
[gdb_cv_have_gnu_regex],
|
||||
[AC_TRY_COMPILE(
|
||||
[#include <gnu-versions.h>],
|
||||
[#define REGEX_INTERFACE_VERSION 1
|
||||
#if _GNU_REGEX_INTERFACE_VERSION != REGEX_INTERFACE_VERSION
|
||||
# error "Version mismatch"
|
||||
#endif],
|
||||
gdb_cv_have_gnu_regex=yes,
|
||||
gdb_cv_have_gnu_regex=no)])
|
||||
if test $gdb_cv_have_gnu_regex = yes; then
|
||||
gdb_use_included_regex=no
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(included-regex,
|
||||
AS_HELP_STRING([--without-included-regex], [don't use included regex; this is the default on systems with version 2 of the GNU C library (use with caution on other system)]),
|
||||
gdb_with_regex=$withval,
|
||||
gdb_with_regex=$gdb_use_included_regex)
|
||||
if test "$gdb_with_regex" = yes; then
|
||||
AC_DEFINE(USE_INCLUDED_REGEX, 1,
|
||||
[Define to 1 if the regex included in libiberty should be used.])
|
||||
fi
|
||||
])
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
/* Shared utility routines for GDB to interact with agent.
|
||||
|
||||
Copyright (C) 2009-2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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 "common-defs.h"
|
||||
#include "gdb_regex.h"
|
||||
|
||||
/* A cleanup function that calls regfree. */
|
||||
|
||||
static void
|
||||
do_regfree_cleanup (void *r)
|
||||
{
|
||||
regfree (r);
|
||||
}
|
||||
|
||||
/* Create a new cleanup that frees the compiled regular expression R. */
|
||||
|
||||
struct cleanup *
|
||||
make_regfree_cleanup (regex_t *r)
|
||||
{
|
||||
return make_cleanup (do_regfree_cleanup, r);
|
||||
}
|
||||
|
||||
/* Return an xmalloc'd error message resulting from a regular
|
||||
expression compilation failure. */
|
||||
|
||||
char *
|
||||
get_regcomp_error (int code, regex_t *rx)
|
||||
{
|
||||
size_t length = regerror (code, rx, NULL, 0);
|
||||
char *result = xmalloc (length);
|
||||
|
||||
regerror (code, rx, result, length);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Compile a regexp and throw an exception on error. This returns a
|
||||
cleanup to free the resulting pattern on success. RX must not be
|
||||
NULL. */
|
||||
|
||||
struct cleanup *
|
||||
compile_rx_or_error (regex_t *pattern, const char *rx, const char *message)
|
||||
{
|
||||
int code;
|
||||
|
||||
gdb_assert (rx != NULL);
|
||||
|
||||
code = regcomp (pattern, rx, REG_NOSUB);
|
||||
if (code != 0)
|
||||
{
|
||||
char *err = get_regcomp_error (code, pattern);
|
||||
|
||||
make_cleanup (xfree, err);
|
||||
error (("%s: %s"), message, err);
|
||||
}
|
||||
|
||||
return make_regfree_cleanup (pattern);
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
NAT_FILE= config/nm-linux.h
|
||||
NATDEPFILES= inf-ptrace.o fork-child.o \
|
||||
x86-nat.o x86-dregs.o i386-linux-nat.o x86-linux-nat.o \
|
||||
proc-service.o linux-thread-db.o linux-maps.o \
|
||||
proc-service.o linux-thread-db.o \
|
||||
linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
|
||||
linux-btrace.o linux-waitpid.o linux-personality.o x86-linux.o \
|
||||
x86-linux-dregs.o linux-namespaces.o
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
NATDEPFILES= inf-ptrace.o fork-child.o \
|
||||
x86-nat.o x86-dregs.o amd64-nat.o amd64-linux-nat.o \
|
||||
x86-linux-nat.o \
|
||||
linux-maps.o linux-nat.o linux-osdata.o \
|
||||
linux-nat.o linux-osdata.o \
|
||||
proc-service.o linux-thread-db.o linux-fork.o \
|
||||
linux-procfs.o linux-ptrace.o linux-btrace.o \
|
||||
linux-waitpid.o linux-personality.o x86-linux.o \
|
||||
|
|
|
@ -11925,57 +11925,6 @@ $as_echo "#define HAVE_SIGSETJMP 1" >>confdefs.h
|
|||
|
||||
fi
|
||||
|
||||
# Assume we'll default to using the included libiberty regex.
|
||||
gdb_use_included_regex=yes
|
||||
|
||||
# However, if the system regex is GNU regex, then default to *not*
|
||||
# using the included regex.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU regex" >&5
|
||||
$as_echo_n "checking for GNU regex... " >&6; }
|
||||
if test "${gdb_cv_have_gnu_regex+set}" = set; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <gnu-versions.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
#define REGEX_INTERFACE_VERSION 1
|
||||
#if _GNU_REGEX_INTERFACE_VERSION != REGEX_INTERFACE_VERSION
|
||||
# error "Version mismatch"
|
||||
#endif
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
gdb_cv_have_gnu_regex=yes
|
||||
else
|
||||
gdb_cv_have_gnu_regex=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_have_gnu_regex" >&5
|
||||
$as_echo "$gdb_cv_have_gnu_regex" >&6; }
|
||||
if test $gdb_cv_have_gnu_regex = yes; then
|
||||
gdb_use_included_regex=no
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-included-regex was given.
|
||||
if test "${with_included_regex+set}" = set; then :
|
||||
withval=$with_included_regex; gdb_with_regex=$withval
|
||||
else
|
||||
gdb_with_regex=$gdb_use_included_regex
|
||||
fi
|
||||
|
||||
if test "$gdb_with_regex" = yes; then
|
||||
|
||||
$as_echo "#define USE_INCLUDED_REGEX 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check the return and argument types of ptrace. No canned test for
|
||||
# this, so roll our own.
|
||||
|
@ -12238,6 +12187,57 @@ if test $ac_cv_func_setpgrp_void = yes; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# Assume we'll default to using the included libiberty regex.
|
||||
gdb_use_included_regex=yes
|
||||
|
||||
# However, if the system regex is GNU regex, then default to *not*
|
||||
# using the included regex.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU regex" >&5
|
||||
$as_echo_n "checking for GNU regex... " >&6; }
|
||||
if test "${gdb_cv_have_gnu_regex+set}" = set; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <gnu-versions.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
#define REGEX_INTERFACE_VERSION 1
|
||||
#if _GNU_REGEX_INTERFACE_VERSION != REGEX_INTERFACE_VERSION
|
||||
# error "Version mismatch"
|
||||
#endif
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
gdb_cv_have_gnu_regex=yes
|
||||
else
|
||||
gdb_cv_have_gnu_regex=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_have_gnu_regex" >&5
|
||||
$as_echo "$gdb_cv_have_gnu_regex" >&6; }
|
||||
if test $gdb_cv_have_gnu_regex = yes; then
|
||||
gdb_use_included_regex=no
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-included-regex was given.
|
||||
if test "${with_included_regex+set}" = set; then :
|
||||
withval=$with_included_regex; gdb_with_regex=$withval
|
||||
else
|
||||
gdb_with_regex=$gdb_use_included_regex
|
||||
fi
|
||||
|
||||
if test "$gdb_with_regex" = yes; then
|
||||
|
||||
$as_echo "#define USE_INCLUDED_REGEX 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
# Check if <sys/proc.h> defines `struct thread' with a td_pcb member.
|
||||
ac_fn_c_check_member "$LINENO" "struct thread" "td_pcb" "ac_cv_member_struct_thread_td_pcb" "#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
|
|
|
@ -1444,6 +1444,35 @@ if test $ac_cv_func_setpgrp_void = yes; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# Assume we'll default to using the included libiberty regex.
|
||||
gdb_use_included_regex=yes
|
||||
|
||||
# However, if the system regex is GNU regex, then default to *not*
|
||||
# using the included regex.
|
||||
AC_CACHE_CHECK(
|
||||
[for GNU regex],
|
||||
[gdb_cv_have_gnu_regex],
|
||||
[AC_TRY_COMPILE(
|
||||
[#include <gnu-versions.h>],
|
||||
[#define REGEX_INTERFACE_VERSION 1
|
||||
#if _GNU_REGEX_INTERFACE_VERSION != REGEX_INTERFACE_VERSION
|
||||
# error "Version mismatch"
|
||||
#endif],
|
||||
gdb_cv_have_gnu_regex=yes,
|
||||
gdb_cv_have_gnu_regex=no)])
|
||||
if test $gdb_cv_have_gnu_regex = yes; then
|
||||
gdb_use_included_regex=no
|
||||
fi
|
||||
|
||||
AC_ARG_WITH(included-regex,
|
||||
AS_HELP_STRING([--without-included-regex], [don't use included regex; this is the default on systems with version 2 of the GNU C library (use with caution on other system)]),
|
||||
gdb_with_regex=$withval,
|
||||
gdb_with_regex=$gdb_use_included_regex)
|
||||
if test "$gdb_with_regex" = yes; then
|
||||
AC_DEFINE(USE_INCLUDED_REGEX, 1,
|
||||
[Define to 1 if the regex included in libiberty should be used.])
|
||||
fi
|
||||
|
||||
# Check if <sys/proc.h> defines `struct thread' with a td_pcb member.
|
||||
AC_CHECK_MEMBERS([struct thread.td_pcb], [], [],
|
||||
[#include <sys/param.h>
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2015-07-15 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Revert the previous 2 commits:
|
||||
gdbserver build-id attribute generator
|
||||
Validate symbol file using build-id
|
||||
|
||||
2015-07-15 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* gdb.texinfo (Files): Add 'set validate-build-id'
|
||||
|
|
|
@ -17950,44 +17950,6 @@ libraries that were loaded by explicit user requests are not
|
|||
discarded.
|
||||
@end table
|
||||
|
||||
@table @code
|
||||
@kindex set validate-build-id
|
||||
@cindex override @value{GDBN} build-id check
|
||||
@item set validate-build-id @var{mode}
|
||||
Setting to override @value{GDBN} build-id check.
|
||||
|
||||
Inferior shared libraries and symbol files may contain unique build-id.
|
||||
By default @value{GDBN} will ignore symbol files with non-matching build-id
|
||||
while printing:
|
||||
|
||||
@smallexample
|
||||
warning: Shared object "libfoo.so.1" could not be validated (remote
|
||||
build ID 2bc1745e does not match local build ID a08f8767) and will be
|
||||
ignored; or use 'set validate-build-id off'.
|
||||
@end smallexample
|
||||
|
||||
Turning off this setting would load such symbol file while still printing:
|
||||
|
||||
@smallexample
|
||||
warning: Shared object "libfoo.so.1" could not be validated (remote
|
||||
build ID 2bc1745e does not match local build ID a08f8767) but it is
|
||||
being loaded due to 'set validate-build-id off'.
|
||||
@end smallexample
|
||||
|
||||
If remote build-id is present but it does not match local build-id (or local
|
||||
build-id is not present) then this setting enables (@var{mode} is @code{off}) or
|
||||
disables (@var{mode} is @code{on}) loading of such symbol file. On systems
|
||||
where build-id is not present in the remote system this setting has no effect.
|
||||
The default value is @code{on}.
|
||||
|
||||
Loading non-matching symbol file may confuse debugging including breakage
|
||||
of backtrace output.
|
||||
|
||||
@kindex show validate-build-id
|
||||
@item show validate-build-id
|
||||
Display the current mode of build-id check override.
|
||||
@end table
|
||||
|
||||
Sometimes you may wish that @value{GDBN} stops and gives you control
|
||||
when any of shared library events happen. The best way to do this is
|
||||
to use @code{catch load} and @code{catch unload} (@pxref{Set
|
||||
|
@ -39551,8 +39513,6 @@ memory address. It is a displacement of absolute memory address against
|
|||
address the file was prelinked to during the library load.
|
||||
@item
|
||||
@code{l_ld}, which is memory address of the @code{PT_DYNAMIC} segment
|
||||
@item
|
||||
@code{build-id}, hex encoded @code{NT_GNU_BUILD_ID} note, if it exists.
|
||||
@end itemize
|
||||
|
||||
Additionally the single @code{main-lm} attribute specifies address of
|
||||
|
@ -39570,7 +39530,7 @@ looks like this:
|
|||
<library name="/lib/ld-linux.so.2" lm="0xe4f51c" l_addr="0xe2d000"
|
||||
l_ld="0xe4eefc"/>
|
||||
<library name="/lib/libc.so.6" lm="0xe4fbe8" l_addr="0x154000"
|
||||
l_ld="0x152350" build-id="9afccf7cc41e6293476223fe72480854"/>
|
||||
l_ld="0x152350"/>
|
||||
</library-list-svr>
|
||||
@end smallexample
|
||||
|
||||
|
@ -39579,14 +39539,13 @@ The format of an SVR4 library list is described by this DTD:
|
|||
@smallexample
|
||||
<!-- library-list-svr4: Root element with versioning -->
|
||||
<!ELEMENT library-list-svr4 (library)*>
|
||||
<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
|
||||
<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
|
||||
<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
|
||||
<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
|
||||
<!ELEMENT library EMPTY>
|
||||
<!ATTLIST library name CDATA #REQUIRED>
|
||||
<!ATTLIST library lm CDATA #REQUIRED>
|
||||
<!ATTLIST library l_addr CDATA #REQUIRED>
|
||||
<!ATTLIST library l_ld CDATA #REQUIRED>
|
||||
<!ATTLIST library build-id CDATA #IMPLIED>
|
||||
<!ATTLIST library name CDATA #REQUIRED>
|
||||
<!ATTLIST library lm CDATA #REQUIRED>
|
||||
<!ATTLIST library l_addr CDATA #REQUIRED>
|
||||
<!ATTLIST library l_ld CDATA #REQUIRED>
|
||||
@end smallexample
|
||||
|
||||
@node Memory Map Format
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
|
||||
<!-- library-list-svr4: Root element with versioning -->
|
||||
<!ELEMENT library-list-svr4 (library)*>
|
||||
<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
|
||||
<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
|
||||
<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
|
||||
<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT library EMPTY>
|
||||
<!ATTLIST library name CDATA #REQUIRED>
|
||||
<!ATTLIST library lm CDATA #REQUIRED>
|
||||
<!ATTLIST library l_addr CDATA #REQUIRED>
|
||||
<!ATTLIST library l_ld CDATA #REQUIRED>
|
||||
<!ATTLIST library build-id CDATA #IMPLIED>
|
||||
<!ATTLIST library name CDATA #REQUIRED>
|
||||
<!ATTLIST library lm CDATA #REQUIRED>
|
||||
<!ATTLIST library l_addr CDATA #REQUIRED>
|
||||
<!ATTLIST library l_ld CDATA #REQUIRED>
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef COMMON_GDB_REGEX_H
|
||||
#define COMMON_GDB_REGEX_H 1
|
||||
#ifndef GDB_REGEX_H
|
||||
#define GDB_REGEX_H 1
|
||||
|
||||
#ifdef USE_INCLUDED_REGEX
|
||||
# include "xregex.h"
|
||||
|
@ -27,9 +27,10 @@
|
|||
# include <regex.h>
|
||||
#endif
|
||||
|
||||
/* From utils.c. */
|
||||
struct cleanup *make_regfree_cleanup (regex_t *);
|
||||
char *get_regcomp_error (int, regex_t *);
|
||||
struct cleanup *compile_rx_or_error (regex_t *pattern, const char *rx,
|
||||
const char *message);
|
||||
|
||||
#endif /* not COMMON_GDB_REGEX_H */
|
||||
#endif /* not GDB_REGEX_H */
|
|
@ -1,3 +1,10 @@
|
|||
2015-07-15 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Revert the previous 3 commits:
|
||||
Move gdb_regex* to common/
|
||||
Move linux_find_memory_regions_full & co.
|
||||
gdbserver build-id attribute generator
|
||||
|
||||
2015-07-15 Aleksandar Ristovski <aristovski@qnx.com
|
||||
Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
|
|
|
@ -194,8 +194,7 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o \
|
|||
mem-break.o hostio.o event-loop.o tracepoint.o xml-utils.o \
|
||||
common-utils.o ptid.o buffer.o format.o filestuff.o dll.o notif.o \
|
||||
tdesc.o print-utils.o rsp-low.o errors.o common-debug.o cleanups.o \
|
||||
common-exceptions.o symbol.o btrace-common.o fileio.o target-utils.o \
|
||||
gdb_regex.o \
|
||||
common-exceptions.o symbol.o btrace-common.o fileio.o \
|
||||
$(XML_BUILTIN) $(DEPFILES) $(LIBOBJS)
|
||||
GDBREPLAY_OBS = gdbreplay.o version.o
|
||||
GDBSERVER_LIBS = @GDBSERVER_LIBS@
|
||||
|
@ -520,9 +519,6 @@ ax.o: ax.c
|
|||
signals.o: ../common/signals.c
|
||||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
linux-maps.o: ../nat/linux-maps.c
|
||||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
print-utils.o: ../common/print-utils.c
|
||||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
|
@ -535,9 +531,6 @@ common-utils.o: ../common/common-utils.c
|
|||
posix-strerror.o: ../common/posix-strerror.c
|
||||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
target-utils.o: ../target/target-utils.c
|
||||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
mingw-strerror.o: ../common/mingw-strerror.c
|
||||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
|
@ -583,9 +576,6 @@ waitstatus.o: ../target/waitstatus.c
|
|||
fileio.o: ../common/fileio.c
|
||||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
gdb_regex.o: ../common/gdb_regex.c
|
||||
$(COMPILE) $<
|
||||
$(POSTCOMPILE)
|
||||
|
||||
# Native object files rules from ../nat
|
||||
|
||||
|
|
|
@ -317,9 +317,6 @@
|
|||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if the regex included in libiberty should be used. */
|
||||
#undef USE_INCLUDED_REGEX
|
||||
|
||||
/* Define if we should use libthread_db directly. */
|
||||
#undef USE_LIBTHREAD_DB_DIRECTLY
|
||||
|
||||
|
|
|
@ -694,7 +694,6 @@ enable_maintainer_mode
|
|||
enable_largefile
|
||||
enable_build_with_cxx
|
||||
enable_libmcheck
|
||||
with_included_regex
|
||||
with_ust
|
||||
with_ust_include
|
||||
with_ust_lib
|
||||
|
@ -1346,10 +1345,6 @@ Optional Features:
|
|||
Optional Packages:
|
||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
|
||||
--without-included-regex
|
||||
don't use included regex; this is the default on
|
||||
systems with version 2 of the GNU C library (use
|
||||
with caution on other system)
|
||||
--with-ust=PATH Specify prefix directory for the installed UST package
|
||||
Equivalent to --with-ust-include=PATH/include
|
||||
plus --with-ust-lib=PATH/lib
|
||||
|
@ -5752,57 +5747,6 @@ $as_echo "#define HAVE_SIGSETJMP 1" >>confdefs.h
|
|||
|
||||
fi
|
||||
|
||||
# Assume we'll default to using the included libiberty regex.
|
||||
gdb_use_included_regex=yes
|
||||
|
||||
# However, if the system regex is GNU regex, then default to *not*
|
||||
# using the included regex.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU regex" >&5
|
||||
$as_echo_n "checking for GNU regex... " >&6; }
|
||||
if test "${gdb_cv_have_gnu_regex+set}" = set; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <gnu-versions.h>
|
||||
int
|
||||
main ()
|
||||
{
|
||||
#define REGEX_INTERFACE_VERSION 1
|
||||
#if _GNU_REGEX_INTERFACE_VERSION != REGEX_INTERFACE_VERSION
|
||||
# error "Version mismatch"
|
||||
#endif
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
gdb_cv_have_gnu_regex=yes
|
||||
else
|
||||
gdb_cv_have_gnu_regex=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_have_gnu_regex" >&5
|
||||
$as_echo "$gdb_cv_have_gnu_regex" >&6; }
|
||||
if test $gdb_cv_have_gnu_regex = yes; then
|
||||
gdb_use_included_regex=no
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-included-regex was given.
|
||||
if test "${with_included_regex+set}" = set; then :
|
||||
withval=$with_included_regex; gdb_with_regex=$withval
|
||||
else
|
||||
gdb_with_regex=$gdb_use_included_regex
|
||||
fi
|
||||
|
||||
if test "$gdb_with_regex" = yes; then
|
||||
|
||||
$as_echo "#define USE_INCLUDED_REGEX 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check for UST
|
||||
ustlibs=""
|
||||
|
|
|
@ -42,7 +42,7 @@ srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/amd64-avx-linux.xml i386/amd
|
|||
|
||||
# Linux object files. This is so we don't have to repeat
|
||||
# these files over and over again.
|
||||
srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-maps.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o"
|
||||
srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o linux-personality.o linux-namespaces.o"
|
||||
|
||||
# Input is taken from the "${target}" variable.
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "agent.h"
|
||||
#include "tdesc.h"
|
||||
#include "rsp-low.h"
|
||||
#include "nat/linux-maps.h"
|
||||
|
||||
#include "nat/linux-nat.h"
|
||||
#include "nat/linux-waitpid.h"
|
||||
|
@ -44,11 +43,9 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <sys/uio.h>
|
||||
#include <search.h>
|
||||
#include "filestuff.h"
|
||||
#include "tracepoint.h"
|
||||
#include "hostio.h"
|
||||
#include "rsp-low.h"
|
||||
#ifndef ELFMAG0
|
||||
/* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
|
||||
then ELFMAG0 will have been defined. If it didn't get included by
|
||||
|
@ -185,31 +182,6 @@ lwp_stop_reason (struct lwp_info *lwp)
|
|||
return lwp->stop_reason;
|
||||
}
|
||||
|
||||
typedef union ElfXX_Ehdr
|
||||
{
|
||||
Elf32_Ehdr _32;
|
||||
Elf64_Ehdr _64;
|
||||
} ElfXX_Ehdr;
|
||||
|
||||
typedef union ElfXX_Phdr
|
||||
{
|
||||
Elf32_Phdr _32;
|
||||
Elf64_Phdr _64;
|
||||
} ElfXX_Phdr;
|
||||
|
||||
typedef union ElfXX_Nhdr
|
||||
{
|
||||
Elf32_Nhdr _32;
|
||||
Elf64_Nhdr _64;
|
||||
} ElfXX_Nhdr;
|
||||
|
||||
#define ELFXX_FLD(elf64, hdr, fld) ((elf64) ? (hdr)._64.fld : (hdr)._32.fld)
|
||||
#define ELFXX_SIZEOF(elf64, hdr) ((elf64) ? sizeof ((hdr)._64) \
|
||||
: sizeof ((hdr)._32))
|
||||
/* Round up to next 4 byte boundary. */
|
||||
#define ELFXX_ROUNDUP_4(elf64, what) (((what) + 3) & ~(ULONGEST) 3)
|
||||
#define BUILD_ID_INVALID "?"
|
||||
|
||||
/* A list of all unknown processes which receive stop signals. Some
|
||||
other process will presumably claim each of these as forked
|
||||
children momentarily. */
|
||||
|
@ -6038,38 +6010,15 @@ get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Linearly traverse pheaders and look for P_TYPE pheader. */
|
||||
|
||||
static const void *
|
||||
find_phdr (const int is_elf64, const void *const phdr_begin,
|
||||
const void *const phdr_end, const ULONGEST p_type)
|
||||
{
|
||||
#define PHDR_NEXT(hdrp) ((const void *) ((const gdb_byte *) (hdrp) + \
|
||||
ELFXX_SIZEOF (is_elf64, *hdrp)))
|
||||
|
||||
const ElfXX_Phdr *phdr = phdr_begin;
|
||||
|
||||
while (PHDR_NEXT (phdr) <= phdr_end)
|
||||
{
|
||||
if (ELFXX_FLD (is_elf64, *phdr, p_type) == p_type)
|
||||
return phdr;
|
||||
phdr = PHDR_NEXT (phdr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#undef PHDR_NEXT
|
||||
}
|
||||
|
||||
/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */
|
||||
|
||||
static CORE_ADDR
|
||||
get_dynamic (const int pid, const int is_elf64)
|
||||
{
|
||||
CORE_ADDR phdr_memaddr, relocation;
|
||||
int num_phdr;
|
||||
int num_phdr, i;
|
||||
unsigned char *phdr_buf;
|
||||
const ElfXX_Phdr *phdr;
|
||||
const int phdr_size = ELFXX_SIZEOF (is_elf64, *phdr);
|
||||
const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr);
|
||||
|
||||
if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr))
|
||||
return 0;
|
||||
|
@ -6083,10 +6032,22 @@ get_dynamic (const int pid, const int is_elf64)
|
|||
/* Compute relocation: it is expected to be 0 for "regular" executables,
|
||||
non-zero for PIE ones. */
|
||||
relocation = -1;
|
||||
phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
|
||||
PT_PHDR);
|
||||
if (phdr != NULL)
|
||||
relocation = phdr_memaddr - ELFXX_FLD (is_elf64, *phdr, p_vaddr);
|
||||
for (i = 0; relocation == -1 && i < num_phdr; i++)
|
||||
if (is_elf64)
|
||||
{
|
||||
Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
|
||||
|
||||
if (p->p_type == PT_PHDR)
|
||||
relocation = phdr_memaddr - p->p_vaddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
|
||||
|
||||
if (p->p_type == PT_PHDR)
|
||||
relocation = phdr_memaddr - p->p_vaddr;
|
||||
}
|
||||
|
||||
if (relocation == -1)
|
||||
{
|
||||
/* PT_PHDR is optional, but necessary for PIE in general. Fortunately
|
||||
|
@ -6102,11 +6063,23 @@ get_dynamic (const int pid, const int is_elf64)
|
|||
return 0;
|
||||
}
|
||||
|
||||
phdr = find_phdr (is_elf64, phdr_buf, phdr_buf + num_phdr * phdr_size,
|
||||
PT_DYNAMIC);
|
||||
for (i = 0; i < num_phdr; i++)
|
||||
{
|
||||
if (is_elf64)
|
||||
{
|
||||
Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
|
||||
|
||||
if (phdr != NULL)
|
||||
return ELFXX_FLD (is_elf64, *phdr, p_vaddr) + relocation;
|
||||
if (p->p_type == PT_DYNAMIC)
|
||||
return p->p_vaddr + relocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
|
||||
|
||||
if (p->p_type == PT_DYNAMIC)
|
||||
return p->p_vaddr + relocation;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6246,278 +6219,6 @@ struct link_map_offsets
|
|||
int l_prev_offset;
|
||||
};
|
||||
|
||||
|
||||
/* Structure for holding a mapping. Only mapping
|
||||
containing l_ld can have hex_build_id set. */
|
||||
|
||||
struct mapping_entry
|
||||
{
|
||||
/* Fields are populated from linux_find_memory_region parameters. */
|
||||
|
||||
ULONGEST vaddr;
|
||||
ULONGEST size;
|
||||
ULONGEST offset;
|
||||
ULONGEST inode;
|
||||
|
||||
/* Hex encoded string allocated using xmalloc, and
|
||||
needs to be freed. It can be NULL. */
|
||||
|
||||
char *hex_build_id;
|
||||
};
|
||||
|
||||
typedef struct mapping_entry mapping_entry_s;
|
||||
|
||||
DEF_VEC_O(mapping_entry_s);
|
||||
|
||||
/* Free vector of mapping_entry_s objects. */
|
||||
|
||||
static void
|
||||
free_mapping_entry_vec (VEC (mapping_entry_s) *lst)
|
||||
{
|
||||
int ix;
|
||||
mapping_entry_s *p;
|
||||
|
||||
for (ix = 0; VEC_iterate (mapping_entry_s, lst, ix, p); ++ix)
|
||||
xfree (p->hex_build_id);
|
||||
|
||||
VEC_free (mapping_entry_s, lst);
|
||||
}
|
||||
|
||||
/* Used for finding a mapping containing the given
|
||||
l_ld passed in K. */
|
||||
|
||||
static int
|
||||
compare_mapping_entry_range (const void *const k, const void *const b)
|
||||
{
|
||||
const ULONGEST key = *(const CORE_ADDR *) k;
|
||||
const mapping_entry_s *const p = b;
|
||||
|
||||
if (key < p->vaddr)
|
||||
return -1;
|
||||
|
||||
if (key < p->vaddr + p->size)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct find_memory_region_callback_data
|
||||
{
|
||||
unsigned is_elf64;
|
||||
|
||||
/* Return. Must be freed with free_mapping_entry_vec. */
|
||||
VEC (mapping_entry_s) *list;
|
||||
};
|
||||
|
||||
/* Read build-id from PT_NOTE.
|
||||
Argument LOAD_ADDR represents run time virtual address corresponding to
|
||||
the beginning of the first loadable segment. L_ADDR is displacement
|
||||
as supplied by the dynamic linker. */
|
||||
|
||||
static void
|
||||
read_build_id (struct find_memory_region_callback_data *const p,
|
||||
mapping_entry_s *const bil, const CORE_ADDR load_addr,
|
||||
const CORE_ADDR l_addr)
|
||||
{
|
||||
const int is_elf64 = p->is_elf64;
|
||||
ElfXX_Ehdr ehdr;
|
||||
|
||||
if (linux_read_memory (load_addr, (unsigned char *) &ehdr,
|
||||
ELFXX_SIZEOF (is_elf64, ehdr)) == 0
|
||||
&& ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG0]) == ELFMAG0
|
||||
&& ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG1]) == ELFMAG1
|
||||
&& ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG2]) == ELFMAG2
|
||||
&& ELFXX_FLD (is_elf64, ehdr, e_ident[EI_MAG3]) == ELFMAG3)
|
||||
{
|
||||
const ElfXX_Phdr *phdr;
|
||||
void *phdr_buf;
|
||||
const unsigned e_phentsize = ELFXX_FLD (is_elf64, ehdr, e_phentsize);
|
||||
|
||||
if (ELFXX_FLD (is_elf64, ehdr, e_phnum) >= 100
|
||||
|| e_phentsize != ELFXX_SIZEOF (is_elf64, *phdr))
|
||||
{
|
||||
/* Basic sanity check failed. */
|
||||
warning (_("Could not identify program header at %s."),
|
||||
paddress (load_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
phdr_buf = alloca (ELFXX_FLD (is_elf64, ehdr, e_phnum) * e_phentsize);
|
||||
|
||||
if (linux_read_memory (load_addr + ELFXX_FLD (is_elf64, ehdr, e_phoff),
|
||||
phdr_buf,
|
||||
ELFXX_FLD (is_elf64, ehdr, e_phnum) * e_phentsize)
|
||||
!= 0)
|
||||
{
|
||||
warning (_("Could not read program header at %s."),
|
||||
paddress (load_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
phdr = phdr_buf;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
gdb_byte *pt_note;
|
||||
const gdb_byte *pt_end;
|
||||
const ElfXX_Nhdr *nhdr;
|
||||
CORE_ADDR note_addr;
|
||||
|
||||
phdr = find_phdr (p->is_elf64, phdr, (gdb_byte *) phdr_buf
|
||||
+ ELFXX_FLD (is_elf64, ehdr, e_phnum) * e_phentsize,
|
||||
PT_NOTE);
|
||||
if (phdr == NULL)
|
||||
break;
|
||||
pt_note = xmalloc (ELFXX_FLD (is_elf64, *phdr, p_memsz));
|
||||
note_addr = ELFXX_FLD (is_elf64, *phdr, p_vaddr) + l_addr;
|
||||
if (linux_read_memory (note_addr, pt_note,
|
||||
ELFXX_FLD (is_elf64, *phdr, p_memsz)) != 0)
|
||||
{
|
||||
xfree (pt_note);
|
||||
warning (_("Could not read note at address 0x%s"),
|
||||
paddress (note_addr));
|
||||
break;
|
||||
}
|
||||
|
||||
pt_end = pt_note + ELFXX_FLD (is_elf64, *phdr, p_memsz);
|
||||
nhdr = (void *) pt_note;
|
||||
while ((const gdb_byte *) nhdr < pt_end)
|
||||
{
|
||||
const size_t namesz
|
||||
= ELFXX_ROUNDUP_4 (is_elf64, ELFXX_FLD (is_elf64, *nhdr,
|
||||
n_namesz));
|
||||
const size_t descsz
|
||||
= ELFXX_ROUNDUP_4 (is_elf64, ELFXX_FLD (is_elf64, *nhdr,
|
||||
n_descsz));
|
||||
const size_t note_sz = (ELFXX_SIZEOF (is_elf64, *nhdr) + namesz
|
||||
+ descsz);
|
||||
|
||||
if (((const gdb_byte *) nhdr + note_sz) > pt_end || note_sz == 0
|
||||
|| descsz == 0)
|
||||
{
|
||||
warning (_("Malformed PT_NOTE at address 0x%s\n"),
|
||||
paddress (note_addr + (gdb_byte *) nhdr - pt_note));
|
||||
break;
|
||||
}
|
||||
if (ELFXX_FLD (is_elf64, *nhdr, n_type) == NT_GNU_BUILD_ID
|
||||
&& ELFXX_FLD (is_elf64, *nhdr, n_namesz) == 4)
|
||||
{
|
||||
const char gnu[4] = "GNU\0";
|
||||
const char *const pname
|
||||
= (char *) nhdr + ELFXX_SIZEOF (is_elf64, *nhdr);
|
||||
|
||||
if (memcmp (pname, gnu, 4) == 0)
|
||||
{
|
||||
const size_t n_descsz = ELFXX_FLD (is_elf64, *nhdr,
|
||||
n_descsz);
|
||||
|
||||
bil->hex_build_id = xmalloc (n_descsz * 2 + 1);
|
||||
bin2hex ((const gdb_byte *) pname + namesz,
|
||||
bil->hex_build_id, n_descsz);
|
||||
xfree (pt_note);
|
||||
return;
|
||||
}
|
||||
}
|
||||
nhdr = (void *) ((gdb_byte *) nhdr + note_sz);
|
||||
}
|
||||
xfree (pt_note);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static linux_find_memory_region_ftype find_memory_region_callback;
|
||||
|
||||
/* Add mapping_entry. See linux_find_memory_ftype for the parameters
|
||||
description. */
|
||||
|
||||
static int
|
||||
find_memory_region_callback (ULONGEST vaddr, ULONGEST size, ULONGEST offset,
|
||||
ULONGEST inode, int read, int write, int exec,
|
||||
int modified, const char *filename, void *data)
|
||||
{
|
||||
if (inode != 0)
|
||||
{
|
||||
struct find_memory_region_callback_data *const p = data;
|
||||
mapping_entry_s bil;
|
||||
|
||||
bil.vaddr = vaddr;
|
||||
bil.size = size;
|
||||
bil.offset = offset;
|
||||
bil.inode = inode;
|
||||
bil.hex_build_id = NULL;
|
||||
|
||||
VEC_safe_push (mapping_entry_s, p->list, &bil);
|
||||
}
|
||||
|
||||
/* Continue the traversal. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Linear reverse find starting from RBEGIN towards REND looking for
|
||||
the lowest vaddr mapping of the same inode and zero offset. */
|
||||
|
||||
static mapping_entry_s *
|
||||
lrfind_mapping_entry (mapping_entry_s *const rbegin,
|
||||
const mapping_entry_s *const rend)
|
||||
{
|
||||
mapping_entry_s *p;
|
||||
|
||||
for (p = rbegin - 1; p >= rend; --p)
|
||||
if (p->offset == 0 && p->inode == rbegin->inode)
|
||||
return p;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get build-id for the given L_LD, where L_LD corresponds to
|
||||
link_map.l_ld as specified by the dynamic linker.
|
||||
DATA must point to already filled list of mapping_entry elements.
|
||||
|
||||
If build-id had not been read, read it and cache in corresponding
|
||||
list element.
|
||||
|
||||
Return build_id as stored in the list element corresponding
|
||||
to L_LD.
|
||||
|
||||
NULL may be returned if build-id could not be fetched.
|
||||
|
||||
Returned string must not be freed explicitly. */
|
||||
|
||||
static const char *
|
||||
get_hex_build_id (const CORE_ADDR l_addr, const CORE_ADDR l_ld,
|
||||
struct find_memory_region_callback_data *const data)
|
||||
{
|
||||
mapping_entry_s *bil;
|
||||
|
||||
bil = bsearch (&l_ld, VEC_address (mapping_entry_s, data->list),
|
||||
VEC_length (mapping_entry_s, data->list),
|
||||
sizeof (mapping_entry_s), compare_mapping_entry_range);
|
||||
|
||||
if (bil == NULL)
|
||||
return NULL;
|
||||
|
||||
if (bil->hex_build_id == NULL)
|
||||
{
|
||||
mapping_entry_s *bil_min;
|
||||
|
||||
bil_min = lrfind_mapping_entry (bil, VEC_address (mapping_entry_s,
|
||||
data->list));
|
||||
if (bil_min != NULL)
|
||||
read_build_id (data, bil, bil_min->vaddr, l_addr);
|
||||
else
|
||||
{
|
||||
/* Do not try to find hex_build_id again. */
|
||||
bil->hex_build_id = xstrdup (BUILD_ID_INVALID);
|
||||
warning (_("Could not determine load address; mapping entry with "
|
||||
"offset 0 corresponding to l_ld = 0x%s could not be "
|
||||
"found; build-id can not be used."),
|
||||
paddress (l_ld));
|
||||
}
|
||||
}
|
||||
|
||||
return bil->hex_build_id;
|
||||
}
|
||||
|
||||
/* Construct qXfer:libraries-svr4:read reply. */
|
||||
|
||||
static int
|
||||
|
@ -6530,15 +6231,6 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
|
|||
struct process_info_private *const priv = current_process ()->priv;
|
||||
char filename[PATH_MAX];
|
||||
int pid, is_elf64;
|
||||
struct find_memory_region_callback_data data;
|
||||
|
||||
/* COREFILTER_ANON_PRIVATE and COREFILTER_ANON_SHARED do not have an
|
||||
associated file so it is not expected it could have an ELF header. */
|
||||
const enum filterflags filterflags = (COREFILTER_MAPPED_PRIVATE
|
||||
| COREFILTER_MAPPED_SHARED
|
||||
| COREFILTER_ELF_HEADERS
|
||||
| COREFILTER_HUGETLB_PRIVATE
|
||||
| COREFILTER_HUGETLB_SHARED);
|
||||
|
||||
static const struct link_map_offsets lmo_32bit_offsets =
|
||||
{
|
||||
|
@ -6581,14 +6273,6 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
|
|||
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
|
||||
ptr_size = is_elf64 ? 8 : 4;
|
||||
|
||||
data.is_elf64 = is_elf64;
|
||||
data.list = NULL;
|
||||
VEC_reserve (mapping_entry_s, data.list, 16);
|
||||
if (linux_find_memory_regions_full (pid, filterflags,
|
||||
find_memory_region_callback, &data)
|
||||
< 0)
|
||||
warning (_("Finding memory regions failed"));
|
||||
|
||||
while (annex[0] != '\0')
|
||||
{
|
||||
const char *sep;
|
||||
|
@ -6695,7 +6379,6 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
|
|||
/* 6x the size for xml_escape_text below. */
|
||||
size_t len = 6 * strlen ((char *) libname);
|
||||
char *name;
|
||||
const char *hex_enc_build_id = NULL;
|
||||
|
||||
if (!header_done)
|
||||
{
|
||||
|
@ -6704,11 +6387,7 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
|
|||
header_done = 1;
|
||||
}
|
||||
|
||||
hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
|
||||
|
||||
while (allocated < (p - document + len + 200
|
||||
+ (hex_enc_build_id != NULL
|
||||
? strlen (hex_enc_build_id) : 0)))
|
||||
while (allocated < p - document + len + 200)
|
||||
{
|
||||
/* Expand to guarantee sufficient storage. */
|
||||
uintptr_t document_len = p - document;
|
||||
|
@ -6720,13 +6399,9 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
|
|||
|
||||
name = xml_escape_text ((char *) libname);
|
||||
p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
|
||||
"l_addr=\"0x%lx\" l_ld=\"0x%lx\"",
|
||||
"l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
|
||||
name, (unsigned long) lm_addr,
|
||||
(unsigned long) l_addr, (unsigned long) l_ld);
|
||||
if (hex_enc_build_id != NULL
|
||||
&& strcmp (hex_enc_build_id, BUILD_ID_INVALID) != 0)
|
||||
p += sprintf (p, " build-id=\"%s\"", hex_enc_build_id);
|
||||
p += sprintf (p, "/>");
|
||||
free (name);
|
||||
}
|
||||
}
|
||||
|
@ -6753,7 +6428,6 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
|
|||
|
||||
memcpy (readbuf, document + offset, len);
|
||||
xfree (document);
|
||||
free_mapping_entry_vec (data.list);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
#include "server.h"
|
||||
#include "tracepoint.h"
|
||||
#include "target/target-utils.h"
|
||||
#include <fcntl.h>
|
||||
|
||||
struct target_ops *the_target;
|
||||
|
||||
|
@ -220,37 +218,3 @@ kill_inferior (int pid)
|
|||
|
||||
return (*the_target->kill) (pid);
|
||||
}
|
||||
|
||||
static int
|
||||
target_fileio_read_stralloc_1_pread (int handle, gdb_byte *read_buf, int len,
|
||||
ULONGEST offset, int *target_errno)
|
||||
{
|
||||
int retval = pread (handle, read_buf, len, offset);
|
||||
|
||||
*target_errno = errno;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static LONGEST
|
||||
target_fileio_read_stralloc_1 (struct inferior *inf, const char *filename,
|
||||
gdb_byte **buf_p, int padding)
|
||||
{
|
||||
int fd;
|
||||
LONGEST retval;
|
||||
|
||||
fd = open (filename, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
retval = read_alloc (buf_p, fd, target_fileio_read_stralloc_1_pread, padding);
|
||||
|
||||
close (fd);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
char *
|
||||
target_fileio_read_stralloc (struct inferior *inf, const char *filename)
|
||||
{
|
||||
return read_stralloc (inf, filename, target_fileio_read_stralloc_1);
|
||||
}
|
||||
|
|
570
gdb/linux-tdep.c
570
gdb/linux-tdep.c
|
@ -35,11 +35,56 @@
|
|||
#include "observer.h"
|
||||
#include "objfiles.h"
|
||||
#include "infcall.h"
|
||||
#include "nat/linux-maps.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "gdb_regex.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
/* This enum represents the values that the user can choose when
|
||||
informing the Linux kernel about which memory mappings will be
|
||||
dumped in a corefile. They are described in the file
|
||||
Documentation/filesystems/proc.txt, inside the Linux kernel
|
||||
tree. */
|
||||
|
||||
enum filterflags
|
||||
{
|
||||
COREFILTER_ANON_PRIVATE = 1 << 0,
|
||||
COREFILTER_ANON_SHARED = 1 << 1,
|
||||
COREFILTER_MAPPED_PRIVATE = 1 << 2,
|
||||
COREFILTER_MAPPED_SHARED = 1 << 3,
|
||||
COREFILTER_ELF_HEADERS = 1 << 4,
|
||||
COREFILTER_HUGETLB_PRIVATE = 1 << 5,
|
||||
COREFILTER_HUGETLB_SHARED = 1 << 6,
|
||||
};
|
||||
|
||||
/* This struct is used to map flags found in the "VmFlags:" field (in
|
||||
the /proc/<PID>/smaps file). */
|
||||
|
||||
struct smaps_vmflags
|
||||
{
|
||||
/* Zero if this structure has not been initialized yet. It
|
||||
probably means that the Linux kernel being used does not emit
|
||||
the "VmFlags:" field on "/proc/PID/smaps". */
|
||||
|
||||
unsigned int initialized_p : 1;
|
||||
|
||||
/* Memory mapped I/O area (VM_IO, "io"). */
|
||||
|
||||
unsigned int io_page : 1;
|
||||
|
||||
/* Area uses huge TLB pages (VM_HUGETLB, "ht"). */
|
||||
|
||||
unsigned int uses_huge_tlb : 1;
|
||||
|
||||
/* Do not include this memory region on the coredump (VM_DONTDUMP, "dd"). */
|
||||
|
||||
unsigned int exclude_coredump : 1;
|
||||
|
||||
/* Is this a MAP_SHARED mapping (VM_SHARED, "sh"). */
|
||||
|
||||
unsigned int shared_mapping : 1;
|
||||
};
|
||||
|
||||
/* Whether to take the /proc/PID/coredump_filter into account when
|
||||
generating a corefile. */
|
||||
|
||||
|
@ -350,6 +395,286 @@ linux_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid)
|
|||
return normal_pid_to_str (ptid);
|
||||
}
|
||||
|
||||
/* Service function for corefiles and info proc. */
|
||||
|
||||
static void
|
||||
read_mapping (const char *line,
|
||||
ULONGEST *addr, ULONGEST *endaddr,
|
||||
const char **permissions, size_t *permissions_len,
|
||||
ULONGEST *offset,
|
||||
const char **device, size_t *device_len,
|
||||
ULONGEST *inode,
|
||||
const char **filename)
|
||||
{
|
||||
const char *p = line;
|
||||
|
||||
*addr = strtoulst (p, &p, 16);
|
||||
if (*p == '-')
|
||||
p++;
|
||||
*endaddr = strtoulst (p, &p, 16);
|
||||
|
||||
p = skip_spaces_const (p);
|
||||
*permissions = p;
|
||||
while (*p && !isspace (*p))
|
||||
p++;
|
||||
*permissions_len = p - *permissions;
|
||||
|
||||
*offset = strtoulst (p, &p, 16);
|
||||
|
||||
p = skip_spaces_const (p);
|
||||
*device = p;
|
||||
while (*p && !isspace (*p))
|
||||
p++;
|
||||
*device_len = p - *device;
|
||||
|
||||
*inode = strtoulst (p, &p, 10);
|
||||
|
||||
p = skip_spaces_const (p);
|
||||
*filename = p;
|
||||
}
|
||||
|
||||
/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
|
||||
|
||||
This function was based on the documentation found on
|
||||
<Documentation/filesystems/proc.txt>, on the Linux kernel.
|
||||
|
||||
Linux kernels before commit
|
||||
834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have this
|
||||
field on smaps. */
|
||||
|
||||
static void
|
||||
decode_vmflags (char *p, struct smaps_vmflags *v)
|
||||
{
|
||||
char *saveptr = NULL;
|
||||
const char *s;
|
||||
|
||||
v->initialized_p = 1;
|
||||
p = skip_to_space (p);
|
||||
p = skip_spaces (p);
|
||||
|
||||
for (s = strtok_r (p, " ", &saveptr);
|
||||
s != NULL;
|
||||
s = strtok_r (NULL, " ", &saveptr))
|
||||
{
|
||||
if (strcmp (s, "io") == 0)
|
||||
v->io_page = 1;
|
||||
else if (strcmp (s, "ht") == 0)
|
||||
v->uses_huge_tlb = 1;
|
||||
else if (strcmp (s, "dd") == 0)
|
||||
v->exclude_coredump = 1;
|
||||
else if (strcmp (s, "sh") == 0)
|
||||
v->shared_mapping = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return 1 if the memory mapping is anonymous, 0 otherwise.
|
||||
|
||||
FILENAME is the name of the file present in the first line of the
|
||||
memory mapping, in the "/proc/PID/smaps" output. For example, if
|
||||
the first line is:
|
||||
|
||||
7fd0ca877000-7fd0d0da0000 r--p 00000000 fd:02 2100770 /path/to/file
|
||||
|
||||
Then FILENAME will be "/path/to/file". */
|
||||
|
||||
static int
|
||||
mapping_is_anonymous_p (const char *filename)
|
||||
{
|
||||
static regex_t dev_zero_regex, shmem_file_regex, file_deleted_regex;
|
||||
static int init_regex_p = 0;
|
||||
|
||||
if (!init_regex_p)
|
||||
{
|
||||
struct cleanup *c = make_cleanup (null_cleanup, NULL);
|
||||
|
||||
/* Let's be pessimistic and assume there will be an error while
|
||||
compiling the regex'es. */
|
||||
init_regex_p = -1;
|
||||
|
||||
/* DEV_ZERO_REGEX matches "/dev/zero" filenames (with or
|
||||
without the "(deleted)" string in the end). We know for
|
||||
sure, based on the Linux kernel code, that memory mappings
|
||||
whose associated filename is "/dev/zero" are guaranteed to be
|
||||
MAP_ANONYMOUS. */
|
||||
compile_rx_or_error (&dev_zero_regex, "^/dev/zero\\( (deleted)\\)\\?$",
|
||||
_("Could not compile regex to match /dev/zero "
|
||||
"filename"));
|
||||
/* SHMEM_FILE_REGEX matches "/SYSV%08x" filenames (with or
|
||||
without the "(deleted)" string in the end). These filenames
|
||||
refer to shared memory (shmem), and memory mappings
|
||||
associated with them are MAP_ANONYMOUS as well. */
|
||||
compile_rx_or_error (&shmem_file_regex,
|
||||
"^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$",
|
||||
_("Could not compile regex to match shmem "
|
||||
"filenames"));
|
||||
/* FILE_DELETED_REGEX is a heuristic we use to try to mimic the
|
||||
Linux kernel's 'n_link == 0' code, which is responsible to
|
||||
decide if it is dealing with a 'MAP_SHARED | MAP_ANONYMOUS'
|
||||
mapping. In other words, if FILE_DELETED_REGEX matches, it
|
||||
does not necessarily mean that we are dealing with an
|
||||
anonymous shared mapping. However, there is no easy way to
|
||||
detect this currently, so this is the best approximation we
|
||||
have.
|
||||
|
||||
As a result, GDB will dump readonly pages of deleted
|
||||
executables when using the default value of coredump_filter
|
||||
(0x33), while the Linux kernel will not dump those pages.
|
||||
But we can live with that. */
|
||||
compile_rx_or_error (&file_deleted_regex, " (deleted)$",
|
||||
_("Could not compile regex to match "
|
||||
"'<file> (deleted)'"));
|
||||
/* We will never release these regexes, so just discard the
|
||||
cleanups. */
|
||||
discard_cleanups (c);
|
||||
|
||||
/* If we reached this point, then everything succeeded. */
|
||||
init_regex_p = 1;
|
||||
}
|
||||
|
||||
if (init_regex_p == -1)
|
||||
{
|
||||
const char deleted[] = " (deleted)";
|
||||
size_t del_len = sizeof (deleted) - 1;
|
||||
size_t filename_len = strlen (filename);
|
||||
|
||||
/* There was an error while compiling the regex'es above. In
|
||||
order to try to give some reliable information to the caller,
|
||||
we just try to find the string " (deleted)" in the filename.
|
||||
If we managed to find it, then we assume the mapping is
|
||||
anonymous. */
|
||||
return (filename_len >= del_len
|
||||
&& strcmp (filename + filename_len - del_len, deleted) == 0);
|
||||
}
|
||||
|
||||
if (*filename == '\0'
|
||||
|| regexec (&dev_zero_regex, filename, 0, NULL, 0) == 0
|
||||
|| regexec (&shmem_file_regex, filename, 0, NULL, 0) == 0
|
||||
|| regexec (&file_deleted_regex, filename, 0, NULL, 0) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
|
||||
MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
|
||||
greater than 0 if it should.
|
||||
|
||||
In a nutshell, this is the logic that we follow in order to decide
|
||||
if a mapping should be dumped or not.
|
||||
|
||||
- If the mapping is associated to a file whose name ends with
|
||||
" (deleted)", or if the file is "/dev/zero", or if it is
|
||||
"/SYSV%08x" (shared memory), or if there is no file associated
|
||||
with it, or if the AnonHugePages: or the Anonymous: fields in the
|
||||
/proc/PID/smaps have contents, then GDB considers this mapping to
|
||||
be anonymous. Otherwise, GDB considers this mapping to be a
|
||||
file-backed mapping (because there will be a file associated with
|
||||
it).
|
||||
|
||||
It is worth mentioning that, from all those checks described
|
||||
above, the most fragile is the one to see if the file name ends
|
||||
with " (deleted)". This does not necessarily mean that the
|
||||
mapping is anonymous, because the deleted file associated with
|
||||
the mapping may have been a hard link to another file, for
|
||||
example. The Linux kernel checks to see if "i_nlink == 0", but
|
||||
GDB cannot easily (and normally) do this check (iff running as
|
||||
root, it could find the mapping in /proc/PID/map_files/ and
|
||||
determine whether there still are other hard links to the
|
||||
inode/file). Therefore, we made a compromise here, and we assume
|
||||
that if the file name ends with " (deleted)", then the mapping is
|
||||
indeed anonymous. FWIW, this is something the Linux kernel could
|
||||
do better: expose this information in a more direct way.
|
||||
|
||||
- If we see the flag "sh" in the "VmFlags:" field (in
|
||||
/proc/PID/smaps), then certainly the memory mapping is shared
|
||||
(VM_SHARED). If we have access to the VmFlags, and we don't see
|
||||
the "sh" there, then certainly the mapping is private. However,
|
||||
Linux kernels before commit
|
||||
834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have the
|
||||
"VmFlags:" field; in that case, we use another heuristic: if we
|
||||
see 'p' in the permission flags, then we assume that the mapping
|
||||
is private, even though the presence of the 's' flag there would
|
||||
mean VM_MAYSHARE, which means the mapping could still be private.
|
||||
This should work OK enough, however. */
|
||||
|
||||
static int
|
||||
dump_mapping_p (enum filterflags filterflags, const struct smaps_vmflags *v,
|
||||
int maybe_private_p, int mapping_anon_p, int mapping_file_p,
|
||||
const char *filename)
|
||||
{
|
||||
/* Initially, we trust in what we received from our caller. This
|
||||
value may not be very precise (i.e., it was probably gathered
|
||||
from the permission line in the /proc/PID/smaps list, which
|
||||
actually refers to VM_MAYSHARE, and not VM_SHARED), but it is
|
||||
what we have until we take a look at the "VmFlags:" field
|
||||
(assuming that the version of the Linux kernel being used
|
||||
supports it, of course). */
|
||||
int private_p = maybe_private_p;
|
||||
|
||||
/* We always dump vDSO and vsyscall mappings, because it's likely that
|
||||
there'll be no file to read the contents from at core load time.
|
||||
The kernel does the same. */
|
||||
if (strcmp ("[vdso]", filename) == 0
|
||||
|| strcmp ("[vsyscall]", filename) == 0)
|
||||
return 1;
|
||||
|
||||
if (v->initialized_p)
|
||||
{
|
||||
/* We never dump I/O mappings. */
|
||||
if (v->io_page)
|
||||
return 0;
|
||||
|
||||
/* Check if we should exclude this mapping. */
|
||||
if (v->exclude_coredump)
|
||||
return 0;
|
||||
|
||||
/* Update our notion of whether this mapping is shared or
|
||||
private based on a trustworthy value. */
|
||||
private_p = !v->shared_mapping;
|
||||
|
||||
/* HugeTLB checking. */
|
||||
if (v->uses_huge_tlb)
|
||||
{
|
||||
if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
|
||||
|| (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (private_p)
|
||||
{
|
||||
if (mapping_anon_p && mapping_file_p)
|
||||
{
|
||||
/* This is a special situation. It can happen when we see a
|
||||
mapping that is file-backed, but that contains anonymous
|
||||
pages. */
|
||||
return ((filterflags & COREFILTER_ANON_PRIVATE) != 0
|
||||
|| (filterflags & COREFILTER_MAPPED_PRIVATE) != 0);
|
||||
}
|
||||
else if (mapping_anon_p)
|
||||
return (filterflags & COREFILTER_ANON_PRIVATE) != 0;
|
||||
else
|
||||
return (filterflags & COREFILTER_MAPPED_PRIVATE) != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mapping_anon_p && mapping_file_p)
|
||||
{
|
||||
/* This is a special situation. It can happen when we see a
|
||||
mapping that is file-backed, but that contains anonymous
|
||||
pages. */
|
||||
return ((filterflags & COREFILTER_ANON_SHARED) != 0
|
||||
|| (filterflags & COREFILTER_MAPPED_SHARED) != 0);
|
||||
}
|
||||
else if (mapping_anon_p)
|
||||
return (filterflags & COREFILTER_ANON_SHARED) != 0;
|
||||
else
|
||||
return (filterflags & COREFILTER_MAPPED_SHARED) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Implement the "info proc" command. */
|
||||
|
||||
static void
|
||||
|
@ -773,6 +1098,191 @@ linux_core_info_proc (struct gdbarch *gdbarch, const char *args,
|
|||
error (_("unable to handle request"));
|
||||
}
|
||||
|
||||
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
|
||||
ULONGEST offset, ULONGEST inode,
|
||||
int read, int write,
|
||||
int exec, int modified,
|
||||
const char *filename,
|
||||
void *data);
|
||||
|
||||
/* List memory regions in the inferior for a corefile. */
|
||||
|
||||
static int
|
||||
linux_find_memory_regions_full (struct gdbarch *gdbarch,
|
||||
linux_find_memory_region_ftype *func,
|
||||
void *obfd)
|
||||
{
|
||||
char mapsfilename[100];
|
||||
char coredumpfilter_name[100];
|
||||
char *data, *coredumpfilterdata;
|
||||
pid_t pid;
|
||||
/* Default dump behavior of coredump_filter (0x33), according to
|
||||
Documentation/filesystems/proc.txt from the Linux kernel
|
||||
tree. */
|
||||
enum filterflags filterflags = (COREFILTER_ANON_PRIVATE
|
||||
| COREFILTER_ANON_SHARED
|
||||
| COREFILTER_ELF_HEADERS
|
||||
| COREFILTER_HUGETLB_PRIVATE);
|
||||
|
||||
/* We need to know the real target PID to access /proc. */
|
||||
if (current_inferior ()->fake_pid_p)
|
||||
return 1;
|
||||
|
||||
pid = current_inferior ()->pid;
|
||||
|
||||
if (use_coredump_filter)
|
||||
{
|
||||
xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
|
||||
"/proc/%d/coredump_filter", pid);
|
||||
coredumpfilterdata = target_fileio_read_stralloc (NULL,
|
||||
coredumpfilter_name);
|
||||
if (coredumpfilterdata != NULL)
|
||||
{
|
||||
sscanf (coredumpfilterdata, "%x", &filterflags);
|
||||
xfree (coredumpfilterdata);
|
||||
}
|
||||
}
|
||||
|
||||
xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
|
||||
data = target_fileio_read_stralloc (NULL, mapsfilename);
|
||||
if (data == NULL)
|
||||
{
|
||||
/* Older Linux kernels did not support /proc/PID/smaps. */
|
||||
xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
|
||||
data = target_fileio_read_stralloc (NULL, mapsfilename);
|
||||
}
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
struct cleanup *cleanup = make_cleanup (xfree, data);
|
||||
char *line, *t;
|
||||
|
||||
line = strtok_r (data, "\n", &t);
|
||||
while (line != NULL)
|
||||
{
|
||||
ULONGEST addr, endaddr, offset, inode;
|
||||
const char *permissions, *device, *filename;
|
||||
struct smaps_vmflags v;
|
||||
size_t permissions_len, device_len;
|
||||
int read, write, exec, priv;
|
||||
int has_anonymous = 0;
|
||||
int should_dump_p = 0;
|
||||
int mapping_anon_p;
|
||||
int mapping_file_p;
|
||||
|
||||
memset (&v, 0, sizeof (v));
|
||||
read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
|
||||
&offset, &device, &device_len, &inode, &filename);
|
||||
mapping_anon_p = mapping_is_anonymous_p (filename);
|
||||
/* If the mapping is not anonymous, then we can consider it
|
||||
to be file-backed. These two states (anonymous or
|
||||
file-backed) seem to be exclusive, but they can actually
|
||||
coexist. For example, if a file-backed mapping has
|
||||
"Anonymous:" pages (see more below), then the Linux
|
||||
kernel will dump this mapping when the user specified
|
||||
that she only wants anonymous mappings in the corefile
|
||||
(*even* when she explicitly disabled the dumping of
|
||||
file-backed mappings). */
|
||||
mapping_file_p = !mapping_anon_p;
|
||||
|
||||
/* Decode permissions. */
|
||||
read = (memchr (permissions, 'r', permissions_len) != 0);
|
||||
write = (memchr (permissions, 'w', permissions_len) != 0);
|
||||
exec = (memchr (permissions, 'x', permissions_len) != 0);
|
||||
/* 'private' here actually means VM_MAYSHARE, and not
|
||||
VM_SHARED. In order to know if a mapping is really
|
||||
private or not, we must check the flag "sh" in the
|
||||
VmFlags field. This is done by decode_vmflags. However,
|
||||
if we are using a Linux kernel released before the commit
|
||||
834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
|
||||
not have the VmFlags there. In this case, there is
|
||||
really no way to know if we are dealing with VM_SHARED,
|
||||
so we just assume that VM_MAYSHARE is enough. */
|
||||
priv = memchr (permissions, 'p', permissions_len) != 0;
|
||||
|
||||
/* Try to detect if region should be dumped by parsing smaps
|
||||
counters. */
|
||||
for (line = strtok_r (NULL, "\n", &t);
|
||||
line != NULL && line[0] >= 'A' && line[0] <= 'Z';
|
||||
line = strtok_r (NULL, "\n", &t))
|
||||
{
|
||||
char keyword[64 + 1];
|
||||
|
||||
if (sscanf (line, "%64s", keyword) != 1)
|
||||
{
|
||||
warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp (keyword, "Anonymous:") == 0)
|
||||
{
|
||||
/* Older Linux kernels did not support the
|
||||
"Anonymous:" counter. Check it here. */
|
||||
has_anonymous = 1;
|
||||
}
|
||||
else if (strcmp (keyword, "VmFlags:") == 0)
|
||||
decode_vmflags (line, &v);
|
||||
|
||||
if (strcmp (keyword, "AnonHugePages:") == 0
|
||||
|| strcmp (keyword, "Anonymous:") == 0)
|
||||
{
|
||||
unsigned long number;
|
||||
|
||||
if (sscanf (line, "%*s%lu", &number) != 1)
|
||||
{
|
||||
warning (_("Error parsing {s,}maps file '%s' number"),
|
||||
mapsfilename);
|
||||
break;
|
||||
}
|
||||
if (number > 0)
|
||||
{
|
||||
/* Even if we are dealing with a file-backed
|
||||
mapping, if it contains anonymous pages we
|
||||
consider it to be *also* an anonymous
|
||||
mapping, because this is what the Linux
|
||||
kernel does:
|
||||
|
||||
// Dump segments that have been written to.
|
||||
if (vma->anon_vma && FILTER(ANON_PRIVATE))
|
||||
goto whole;
|
||||
|
||||
Note that if the mapping is already marked as
|
||||
file-backed (i.e., mapping_file_p is
|
||||
non-zero), then this is a special case, and
|
||||
this mapping will be dumped either when the
|
||||
user wants to dump file-backed *or* anonymous
|
||||
mappings. */
|
||||
mapping_anon_p = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_anonymous)
|
||||
should_dump_p = dump_mapping_p (filterflags, &v, priv,
|
||||
mapping_anon_p, mapping_file_p,
|
||||
filename);
|
||||
else
|
||||
{
|
||||
/* Older Linux kernels did not support the "Anonymous:" counter.
|
||||
If it is missing, we can't be sure - dump all the pages. */
|
||||
should_dump_p = 1;
|
||||
}
|
||||
|
||||
/* Invoke the callback function to create the corefile segment. */
|
||||
if (should_dump_p)
|
||||
func (addr, endaddr - addr, offset, inode,
|
||||
read, write, exec, 1, /* MODIFIED is true because we
|
||||
want to dump the mapping. */
|
||||
filename, obfd);
|
||||
}
|
||||
|
||||
do_cleanups (cleanup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* A structure for passing information through
|
||||
linux_find_memory_regions_full. */
|
||||
|
||||
|
@ -784,7 +1294,7 @@ struct linux_find_memory_regions_data
|
|||
|
||||
/* The original datum. */
|
||||
|
||||
void *data;
|
||||
void *obfd;
|
||||
};
|
||||
|
||||
/* A callback for linux_find_memory_regions that converts between the
|
||||
|
@ -798,48 +1308,7 @@ linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
|
|||
{
|
||||
struct linux_find_memory_regions_data *data = arg;
|
||||
|
||||
return data->func (vaddr, size, read, write, exec, modified, data->data);
|
||||
}
|
||||
|
||||
/* Wrapper of linux_find_memory_regions_full handling FAKE_PID_P in GDB. */
|
||||
|
||||
static int
|
||||
linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
|
||||
linux_find_memory_region_ftype *func,
|
||||
void *func_data)
|
||||
{
|
||||
pid_t pid;
|
||||
/* Default dump behavior of coredump_filter (0x33), according to
|
||||
Documentation/filesystems/proc.txt from the Linux kernel
|
||||
tree. */
|
||||
enum filterflags filterflags = (COREFILTER_ANON_PRIVATE
|
||||
| COREFILTER_ANON_SHARED
|
||||
| COREFILTER_ELF_HEADERS
|
||||
| COREFILTER_HUGETLB_PRIVATE);
|
||||
|
||||
/* We need to know the real target PID so
|
||||
linux_find_memory_regions_full can access /proc. */
|
||||
if (current_inferior ()->fake_pid_p)
|
||||
return -1;
|
||||
|
||||
pid = current_inferior ()->pid;
|
||||
|
||||
if (use_coredump_filter)
|
||||
{
|
||||
char coredumpfilter_name[100], *coredumpfilterdata;
|
||||
|
||||
xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
|
||||
"/proc/%d/coredump_filter", pid);
|
||||
coredumpfilterdata = target_fileio_read_stralloc (NULL,
|
||||
coredumpfilter_name);
|
||||
if (coredumpfilterdata != NULL)
|
||||
{
|
||||
sscanf (coredumpfilterdata, "%x", &filterflags);
|
||||
xfree (coredumpfilterdata);
|
||||
}
|
||||
}
|
||||
|
||||
return linux_find_memory_regions_full (pid, filterflags, func, func_data);
|
||||
return data->func (vaddr, size, read, write, exec, modified, data->obfd);
|
||||
}
|
||||
|
||||
/* A variant of linux_find_memory_regions_full that is suitable as the
|
||||
|
@ -847,15 +1316,16 @@ linux_find_memory_regions_gdb (struct gdbarch *gdbarch,
|
|||
|
||||
static int
|
||||
linux_find_memory_regions (struct gdbarch *gdbarch,
|
||||
find_memory_region_ftype func, void *func_data)
|
||||
find_memory_region_ftype func, void *obfd)
|
||||
{
|
||||
struct linux_find_memory_regions_data data;
|
||||
|
||||
data.func = func;
|
||||
data.data = func_data;
|
||||
data.obfd = obfd;
|
||||
|
||||
return linux_find_memory_regions_gdb (gdbarch,
|
||||
linux_find_memory_regions_thunk, &data);
|
||||
return linux_find_memory_regions_full (gdbarch,
|
||||
linux_find_memory_regions_thunk,
|
||||
&data);
|
||||
}
|
||||
|
||||
/* Determine which signal stopped execution. */
|
||||
|
@ -1037,8 +1507,8 @@ linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd,
|
|||
pack_long (buf, long_type, 1);
|
||||
obstack_grow (&data_obstack, buf, TYPE_LENGTH (long_type));
|
||||
|
||||
linux_find_memory_regions_gdb (gdbarch, linux_make_mappings_callback,
|
||||
&mapping_data);
|
||||
linux_find_memory_regions_full (gdbarch, linux_make_mappings_callback,
|
||||
&mapping_data);
|
||||
|
||||
if (mapping_data.file_count != 0)
|
||||
{
|
||||
|
|
|
@ -1,493 +0,0 @@
|
|||
/* Linux-specific memory maps manipulation routines.
|
||||
Copyright (C) 2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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 "common-defs.h"
|
||||
#include "linux-maps.h"
|
||||
#include <ctype.h>
|
||||
#include "target/target-utils.h"
|
||||
#include "gdb_regex.h"
|
||||
#include "target/target.h"
|
||||
|
||||
/* This struct is used to map flags found in the "VmFlags:" field (in
|
||||
the /proc/<PID>/smaps file). */
|
||||
|
||||
struct smaps_vmflags
|
||||
{
|
||||
/* Zero if this structure has not been initialized yet. It
|
||||
probably means that the Linux kernel being used does not emit
|
||||
the "VmFlags:" field on "/proc/PID/smaps". */
|
||||
|
||||
unsigned int initialized_p : 1;
|
||||
|
||||
/* Memory mapped I/O area (VM_IO, "io"). */
|
||||
|
||||
unsigned int io_page : 1;
|
||||
|
||||
/* Area uses huge TLB pages (VM_HUGETLB, "ht"). */
|
||||
|
||||
unsigned int uses_huge_tlb : 1;
|
||||
|
||||
/* Do not include this memory region on the coredump (VM_DONTDUMP, "dd"). */
|
||||
|
||||
unsigned int exclude_coredump : 1;
|
||||
|
||||
/* Is this a MAP_SHARED mapping (VM_SHARED, "sh"). */
|
||||
|
||||
unsigned int shared_mapping : 1;
|
||||
};
|
||||
|
||||
/* Service function for corefiles and info proc. */
|
||||
|
||||
void
|
||||
read_mapping (const char *line,
|
||||
ULONGEST *addr, ULONGEST *endaddr,
|
||||
const char **permissions, size_t *permissions_len,
|
||||
ULONGEST *offset,
|
||||
const char **device, size_t *device_len,
|
||||
ULONGEST *inode,
|
||||
const char **filename)
|
||||
{
|
||||
const char *p = line;
|
||||
|
||||
*addr = strtoulst (p, &p, 16);
|
||||
if (*p == '-')
|
||||
p++;
|
||||
*endaddr = strtoulst (p, &p, 16);
|
||||
|
||||
p = skip_spaces_const (p);
|
||||
*permissions = p;
|
||||
while (*p && !isspace (*p))
|
||||
p++;
|
||||
*permissions_len = p - *permissions;
|
||||
|
||||
*offset = strtoulst (p, &p, 16);
|
||||
|
||||
p = skip_spaces_const (p);
|
||||
*device = p;
|
||||
while (*p && !isspace (*p))
|
||||
p++;
|
||||
*device_len = p - *device;
|
||||
|
||||
*inode = strtoulst (p, &p, 10);
|
||||
|
||||
p = skip_spaces_const (p);
|
||||
*filename = p;
|
||||
}
|
||||
|
||||
/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
|
||||
|
||||
This function was based on the documentation found on
|
||||
<Documentation/filesystems/proc.txt>, on the Linux kernel.
|
||||
|
||||
Linux kernels before commit
|
||||
834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have this
|
||||
field on smaps. */
|
||||
|
||||
static void
|
||||
decode_vmflags (char *p, struct smaps_vmflags *v)
|
||||
{
|
||||
char *saveptr = NULL;
|
||||
const char *s;
|
||||
|
||||
v->initialized_p = 1;
|
||||
p = skip_to_space (p);
|
||||
p = skip_spaces (p);
|
||||
|
||||
for (s = strtok_r (p, " ", &saveptr);
|
||||
s != NULL;
|
||||
s = strtok_r (NULL, " ", &saveptr))
|
||||
{
|
||||
if (strcmp (s, "io") == 0)
|
||||
v->io_page = 1;
|
||||
else if (strcmp (s, "ht") == 0)
|
||||
v->uses_huge_tlb = 1;
|
||||
else if (strcmp (s, "dd") == 0)
|
||||
v->exclude_coredump = 1;
|
||||
else if (strcmp (s, "sh") == 0)
|
||||
v->shared_mapping = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return 1 if the memory mapping is anonymous, 0 otherwise.
|
||||
|
||||
FILENAME is the name of the file present in the first line of the
|
||||
memory mapping, in the "/proc/PID/smaps" output. For example, if
|
||||
the first line is:
|
||||
|
||||
7fd0ca877000-7fd0d0da0000 r--p 00000000 fd:02 2100770 /path/to/file
|
||||
|
||||
Then FILENAME will be "/path/to/file". */
|
||||
|
||||
static int
|
||||
mapping_is_anonymous_p (const char *filename)
|
||||
{
|
||||
static regex_t dev_zero_regex, shmem_file_regex, file_deleted_regex;
|
||||
static int init_regex_p = 0;
|
||||
|
||||
if (!init_regex_p)
|
||||
{
|
||||
struct cleanup *c = make_cleanup (null_cleanup, NULL);
|
||||
|
||||
/* Let's be pessimistic and assume there will be an error while
|
||||
compiling the regex'es. */
|
||||
init_regex_p = -1;
|
||||
|
||||
/* DEV_ZERO_REGEX matches "/dev/zero" filenames (with or
|
||||
without the "(deleted)" string in the end). We know for
|
||||
sure, based on the Linux kernel code, that memory mappings
|
||||
whose associated filename is "/dev/zero" are guaranteed to be
|
||||
MAP_ANONYMOUS. */
|
||||
compile_rx_or_error (&dev_zero_regex, "^/dev/zero\\( (deleted)\\)\\?$",
|
||||
_("Could not compile regex to match /dev/zero "
|
||||
"filename"));
|
||||
/* SHMEM_FILE_REGEX matches "/SYSV%08x" filenames (with or
|
||||
without the "(deleted)" string in the end). These filenames
|
||||
refer to shared memory (shmem), and memory mappings
|
||||
associated with them are MAP_ANONYMOUS as well. */
|
||||
compile_rx_or_error (&shmem_file_regex,
|
||||
"^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$",
|
||||
_("Could not compile regex to match shmem "
|
||||
"filenames"));
|
||||
/* FILE_DELETED_REGEX is a heuristic we use to try to mimic the
|
||||
Linux kernel's 'n_link == 0' code, which is responsible to
|
||||
decide if it is dealing with a 'MAP_SHARED | MAP_ANONYMOUS'
|
||||
mapping. In other words, if FILE_DELETED_REGEX matches, it
|
||||
does not necessarily mean that we are dealing with an
|
||||
anonymous shared mapping. However, there is no easy way to
|
||||
detect this currently, so this is the best approximation we
|
||||
have.
|
||||
|
||||
As a result, GDB will dump readonly pages of deleted
|
||||
executables when using the default value of coredump_filter
|
||||
(0x33), while the Linux kernel will not dump those pages.
|
||||
But we can live with that. */
|
||||
compile_rx_or_error (&file_deleted_regex, " (deleted)$",
|
||||
_("Could not compile regex to match "
|
||||
"'<file> (deleted)'"));
|
||||
/* We will never release these regexes, so just discard the
|
||||
cleanups. */
|
||||
discard_cleanups (c);
|
||||
|
||||
/* If we reached this point, then everything succeeded. */
|
||||
init_regex_p = 1;
|
||||
}
|
||||
|
||||
if (init_regex_p == -1)
|
||||
{
|
||||
const char deleted[] = " (deleted)";
|
||||
size_t del_len = sizeof (deleted) - 1;
|
||||
size_t filename_len = strlen (filename);
|
||||
|
||||
/* There was an error while compiling the regex'es above. In
|
||||
order to try to give some reliable information to the caller,
|
||||
we just try to find the string " (deleted)" in the filename.
|
||||
If we managed to find it, then we assume the mapping is
|
||||
anonymous. */
|
||||
return (filename_len >= del_len
|
||||
&& strcmp (filename + filename_len - del_len, deleted) == 0);
|
||||
}
|
||||
|
||||
if (*filename == '\0'
|
||||
|| regexec (&dev_zero_regex, filename, 0, NULL, 0) == 0
|
||||
|| regexec (&shmem_file_regex, filename, 0, NULL, 0) == 0
|
||||
|| regexec (&file_deleted_regex, filename, 0, NULL, 0) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
|
||||
MAYBE_PRIVATE_P, and MAPPING_ANONYMOUS_P) should not be dumped, or
|
||||
greater than 0 if it should.
|
||||
|
||||
In a nutshell, this is the logic that we follow in order to decide
|
||||
if a mapping should be dumped or not.
|
||||
|
||||
- If the mapping is associated to a file whose name ends with
|
||||
" (deleted)", or if the file is "/dev/zero", or if it is
|
||||
"/SYSV%08x" (shared memory), or if there is no file associated
|
||||
with it, or if the AnonHugePages: or the Anonymous: fields in the
|
||||
/proc/PID/smaps have contents, then GDB considers this mapping to
|
||||
be anonymous. Otherwise, GDB considers this mapping to be a
|
||||
file-backed mapping (because there will be a file associated with
|
||||
it).
|
||||
|
||||
It is worth mentioning that, from all those checks described
|
||||
above, the most fragile is the one to see if the file name ends
|
||||
with " (deleted)". This does not necessarily mean that the
|
||||
mapping is anonymous, because the deleted file associated with
|
||||
the mapping may have been a hard link to another file, for
|
||||
example. The Linux kernel checks to see if "i_nlink == 0", but
|
||||
GDB cannot easily (and normally) do this check (iff running as
|
||||
root, it could find the mapping in /proc/PID/map_files/ and
|
||||
determine whether there still are other hard links to the
|
||||
inode/file). Therefore, we made a compromise here, and we assume
|
||||
that if the file name ends with " (deleted)", then the mapping is
|
||||
indeed anonymous. FWIW, this is something the Linux kernel could
|
||||
do better: expose this information in a more direct way.
|
||||
|
||||
- If we see the flag "sh" in the "VmFlags:" field (in
|
||||
/proc/PID/smaps), then certainly the memory mapping is shared
|
||||
(VM_SHARED). If we have access to the VmFlags, and we don't see
|
||||
the "sh" there, then certainly the mapping is private. However,
|
||||
Linux kernels before commit
|
||||
834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have the
|
||||
"VmFlags:" field; in that case, we use another heuristic: if we
|
||||
see 'p' in the permission flags, then we assume that the mapping
|
||||
is private, even though the presence of the 's' flag there would
|
||||
mean VM_MAYSHARE, which means the mapping could still be private.
|
||||
This should work OK enough, however. */
|
||||
|
||||
static int
|
||||
dump_mapping_p (enum filterflags filterflags, const struct smaps_vmflags *v,
|
||||
int maybe_private_p, int mapping_anon_p, int mapping_file_p,
|
||||
const char *filename)
|
||||
{
|
||||
/* Initially, we trust in what we received from our caller. This
|
||||
value may not be very precise (i.e., it was probably gathered
|
||||
from the permission line in the /proc/PID/smaps list, which
|
||||
actually refers to VM_MAYSHARE, and not VM_SHARED), but it is
|
||||
what we have until we take a look at the "VmFlags:" field
|
||||
(assuming that the version of the Linux kernel being used
|
||||
supports it, of course). */
|
||||
int private_p = maybe_private_p;
|
||||
|
||||
/* We always dump vDSO and vsyscall mappings, because it's likely that
|
||||
there'll be no file to read the contents from at core load time.
|
||||
The kernel does the same. */
|
||||
if (strcmp ("[vdso]", filename) == 0
|
||||
|| strcmp ("[vsyscall]", filename) == 0)
|
||||
return 1;
|
||||
|
||||
if (v->initialized_p)
|
||||
{
|
||||
/* We never dump I/O mappings. */
|
||||
if (v->io_page)
|
||||
return 0;
|
||||
|
||||
/* Check if we should exclude this mapping. */
|
||||
if (v->exclude_coredump)
|
||||
return 0;
|
||||
|
||||
/* Update our notion of whether this mapping is shared or
|
||||
private based on a trustworthy value. */
|
||||
private_p = !v->shared_mapping;
|
||||
|
||||
/* HugeTLB checking. */
|
||||
if (v->uses_huge_tlb)
|
||||
{
|
||||
if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
|
||||
|| (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (private_p)
|
||||
{
|
||||
if (mapping_anon_p && mapping_file_p)
|
||||
{
|
||||
/* This is a special situation. It can happen when we see a
|
||||
mapping that is file-backed, but that contains anonymous
|
||||
pages. */
|
||||
return ((filterflags & COREFILTER_ANON_PRIVATE) != 0
|
||||
|| (filterflags & COREFILTER_MAPPED_PRIVATE) != 0);
|
||||
}
|
||||
else if (mapping_anon_p)
|
||||
return (filterflags & COREFILTER_ANON_PRIVATE) != 0;
|
||||
else
|
||||
return (filterflags & COREFILTER_MAPPED_PRIVATE) != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mapping_anon_p && mapping_file_p)
|
||||
{
|
||||
/* This is a special situation. It can happen when we see a
|
||||
mapping that is file-backed, but that contains anonymous
|
||||
pages. */
|
||||
return ((filterflags & COREFILTER_ANON_SHARED) != 0
|
||||
|| (filterflags & COREFILTER_MAPPED_SHARED) != 0);
|
||||
}
|
||||
else if (mapping_anon_p)
|
||||
return (filterflags & COREFILTER_ANON_SHARED) != 0;
|
||||
else
|
||||
return (filterflags & COREFILTER_MAPPED_SHARED) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* List memory regions in the inferior PID matched to FILTERFLAGS for
|
||||
a corefile. Call FUNC with FUNC_DATA for each such region. Return
|
||||
immediately with the value returned by FUNC if it is non-zero.
|
||||
*MEMORY_TO_FREE_PTR should be registered to be freed automatically if
|
||||
called FUNC throws an exception. MEMORY_TO_FREE_PTR can be also
|
||||
passed as NULL if it is not used. Return -1 if error occurs, 0 if
|
||||
all memory regions have been processed or return the value from FUNC
|
||||
if FUNC returns non-zero. */
|
||||
|
||||
int
|
||||
linux_find_memory_regions_full (pid_t pid, enum filterflags filterflags,
|
||||
linux_find_memory_region_ftype *func,
|
||||
void *func_data)
|
||||
{
|
||||
char mapsfilename[100];
|
||||
char *data;
|
||||
|
||||
xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
|
||||
data = target_fileio_read_stralloc (NULL, mapsfilename);
|
||||
if (data == NULL)
|
||||
{
|
||||
/* Older Linux kernels did not support /proc/PID/smaps. */
|
||||
xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
|
||||
data = target_fileio_read_stralloc (NULL, mapsfilename);
|
||||
}
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
struct cleanup *cleanup = make_cleanup (xfree, data);
|
||||
char *line, *t;
|
||||
int retval = 0;
|
||||
|
||||
line = strtok_r (data, "\n", &t);
|
||||
while (line != NULL)
|
||||
{
|
||||
ULONGEST addr, endaddr, offset, inode;
|
||||
const char *permissions, *device, *filename;
|
||||
struct smaps_vmflags v;
|
||||
size_t permissions_len, device_len;
|
||||
int read, write, exec, priv;
|
||||
int has_anonymous = 0;
|
||||
int should_dump_p = 0;
|
||||
int mapping_anon_p;
|
||||
int mapping_file_p;
|
||||
|
||||
memset (&v, 0, sizeof (v));
|
||||
read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
|
||||
&offset, &device, &device_len, &inode, &filename);
|
||||
mapping_anon_p = mapping_is_anonymous_p (filename);
|
||||
/* If the mapping is not anonymous, then we can consider it
|
||||
to be file-backed. These two states (anonymous or
|
||||
file-backed) seem to be exclusive, but they can actually
|
||||
coexist. For example, if a file-backed mapping has
|
||||
"Anonymous:" pages (see more below), then the Linux
|
||||
kernel will dump this mapping when the user specified
|
||||
that she only wants anonymous mappings in the corefile
|
||||
(*even* when she explicitly disabled the dumping of
|
||||
file-backed mappings). */
|
||||
mapping_file_p = !mapping_anon_p;
|
||||
|
||||
/* Decode permissions. */
|
||||
read = (memchr (permissions, 'r', permissions_len) != 0);
|
||||
write = (memchr (permissions, 'w', permissions_len) != 0);
|
||||
exec = (memchr (permissions, 'x', permissions_len) != 0);
|
||||
/* 'private' here actually means VM_MAYSHARE, and not
|
||||
VM_SHARED. In order to know if a mapping is really
|
||||
private or not, we must check the flag "sh" in the
|
||||
VmFlags field. This is done by decode_vmflags. However,
|
||||
if we are using a Linux kernel released before the commit
|
||||
834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
|
||||
not have the VmFlags there. In this case, there is
|
||||
really no way to know if we are dealing with VM_SHARED,
|
||||
so we just assume that VM_MAYSHARE is enough. */
|
||||
priv = memchr (permissions, 'p', permissions_len) != 0;
|
||||
|
||||
/* Try to detect if region should be dumped by parsing smaps
|
||||
counters. */
|
||||
for (line = strtok_r (NULL, "\n", &t);
|
||||
line != NULL && line[0] >= 'A' && line[0] <= 'Z';
|
||||
line = strtok_r (NULL, "\n", &t))
|
||||
{
|
||||
char keyword[64 + 1];
|
||||
|
||||
if (sscanf (line, "%64s", keyword) != 1)
|
||||
{
|
||||
warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp (keyword, "Anonymous:") == 0)
|
||||
{
|
||||
/* Older Linux kernels did not support the
|
||||
"Anonymous:" counter. Check it here. */
|
||||
has_anonymous = 1;
|
||||
}
|
||||
else if (strcmp (keyword, "VmFlags:") == 0)
|
||||
decode_vmflags (line, &v);
|
||||
|
||||
if (strcmp (keyword, "AnonHugePages:") == 0
|
||||
|| strcmp (keyword, "Anonymous:") == 0)
|
||||
{
|
||||
unsigned long number;
|
||||
|
||||
if (sscanf (line, "%*s%lu", &number) != 1)
|
||||
{
|
||||
warning (_("Error parsing {s,}maps file '%s' number"),
|
||||
mapsfilename);
|
||||
break;
|
||||
}
|
||||
if (number > 0)
|
||||
{
|
||||
/* Even if we are dealing with a file-backed
|
||||
mapping, if it contains anonymous pages we
|
||||
consider it to be *also* an anonymous
|
||||
mapping, because this is what the Linux
|
||||
kernel does:
|
||||
|
||||
// Dump segments that have been written to.
|
||||
if (vma->anon_vma && FILTER(ANON_PRIVATE))
|
||||
goto whole;
|
||||
|
||||
Note that if the mapping is already marked as
|
||||
file-backed (i.e., mapping_file_p is
|
||||
non-zero), then this is a special case, and
|
||||
this mapping will be dumped either when the
|
||||
user wants to dump file-backed *or* anonymous
|
||||
mappings. */
|
||||
mapping_anon_p = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_anonymous)
|
||||
should_dump_p = dump_mapping_p (filterflags, &v, priv,
|
||||
mapping_anon_p, mapping_file_p,
|
||||
filename);
|
||||
else
|
||||
{
|
||||
/* Older Linux kernels did not support the "Anonymous:" counter.
|
||||
If it is missing, we can't be sure - dump all the pages. */
|
||||
should_dump_p = 1;
|
||||
}
|
||||
|
||||
/* Invoke the callback function to create the corefile segment. */
|
||||
if (should_dump_p)
|
||||
retval = func (addr, endaddr - addr, offset, inode,
|
||||
read, write, exec,
|
||||
1, /* MODIFIED is true because we want to dump the
|
||||
mapping. */
|
||||
filename, func_data);
|
||||
if (retval != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
do_cleanups (cleanup);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/* Linux-specific memory maps manipulation routines.
|
||||
Copyright (C) 2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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/>. */
|
||||
|
||||
#ifndef NAT_LINUX_MAPS_H
|
||||
#define NAT_LINUX_MAPS_H
|
||||
|
||||
extern void
|
||||
read_mapping (const char *line,
|
||||
ULONGEST *addr, ULONGEST *endaddr,
|
||||
const char **permissions, size_t *permissions_len,
|
||||
ULONGEST *offset,
|
||||
const char **device, size_t *device_len,
|
||||
ULONGEST *inode,
|
||||
const char **filename);
|
||||
|
||||
/* Callback function for linux_find_memory_regions_full. If it returns
|
||||
non-zero linux_find_memory_regions_full returns immediately with that
|
||||
value. */
|
||||
|
||||
typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
|
||||
ULONGEST offset, ULONGEST inode,
|
||||
int read, int write,
|
||||
int exec, int modified,
|
||||
const char *filename,
|
||||
void *data);
|
||||
|
||||
/* This enum represents the values that the user can choose when
|
||||
informing the Linux kernel about which memory mappings will be
|
||||
dumped in a corefile. They are described in the file
|
||||
Documentation/filesystems/proc.txt, inside the Linux kernel
|
||||
tree. */
|
||||
|
||||
enum filterflags
|
||||
{
|
||||
COREFILTER_ANON_PRIVATE = 1 << 0,
|
||||
COREFILTER_ANON_SHARED = 1 << 1,
|
||||
COREFILTER_MAPPED_PRIVATE = 1 << 2,
|
||||
COREFILTER_MAPPED_SHARED = 1 << 3,
|
||||
COREFILTER_ELF_HEADERS = 1 << 4,
|
||||
COREFILTER_HUGETLB_PRIVATE = 1 << 5,
|
||||
COREFILTER_HUGETLB_SHARED = 1 << 6,
|
||||
};
|
||||
|
||||
extern int
|
||||
linux_find_memory_regions_full (pid_t pid, enum filterflags filterflags,
|
||||
linux_find_memory_region_ftype *func,
|
||||
void *func_data);
|
||||
|
||||
#endif /* NAT_LINUX_MAPS_H */
|
|
@ -634,5 +634,4 @@ _initialize_darwin_solib (void)
|
|||
darwin_so_ops.in_dynsym_resolve_code = darwin_in_dynsym_resolve_code;
|
||||
darwin_so_ops.lookup_lib_global_symbol = darwin_lookup_lib_symbol;
|
||||
darwin_so_ops.bfd_open = darwin_bfd_open;
|
||||
darwin_so_ops.validate = default_solib_validate;
|
||||
}
|
||||
|
|
|
@ -1080,7 +1080,6 @@ _initialize_dsbt_solib (void)
|
|||
dsbt_so_ops.open_symbol_file_object = open_symbol_file_object;
|
||||
dsbt_so_ops.in_dynsym_resolve_code = dsbt_in_dynsym_resolve_code;
|
||||
dsbt_so_ops.bfd_open = solib_bfd_open;
|
||||
dsbt_so_ops.validate = default_solib_validate;
|
||||
|
||||
/* Debug this file's internals. */
|
||||
add_setshow_zuinteger_cmd ("solib-dsbt", class_maintenance,
|
||||
|
|
|
@ -1183,7 +1183,6 @@ _initialize_frv_solib (void)
|
|||
frv_so_ops.open_symbol_file_object = open_symbol_file_object;
|
||||
frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code;
|
||||
frv_so_ops.bfd_open = solib_bfd_open;
|
||||
frv_so_ops.validate = default_solib_validate;
|
||||
|
||||
/* Debug this file's internals. */
|
||||
add_setshow_zuinteger_cmd ("solib-frv", class_maintenance,
|
||||
|
|
|
@ -519,7 +519,6 @@ set_spu_solib_ops (struct gdbarch *gdbarch)
|
|||
spu_so_ops.current_sos = spu_current_sos;
|
||||
spu_so_ops.bfd_open = spu_bfd_open;
|
||||
spu_so_ops.lookup_lib_global_symbol = spu_lookup_lib_symbol;
|
||||
spu_so_ops.validate = default_solib_validate;
|
||||
}
|
||||
|
||||
set_solib_ops (gdbarch, &spu_so_ops);
|
||||
|
|
103
gdb/solib-svr4.c
103
gdb/solib-svr4.c
|
@ -45,9 +45,6 @@
|
|||
#include "auxv.h"
|
||||
#include "gdb_bfd.h"
|
||||
#include "probe.h"
|
||||
#include "rsp-low.h"
|
||||
|
||||
#define NOTE_GNU_BUILD_ID_NAME ".note.gnu.build-id"
|
||||
|
||||
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
|
||||
static int svr4_have_link_map_offsets (void);
|
||||
|
@ -973,64 +970,6 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size)
|
|||
return (name_lm >= vaddr && name_lm < vaddr + size);
|
||||
}
|
||||
|
||||
/* Validate SO by comparing build-id from the associated bfd and
|
||||
corresponding build-id from target memory. Return NULL for success
|
||||
or a string for error. Caller must call xfree for the error string. */
|
||||
|
||||
static char *
|
||||
svr4_validate (const struct so_list *const so)
|
||||
{
|
||||
const bfd_byte *local_id;
|
||||
size_t local_idsz;
|
||||
|
||||
gdb_assert (so != NULL);
|
||||
|
||||
/* Target doesn't support reporting the build ID or the remote shared library
|
||||
does not have build ID. */
|
||||
if (so->build_id == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Build ID may be present in the local file, just GDB is unable to retrieve
|
||||
it. As it has been reported by gdbserver it is not FSF gdbserver. */
|
||||
if (so->abfd == NULL
|
||||
|| !bfd_check_format (so->abfd, bfd_object))
|
||||
return NULL;
|
||||
|
||||
/* GDB has verified the local file really does not contain the build ID. */
|
||||
if (so->abfd->build_id == NULL)
|
||||
{
|
||||
char *remote_hex;
|
||||
|
||||
remote_hex = alloca (so->build_idsz * 2 + 1);
|
||||
bin2hex (so->build_id, remote_hex, so->build_idsz);
|
||||
|
||||
return xstrprintf (_("remote build ID is %s "
|
||||
"but local file does not have build ID"),
|
||||
remote_hex);
|
||||
}
|
||||
|
||||
local_id = so->abfd->build_id->data;
|
||||
local_idsz = so->abfd->build_id->size;
|
||||
|
||||
if (so->build_idsz != local_idsz
|
||||
|| memcmp (so->build_id, local_id, so->build_idsz) != 0)
|
||||
{
|
||||
char *remote_hex, *local_hex;
|
||||
|
||||
remote_hex = alloca (so->build_idsz * 2 + 1);
|
||||
bin2hex (so->build_id, remote_hex, so->build_idsz);
|
||||
local_hex = alloca (local_idsz * 2 + 1);
|
||||
bin2hex (local_id, local_hex, local_idsz);
|
||||
|
||||
return xstrprintf (_("remote build ID %s "
|
||||
"does not match local build ID %s"),
|
||||
remote_hex, local_hex);
|
||||
}
|
||||
|
||||
/* Both build IDs are present and they match. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Implement the "open_symbol_file_object" target_so_ops method.
|
||||
|
||||
If no open symbol file, attempt to locate and open the main symbol
|
||||
|
@ -1169,12 +1108,6 @@ svr4_copy_library_list (struct so_list *src)
|
|||
newobj->lm_info = xmalloc (sizeof (struct lm_info));
|
||||
memcpy (newobj->lm_info, src->lm_info, sizeof (struct lm_info));
|
||||
|
||||
if (newobj->build_id != NULL)
|
||||
{
|
||||
newobj->build_id = xmalloc (src->build_idsz);
|
||||
memcpy (newobj->build_id, src->build_id, src->build_idsz);
|
||||
}
|
||||
|
||||
newobj->next = NULL;
|
||||
*link = newobj;
|
||||
link = &newobj->next;
|
||||
|
@ -1202,9 +1135,6 @@ library_list_start_library (struct gdb_xml_parser *parser,
|
|||
ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value;
|
||||
ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value;
|
||||
ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value;
|
||||
const struct gdb_xml_value *const att_build_id
|
||||
= xml_find_attribute (attributes, "build-id");
|
||||
const char *const hex_build_id = att_build_id ? att_build_id->value : NULL;
|
||||
struct so_list *new_elem;
|
||||
|
||||
new_elem = XCNEW (struct so_list);
|
||||
|
@ -1216,37 +1146,6 @@ library_list_start_library (struct gdb_xml_parser *parser,
|
|||
strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1);
|
||||
new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0;
|
||||
strcpy (new_elem->so_original_name, new_elem->so_name);
|
||||
if (hex_build_id != NULL)
|
||||
{
|
||||
const size_t hex_build_id_len = strlen (hex_build_id);
|
||||
|
||||
if (hex_build_id_len == 0)
|
||||
warning (_("Shared library \"%s\" received empty build-id "
|
||||
"from gdbserver"), new_elem->so_original_name);
|
||||
else if ((hex_build_id_len & 1U) != 0)
|
||||
warning (_("Shared library \"%s\" received odd number "
|
||||
"of build-id \"%s\" hex characters from gdbserver"),
|
||||
new_elem->so_original_name, hex_build_id);
|
||||
else
|
||||
{
|
||||
const size_t build_idsz = hex_build_id_len / 2;
|
||||
|
||||
new_elem->build_id = xmalloc (build_idsz);
|
||||
new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id,
|
||||
build_idsz);
|
||||
if (new_elem->build_idsz != build_idsz)
|
||||
{
|
||||
warning (_("Shared library \"%s\" received invalid "
|
||||
"build-id \"%s\" hex character at encoded byte "
|
||||
"position %s (first as 0) from gdbserver"),
|
||||
new_elem->so_original_name, hex_build_id,
|
||||
pulongest (new_elem->build_idsz));
|
||||
xfree (new_elem->build_id);
|
||||
new_elem->build_id = NULL;
|
||||
new_elem->build_idsz = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*list->tailp = new_elem;
|
||||
list->tailp = &new_elem->next;
|
||||
|
@ -1281,7 +1180,6 @@ static const struct gdb_xml_attribute svr4_library_attributes[] =
|
|||
{ "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
|
||||
{ "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
|
||||
{ "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
|
||||
{ "build-id", GDB_XML_AF_OPTIONAL, NULL, NULL },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -3360,5 +3258,4 @@ _initialize_svr4_solib (void)
|
|||
svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
|
||||
svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints;
|
||||
svr4_so_ops.handle_event = svr4_handle_solib_event;
|
||||
svr4_so_ops.validate = svr4_validate;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "target.h"
|
||||
#include "vec.h"
|
||||
#include "solib-target.h"
|
||||
#include "solib.h"
|
||||
|
||||
/* Private data for each loaded library. */
|
||||
struct lm_info
|
||||
|
@ -507,7 +506,6 @@ _initialize_solib_target (void)
|
|||
solib_target_so_ops.in_dynsym_resolve_code
|
||||
= solib_target_in_dynsym_resolve_code;
|
||||
solib_target_so_ops.bfd_open = solib_bfd_open;
|
||||
solib_target_so_ops.validate = default_solib_validate;
|
||||
|
||||
/* Set current_target_so_ops to solib_target_so_ops if not already
|
||||
set. */
|
||||
|
|
64
gdb/solib.c
64
gdb/solib.c
|
@ -518,20 +518,6 @@ solib_bfd_open (char *pathname)
|
|||
return abfd;
|
||||
}
|
||||
|
||||
/* Boolean for command 'set validate-build-id'. */
|
||||
static int validate_build_id = 1;
|
||||
|
||||
/* Implement 'show validate-build-id'. */
|
||||
|
||||
static void
|
||||
show_validate_build_id (struct ui_file *file, int from_tty,
|
||||
struct cmd_list_element *c, const char *value)
|
||||
{
|
||||
fprintf_filtered (file, _("Validation a build-id matches to load a shared "
|
||||
"library is %s.\n"),
|
||||
value);
|
||||
}
|
||||
|
||||
/* Given a pointer to one of the shared objects in our list of mapped
|
||||
objects, use the recorded name to open a bfd descriptor for the
|
||||
object, build a section table, relocate all the section addresses
|
||||
|
@ -548,7 +534,7 @@ static int
|
|||
solib_map_sections (struct so_list *so)
|
||||
{
|
||||
const struct target_so_ops *ops = solib_ops (target_gdbarch ());
|
||||
char *filename, *validate_error;
|
||||
char *filename;
|
||||
struct target_section *p;
|
||||
struct cleanup *old_chain;
|
||||
bfd *abfd;
|
||||
|
@ -564,29 +550,6 @@ solib_map_sections (struct so_list *so)
|
|||
/* Leave bfd open, core_xfer_memory and "info files" need it. */
|
||||
so->abfd = abfd;
|
||||
|
||||
gdb_assert (ops->validate != NULL);
|
||||
|
||||
validate_error = ops->validate (so);
|
||||
if (validate_error != NULL)
|
||||
{
|
||||
if (validate_build_id)
|
||||
{
|
||||
warning (_("Shared object \"%s\" could not be validated (%s) and "
|
||||
"will be ignored; "
|
||||
"or use 'set validate-build-id off'."),
|
||||
so->so_name, validate_error);
|
||||
xfree (validate_error);
|
||||
gdb_bfd_unref (so->abfd);
|
||||
so->abfd = NULL;
|
||||
return 0;
|
||||
}
|
||||
warning (_("Shared object \"%s\" could not be validated (%s) "
|
||||
"but it is being loaded due to "
|
||||
"'set validate-build-id off'."),
|
||||
so->so_name, validate_error);
|
||||
xfree (validate_error);
|
||||
}
|
||||
|
||||
/* Copy the full path name into so_name, allowing symbol_file_add
|
||||
to find it later. This also affects the =library-loaded GDB/MI
|
||||
event, and in particular the part of that notification providing
|
||||
|
@ -663,9 +626,6 @@ clear_so (struct so_list *so)
|
|||
of the symbol file. */
|
||||
strcpy (so->so_name, so->so_original_name);
|
||||
|
||||
xfree (so->build_id);
|
||||
so->build_id = NULL;
|
||||
|
||||
/* Do the same for target-specific data. */
|
||||
if (ops->clear_so != NULL)
|
||||
ops->clear_so (so);
|
||||
|
@ -1697,14 +1657,6 @@ remove_user_added_objfile (struct objfile *objfile)
|
|||
}
|
||||
}
|
||||
|
||||
/* Default implementation does not perform any validation. */
|
||||
|
||||
char *
|
||||
default_solib_validate (const struct so_list *const so)
|
||||
{
|
||||
return NULL; /* No validation. */
|
||||
}
|
||||
|
||||
extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */
|
||||
|
||||
void
|
||||
|
@ -1762,18 +1714,4 @@ PATH and LD_LIBRARY_PATH."),
|
|||
reload_shared_libraries,
|
||||
show_solib_search_path,
|
||||
&setlist, &showlist);
|
||||
|
||||
add_setshow_boolean_cmd ("validate-build-id", class_support,
|
||||
&validate_build_id, _("\
|
||||
Set validation a build-id matches to load a shared library."), _("\
|
||||
SHow validation a build-id matches to load a shared library."), _("\
|
||||
Inferior shared library and symbol file may contain unique build-id.\n\
|
||||
If both build-ids are present but they do not match then this setting\n\
|
||||
enables (off) or disables (on) loading of such symbol file.\n\
|
||||
Loading non-matching symbol file may confuse debugging including breakage\n\
|
||||
of backtrace output."),
|
||||
NULL,
|
||||
show_validate_build_id,
|
||||
&setlist, &showlist);
|
||||
|
||||
}
|
||||
|
|
|
@ -98,8 +98,4 @@ extern void update_solib_breakpoints (void);
|
|||
|
||||
extern void handle_solib_event (void);
|
||||
|
||||
/* Default validation always returns 1. */
|
||||
|
||||
extern char *default_solib_validate (const struct so_list *so);
|
||||
|
||||
#endif /* SOLIB_H */
|
||||
|
|
18
gdb/solist.h
18
gdb/solist.h
|
@ -75,19 +75,6 @@ struct so_list
|
|||
There may not be just one (e.g. if two segments are relocated
|
||||
differently); but this is only used for "info sharedlibrary". */
|
||||
CORE_ADDR addr_low, addr_high;
|
||||
|
||||
/* Build id decoded from .note.gnu.build-id without note header. This is
|
||||
actual BUILD_ID which comes either from the remote target via qXfer
|
||||
packet or via reading target memory. Note that if there's a
|
||||
mismatch with the associated bfd then so->abfd will be cleared.
|
||||
Reading target memory should be done by following execution view
|
||||
of the binary (following program headers in the case of ELF).
|
||||
Computing address from the linking view (following ELF section
|
||||
headers) may give incorrect build-id memory address despite the
|
||||
symbols still match.
|
||||
Such an example is a prelinked vs. unprelinked i386 ELF file. */
|
||||
size_t build_idsz;
|
||||
gdb_byte *build_id;
|
||||
};
|
||||
|
||||
struct target_so_ops
|
||||
|
@ -181,11 +168,6 @@ struct target_so_ops
|
|||
NULL, in which case no specific preprocessing is necessary
|
||||
for this target. */
|
||||
void (*handle_event) (void);
|
||||
|
||||
/* Return NULL if SO does match target SO it is supposed to
|
||||
represent. Otherwise return string describing why it does not match.
|
||||
Caller has to free the string. */
|
||||
char *(*validate) (const struct so_list *so);
|
||||
};
|
||||
|
||||
/* Free the memory associated with a (so_list *). */
|
||||
|
|
95
gdb/target.c
95
gdb/target.c
|
@ -43,7 +43,6 @@
|
|||
#include "agent.h"
|
||||
#include "auxv.h"
|
||||
#include "target-debug.h"
|
||||
#include "target/target-utils.h"
|
||||
|
||||
static void target_info (char *, int);
|
||||
|
||||
|
@ -2974,17 +2973,6 @@ target_fileio_close_cleanup (void *opaque)
|
|||
target_fileio_close (fd, &target_errno);
|
||||
}
|
||||
|
||||
/* Helper for target_fileio_read_alloc_1 to make it interruptible. */
|
||||
|
||||
static int
|
||||
target_fileio_read_alloc_1_pread (int handle, gdb_byte *read_buf, int len,
|
||||
ULONGEST offset, int *target_errno)
|
||||
{
|
||||
QUIT;
|
||||
|
||||
return target_fileio_pread (handle, read_buf, len, offset, target_errno);
|
||||
}
|
||||
|
||||
/* Read target file FILENAME, in the filesystem as seen by INF. If
|
||||
INF is NULL, use the filesystem seen by the debugger (GDB or, for
|
||||
remote targets, the remote stub). Store the result in *BUF_P and
|
||||
|
@ -2998,17 +2986,58 @@ target_fileio_read_alloc_1 (struct inferior *inf, const char *filename,
|
|||
gdb_byte **buf_p, int padding)
|
||||
{
|
||||
struct cleanup *close_cleanup;
|
||||
int fd, target_errno;
|
||||
LONGEST retval;
|
||||
size_t buf_alloc, buf_pos;
|
||||
gdb_byte *buf;
|
||||
LONGEST n;
|
||||
int fd;
|
||||
int target_errno;
|
||||
|
||||
fd = target_fileio_open (inf, filename, FILEIO_O_RDONLY, 0700, &target_errno);
|
||||
fd = target_fileio_open (inf, filename, FILEIO_O_RDONLY, 0700,
|
||||
&target_errno);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd);
|
||||
retval = read_alloc (buf_p, fd, target_fileio_read_alloc_1_pread, padding);
|
||||
do_cleanups (close_cleanup);
|
||||
return retval;
|
||||
|
||||
/* Start by reading up to 4K at a time. The target will throttle
|
||||
this number down if necessary. */
|
||||
buf_alloc = 4096;
|
||||
buf = xmalloc (buf_alloc);
|
||||
buf_pos = 0;
|
||||
while (1)
|
||||
{
|
||||
n = target_fileio_pread (fd, &buf[buf_pos],
|
||||
buf_alloc - buf_pos - padding, buf_pos,
|
||||
&target_errno);
|
||||
if (n < 0)
|
||||
{
|
||||
/* An error occurred. */
|
||||
do_cleanups (close_cleanup);
|
||||
xfree (buf);
|
||||
return -1;
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
/* Read all there was. */
|
||||
do_cleanups (close_cleanup);
|
||||
if (buf_pos == 0)
|
||||
xfree (buf);
|
||||
else
|
||||
*buf_p = buf;
|
||||
return buf_pos;
|
||||
}
|
||||
|
||||
buf_pos += n;
|
||||
|
||||
/* If the buffer is filling up, expand it. */
|
||||
if (buf_alloc < buf_pos * 2)
|
||||
{
|
||||
buf_alloc *= 2;
|
||||
buf = xrealloc (buf, buf_alloc);
|
||||
}
|
||||
|
||||
QUIT;
|
||||
}
|
||||
}
|
||||
|
||||
/* See target.h. */
|
||||
|
@ -3020,14 +3049,40 @@ target_fileio_read_alloc (struct inferior *inf, const char *filename,
|
|||
return target_fileio_read_alloc_1 (inf, filename, buf_p, 0);
|
||||
}
|
||||
|
||||
/* See target/target.h. */
|
||||
/* See target.h. */
|
||||
|
||||
char *
|
||||
target_fileio_read_stralloc (struct inferior *inf, const char *filename)
|
||||
{
|
||||
return read_stralloc (inf, filename, target_fileio_read_alloc_1);
|
||||
gdb_byte *buffer;
|
||||
char *bufstr;
|
||||
LONGEST i, transferred;
|
||||
|
||||
transferred = target_fileio_read_alloc_1 (inf, filename, &buffer, 1);
|
||||
bufstr = (char *) buffer;
|
||||
|
||||
if (transferred < 0)
|
||||
return NULL;
|
||||
|
||||
if (transferred == 0)
|
||||
return xstrdup ("");
|
||||
|
||||
bufstr[transferred] = 0;
|
||||
|
||||
/* Check for embedded NUL bytes; but allow trailing NULs. */
|
||||
for (i = strlen (bufstr); i < transferred; i++)
|
||||
if (bufstr[i] != 0)
|
||||
{
|
||||
warning (_("target file %s "
|
||||
"contained unexpected null characters"),
|
||||
filename);
|
||||
break;
|
||||
}
|
||||
|
||||
return bufstr;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
default_region_ok_for_hw_watchpoint (struct target_ops *self,
|
||||
CORE_ADDR addr, int len)
|
||||
|
|
10
gdb/target.h
10
gdb/target.h
|
@ -2033,6 +2033,16 @@ extern LONGEST target_fileio_read_alloc (struct inferior *inf,
|
|||
const char *filename,
|
||||
gdb_byte **buf_p);
|
||||
|
||||
/* Read target file FILENAME, in the filesystem as seen by INF. If
|
||||
INF is NULL, use the filesystem seen by the debugger (GDB or, for
|
||||
remote targets, the remote stub). The result is NUL-terminated and
|
||||
returned as a string, allocated using xmalloc. If an error occurs
|
||||
or the transfer is unsupported, NULL is returned. Empty objects
|
||||
are returned as allocated but empty strings. A warning is issued
|
||||
if the result contains any embedded NUL bytes. */
|
||||
extern char *target_fileio_read_stralloc (struct inferior *inf,
|
||||
const char *filename);
|
||||
|
||||
|
||||
/* Tracepoint-related operations. */
|
||||
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
/* Utility target functions for GDB, and GDBserver.
|
||||
|
||||
Copyright (C) 2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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 "common-defs.h"
|
||||
#include "target/target-utils.h"
|
||||
|
||||
LONGEST
|
||||
read_alloc (gdb_byte **buf_p, int handle, read_alloc_pread_ftype *pread_func,
|
||||
int padding)
|
||||
{
|
||||
size_t buf_alloc, buf_pos;
|
||||
gdb_byte *buf;
|
||||
LONGEST n;
|
||||
int target_errno;
|
||||
|
||||
/* Start by reading up to 4K at a time. The target will throttle
|
||||
this number down if necessary. */
|
||||
buf_alloc = 4096;
|
||||
buf = xmalloc (buf_alloc);
|
||||
buf_pos = 0;
|
||||
while (1)
|
||||
{
|
||||
n = pread_func (handle, &buf[buf_pos], buf_alloc - buf_pos - padding,
|
||||
buf_pos, &target_errno);
|
||||
if (n <= 0)
|
||||
{
|
||||
if (n < 0 || (n == 0 && buf_pos == 0))
|
||||
xfree (buf);
|
||||
else
|
||||
*buf_p = buf;
|
||||
if (n < 0)
|
||||
{
|
||||
/* An error occurred. */
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read all there was. */
|
||||
return buf_pos;
|
||||
}
|
||||
}
|
||||
|
||||
buf_pos += n;
|
||||
|
||||
/* If the buffer is filling up, expand it. */
|
||||
if (buf_alloc < buf_pos * 2)
|
||||
{
|
||||
buf_alloc *= 2;
|
||||
buf = xrealloc (buf, buf_alloc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
read_stralloc (struct inferior *inf, const char *filename,
|
||||
read_stralloc_func_ftype *func)
|
||||
{
|
||||
gdb_byte *buffer;
|
||||
char *bufstr;
|
||||
LONGEST i, transferred;
|
||||
|
||||
transferred = func (inf, filename, &buffer, 1);
|
||||
bufstr = (char *) buffer;
|
||||
|
||||
if (transferred < 0)
|
||||
return NULL;
|
||||
|
||||
if (transferred == 0)
|
||||
return xstrdup ("");
|
||||
|
||||
bufstr[transferred] = 0;
|
||||
|
||||
/* Check for embedded NUL bytes; but allow trailing NULs. */
|
||||
for (i = strlen (bufstr); i < transferred; i++)
|
||||
if (bufstr[i] != 0)
|
||||
{
|
||||
warning (_("target file %s "
|
||||
"contained unexpected null characters"),
|
||||
filename);
|
||||
break;
|
||||
}
|
||||
|
||||
return bufstr;
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/* Utility target functions for GDB, and GDBserver.
|
||||
|
||||
Copyright (C) 2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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/>. */
|
||||
|
||||
#ifndef TARGET_TARGET_UTILS_H
|
||||
#define TARGET_TARGET_UTILS_H
|
||||
|
||||
typedef int (read_alloc_pread_ftype) (int handle, gdb_byte *read_buf, int len,
|
||||
ULONGEST offset, int *target_errno);
|
||||
extern LONGEST read_alloc (gdb_byte **buf_p, int handle,
|
||||
read_alloc_pread_ftype *pread_func, int padding);
|
||||
|
||||
struct inferior;
|
||||
typedef LONGEST (read_stralloc_func_ftype) (struct inferior *inf,
|
||||
const char *filename,
|
||||
gdb_byte **buf_p, int padding);
|
||||
extern char *read_stralloc (struct inferior *inf, const char *filename,
|
||||
read_stralloc_func_ftype *func);
|
||||
|
||||
#endif /* TARGET_TARGET_UTILS_H */
|
|
@ -70,15 +70,4 @@ extern void target_stop_and_wait (ptid_t ptid);
|
|||
|
||||
extern void target_continue_no_signal (ptid_t ptid);
|
||||
|
||||
/* Read target file FILENAME, in the filesystem as seen by INF. If
|
||||
INF is NULL, use the filesystem seen by the debugger (GDB or, for
|
||||
remote targets, the remote stub). The result is NUL-terminated and
|
||||
returned as a string, allocated using xmalloc. If an error occurs
|
||||
or the transfer is unsupported, NULL is returned. Empty objects
|
||||
are returned as allocated but empty strings. A warning is issued
|
||||
if the result contains any embedded NUL bytes. */
|
||||
struct inferior;
|
||||
extern char *target_fileio_read_stralloc (struct inferior *inf,
|
||||
const char *filename);
|
||||
|
||||
#endif /* TARGET_COMMON_H */
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2015-07-15 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
Revert the previous commit:
|
||||
Tests for validate symbol file using build-id.
|
||||
|
||||
2015-07-15 Aleksandar Ristovski <aristovski@qnx.com
|
||||
|
||||
Tests for validate symbol file using build-id.
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2015 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
int _bar = 42;
|
||||
|
||||
int
|
||||
bar (void)
|
||||
{
|
||||
return _bar + 21;
|
||||
}
|
||||
|
||||
int
|
||||
foo (void)
|
||||
{
|
||||
return _bar;
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2015 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
int _bar = 21;
|
||||
|
||||
int
|
||||
bar (void)
|
||||
{
|
||||
return 42 - _bar;
|
||||
}
|
||||
|
||||
int
|
||||
foo (void)
|
||||
{
|
||||
return 24 + bar();
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2015 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 <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
/* The following defines must correspond to solib-mismatch.exp . */
|
||||
|
||||
/* DIRNAME and LIB must be defined at compile time. */
|
||||
#ifndef DIRNAME
|
||||
# error DIRNAME not defined
|
||||
#endif
|
||||
#ifndef LIB
|
||||
# error LIB not defined
|
||||
#endif
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
void *h;
|
||||
int (*foo) (void);
|
||||
|
||||
if (chdir (DIRNAME) != 0)
|
||||
{
|
||||
printf ("ERROR - Could not cd to %s\n", DIRNAME);
|
||||
return 1;
|
||||
}
|
||||
|
||||
h = dlopen (LIB, RTLD_NOW);
|
||||
|
||||
if (h == NULL)
|
||||
{
|
||||
printf ("ERROR - could not open lib %s\n", LIB);
|
||||
return 1;
|
||||
}
|
||||
foo = dlsym (h, "foo"); /* set breakpoint 1 here */
|
||||
dlclose (h);
|
||||
return 0;
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
# Copyright 2015 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/>. */
|
||||
|
||||
standard_testfile
|
||||
set executable $testfile
|
||||
|
||||
if ![is_remote target] {
|
||||
untested "only gdbserver supports build-id reporting"
|
||||
return -1
|
||||
}
|
||||
if [is_remote host] {
|
||||
untested "only local host is currently supported"
|
||||
return -1
|
||||
}
|
||||
|
||||
# Test overview:
|
||||
# generate two shared objects. One that will be used by the process
|
||||
# and another, modified, that will be found by gdb. Gdb should
|
||||
# detect the mismatch and refuse to use mismatched shared object.
|
||||
|
||||
if { [get_compiler_info] } {
|
||||
untested "get_compiler_info failed."
|
||||
return -1
|
||||
}
|
||||
|
||||
# First version of the object, to be loaded by ld.
|
||||
set srclibfilerun ${testfile}-lib.c
|
||||
|
||||
# Modified version of the object to be loaded by gdb
|
||||
# Code in -libmod.c is tuned so it gives a mismatch but
|
||||
# leaves .dynamic at the same point.
|
||||
set srclibfilegdb ${testfile}-libmod.c
|
||||
|
||||
# So file name:
|
||||
set binlibfilebase lib${testfile}.so
|
||||
|
||||
# Setup run directory (where program is run from)
|
||||
# It contains executable and '-lib' version of the library.
|
||||
set binlibfiledirrun [standard_output_file ${testfile}_wd]
|
||||
set binlibfilerun ${binlibfiledirrun}/${binlibfilebase}
|
||||
|
||||
# Second solib version is in current directory, '-libmod' version.
|
||||
set binlibfiledirgdb [standard_output_file ""]
|
||||
set binlibfilegdb ${binlibfiledirgdb}/${binlibfilebase}
|
||||
|
||||
# Executable
|
||||
set srcfile ${testfile}.c
|
||||
set executable ${testfile}
|
||||
|
||||
file delete -force -- "${binlibfiledirrun}"
|
||||
file mkdir "${binlibfiledirrun}"
|
||||
|
||||
set exec_opts {}
|
||||
|
||||
if { ![istarget "*-*-nto-*"] } {
|
||||
lappend exec_opts "shlib_load"
|
||||
}
|
||||
|
||||
lappend exec_opts "additional_flags=-DDIRNAME\=\"${binlibfiledirrun}\" -DLIB\=\"./${binlibfilebase}\""
|
||||
lappend exec_opts "debug"
|
||||
|
||||
if { [build_executable $testfile.exp $executable $srcfile $exec_opts] != 0 } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if { [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilerun}" "${binlibfilerun}" [list debug ldflags=-Wl,--build-id]] != ""
|
||||
|| [gdb_gnu_strip_debug "${binlibfilerun}"]
|
||||
|| [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfilegdb}" "${binlibfilegdb}" [list debug ldflags=-Wl,--build-id]] != "" } {
|
||||
untested "compilation failed."
|
||||
return -1
|
||||
}
|
||||
|
||||
proc solib_matching_test { solibfile symsloaded } {
|
||||
global gdb_prompt
|
||||
global testfile
|
||||
global executable
|
||||
global srcdir
|
||||
global subdir
|
||||
global binlibfiledirrun
|
||||
global binlibfiledirgdb
|
||||
global srcfile
|
||||
|
||||
clean_restart ${binlibfiledirrun}/${executable}
|
||||
|
||||
gdb_test_no_output "set solib-search-path \"${binlibfiledirgdb}\"" ""
|
||||
if { [gdb_test "cd ${binlibfiledirgdb}" "" ""] != 0 } {
|
||||
untested "cd ${binlibfiledirgdb}"
|
||||
return -1
|
||||
}
|
||||
|
||||
# Do not auto load shared libraries, the test needs to have control
|
||||
# over when the relevant output gets printed.
|
||||
gdb_test_no_output "set auto-solib-add off" ""
|
||||
|
||||
if ![runto "${srcfile}:[gdb_get_line_number "set breakpoint 1 here"]"] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test "sharedlibrary" "" ""
|
||||
|
||||
set nocrlf "\[^\r\n\]*"
|
||||
set expected_header "From${nocrlf}To${nocrlf}Syms${nocrlf}Read${nocrlf}Shared${nocrlf}"
|
||||
set expected_line "${symsloaded}${nocrlf}${solibfile}"
|
||||
|
||||
gdb_test "info sharedlibrary ${solibfile}" \
|
||||
"${expected_header}\r\n.*${expected_line}.*" \
|
||||
"Symbols for ${solibfile} loaded: expected '${symsloaded}'"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Copy binary to working dir so it pulls in the library from that dir
|
||||
# (by the virtue of $ORIGIN).
|
||||
file copy -force "${binlibfiledirgdb}/${executable}" \
|
||||
"${binlibfiledirrun}/${executable}"
|
||||
|
||||
# Test unstripped, .dynamic matching
|
||||
with_test_prefix "test unstripped, .dynamic matching" {
|
||||
solib_matching_test "${binlibfilebase}" "No"
|
||||
}
|
||||
|
||||
# Keep original so for debugging purposes
|
||||
file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig"
|
||||
set objcopy_program [transform objcopy]
|
||||
set result [catch "exec $objcopy_program --only-keep-debug ${binlibfilegdb}"]
|
||||
if {$result != 0} {
|
||||
untested "test --only-keep-debug (objcopy)"
|
||||
}
|
||||
|
||||
# Test --only-keep-debug, .dynamic matching so
|
||||
with_test_prefix "test --only-keep-debug" {
|
||||
solib_matching_test "${binlibfilebase}" "No"
|
||||
}
|
||||
|
||||
# Keep previous so for debugging puroses
|
||||
file copy -force "${binlibfilegdb}" "${binlibfilegdb}-orig1"
|
||||
|
||||
# Copy loaded so over the one gdb will find
|
||||
file copy -force "${binlibfilerun}" "${binlibfilegdb}"
|
||||
|
||||
# Now test it does not mis-invalidate matching libraries
|
||||
with_test_prefix "test matching libraries" {
|
||||
solib_matching_test "${binlibfilebase}" "Yes"
|
||||
}
|
55
gdb/utils.c
55
gdb/utils.c
|
@ -67,6 +67,7 @@
|
|||
|
||||
#include "gdb_usleep.h"
|
||||
#include "interps.h"
|
||||
#include "gdb_regex.h"
|
||||
|
||||
#if !HAVE_DECL_MALLOC
|
||||
extern PTR malloc (); /* ARI: PTR */
|
||||
|
@ -1113,6 +1114,60 @@ make_hex_string (const gdb_byte *data, size_t length)
|
|||
|
||||
|
||||
|
||||
/* A cleanup function that calls regfree. */
|
||||
|
||||
static void
|
||||
do_regfree_cleanup (void *r)
|
||||
{
|
||||
regfree (r);
|
||||
}
|
||||
|
||||
/* Create a new cleanup that frees the compiled regular expression R. */
|
||||
|
||||
struct cleanup *
|
||||
make_regfree_cleanup (regex_t *r)
|
||||
{
|
||||
return make_cleanup (do_regfree_cleanup, r);
|
||||
}
|
||||
|
||||
/* Return an xmalloc'd error message resulting from a regular
|
||||
expression compilation failure. */
|
||||
|
||||
char *
|
||||
get_regcomp_error (int code, regex_t *rx)
|
||||
{
|
||||
size_t length = regerror (code, rx, NULL, 0);
|
||||
char *result = xmalloc (length);
|
||||
|
||||
regerror (code, rx, result, length);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Compile a regexp and throw an exception on error. This returns a
|
||||
cleanup to free the resulting pattern on success. RX must not be
|
||||
NULL. */
|
||||
|
||||
struct cleanup *
|
||||
compile_rx_or_error (regex_t *pattern, const char *rx, const char *message)
|
||||
{
|
||||
int code;
|
||||
|
||||
gdb_assert (rx != NULL);
|
||||
|
||||
code = regcomp (pattern, rx, REG_NOSUB);
|
||||
if (code != 0)
|
||||
{
|
||||
char *err = get_regcomp_error (code, pattern);
|
||||
|
||||
make_cleanup (xfree, err);
|
||||
error (("%s: %s"), message, err);
|
||||
}
|
||||
|
||||
return make_regfree_cleanup (pattern);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This function supports the query, nquery, and yquery functions.
|
||||
Ask user a y-or-n question and return 0 if answer is no, 1 if
|
||||
answer is yes, or default the answer to the specified default
|
||||
|
|
Loading…
Reference in New Issue