aboutsummaryrefslogtreecommitdiff
path: root/gdbserver
diff options
context:
space:
mode:
Diffstat (limited to 'gdbserver')
-rwxr-xr-xgdbserver/configure225
-rw-r--r--gdbserver/configure.ac2
-rw-r--r--gdbserver/gdbreplay.cc2
-rw-r--r--gdbserver/hostio.cc62
-rw-r--r--gdbserver/i387-fp.cc40
-rw-r--r--gdbserver/linux-aarch64-low.cc46
-rw-r--r--gdbserver/linux-amd64-ipa.cc10
-rw-r--r--gdbserver/linux-i386-ipa.cc6
-rw-r--r--gdbserver/linux-low.cc60
-rw-r--r--gdbserver/linux-low.h9
-rw-r--r--gdbserver/linux-x86-low.cc44
-rw-r--r--gdbserver/server.cc457
-rw-r--r--gdbserver/server.h1
-rw-r--r--gdbserver/target.cc9
-rw-r--r--gdbserver/target.h7
-rw-r--r--gdbserver/tracepoint.cc6
-rw-r--r--gdbserver/utils.cc2
17 files changed, 517 insertions, 471 deletions
diff --git a/gdbserver/configure b/gdbserver/configure
index b45b55f..1554296 100755
--- a/gdbserver/configure
+++ b/gdbserver/configure
@@ -7531,119 +7531,6 @@ $as_echo "#define HAVE_CXX17 1" >>confdefs.h
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
-$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_header_stdc=yes
-else
- ac_cv_header_stdc=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-if test $ac_cv_header_stdc = yes; then
- # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "memchr" >/dev/null 2>&1; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "free" >/dev/null 2>&1; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
- if test "$cross_compiling" = yes; then :
- :
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ctype.h>
-#include <stdlib.h>
-#if ((' ' & 0x0FF) == 0x020)
-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#else
-# define ISLOWER(c) \
- (('a' <= (c) && (c) <= 'i') \
- || ('j' <= (c) && (c) <= 'r') \
- || ('s' <= (c) && (c) <= 'z'))
-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
-#endif
-
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int
-main ()
-{
- int i;
- for (i = 0; i < 256; i++)
- if (XOR (islower (i), ISLOWER (i))
- || toupper (i) != TOUPPER (i))
- return 2;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
-$as_echo "$ac_cv_header_stdc" >&6; }
-if test $ac_cv_header_stdc = yes; then
-
-$as_echo "#define STDC_HEADERS 1" >>confdefs.h
-
-fi
-
-
ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
if test "x$ac_cv_type_size_t" = xyes; then :
@@ -7920,118 +7807,6 @@ fi
# Set the 'development' global.
. $srcdir/../bfd/development.sh
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
-$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_header_stdc=yes
-else
- ac_cv_header_stdc=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-if test $ac_cv_header_stdc = yes; then
- # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "memchr" >/dev/null 2>&1; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "free" >/dev/null 2>&1; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
- if test "$cross_compiling" = yes; then :
- :
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ctype.h>
-#include <stdlib.h>
-#if ((' ' & 0x0FF) == 0x020)
-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#else
-# define ISLOWER(c) \
- (('a' <= (c) && (c) <= 'i') \
- || ('j' <= (c) && (c) <= 'r') \
- || ('s' <= (c) && (c) <= 'z'))
-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
-#endif
-
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int
-main ()
-{
- int i;
- for (i = 0; i < 256; i++)
- if (XOR (islower (i), ISLOWER (i))
- || toupper (i) != TOUPPER (i))
- return 2;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
-$as_echo "$ac_cv_header_stdc" >&6; }
-if test $ac_cv_header_stdc = yes; then
-
-$as_echo "#define STDC_HEADERS 1" >>confdefs.h
-
-fi
-
# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
# for constant arguments. Useless!
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5
diff --git a/gdbserver/configure.ac b/gdbserver/configure.ac
index bd2cac8..f5a669a 100644
--- a/gdbserver/configure.ac
+++ b/gdbserver/configure.ac
@@ -50,8 +50,6 @@ AC_ARG_PROGRAM
# necessary, set CXX_DIALECT to some -std=xxx switch.
AX_CXX_COMPILE_STDCXX(17, , mandatory)
-AC_HEADER_STDC
-
GDB_AC_COMMON
# This is set by GDB_AC_COMMON.
AC_SUBST(WIN32APILIBS)
diff --git a/gdbserver/gdbreplay.cc b/gdbserver/gdbreplay.cc
index 44aa2fb..a517031 100644
--- a/gdbserver/gdbreplay.cc
+++ b/gdbserver/gdbreplay.cc
@@ -462,7 +462,7 @@ static void
gdbreplay_version (void)
{
printf ("GNU gdbreplay %s%s\n"
- "Copyright (C) 2024 Free Software Foundation, Inc.\n"
+ "Copyright (C) 2025 Free Software Foundation, Inc.\n"
"gdbreplay is free software, covered by "
"the GNU General Public License.\n"
"This gdbreplay was configured as \"%s\"\n",
diff --git a/gdbserver/hostio.cc b/gdbserver/hostio.cc
index 17b6179..69729a8 100644
--- a/gdbserver/hostio.cc
+++ b/gdbserver/hostio.cc
@@ -89,12 +89,18 @@ require_filename (char **pp, char *filename)
return 0;
}
+template <typename T>
static int
-require_int (char **pp, int *value)
+require_int (char **pp, T *value)
{
+ constexpr bool is_signed = std::is_signed<T>::value;
+
char *p;
int count, firstdigit;
+ /* Max count of hexadecimal digits in T (1 hex digit is 4 bits). */
+ int max_count = sizeof (T) * CHAR_BIT / 4;
+
p = *pp;
*value = 0;
count = 0;
@@ -111,7 +117,8 @@ require_int (char **pp, int *value)
firstdigit = nib;
/* Don't allow overflow. */
- if (count >= 8 || (count == 7 && firstdigit >= 0x8))
+ if (count >= max_count
+ || (is_signed && count == (max_count - 1) && firstdigit >= 0x8))
return -1;
*value = *value * 16 + nib;
@@ -343,7 +350,8 @@ handle_open (char *own_buf)
static void
handle_pread (char *own_buf, int *new_packet_len)
{
- int fd, ret, len, offset, bytes_sent;
+ int fd, ret, len, bytes_sent;
+ off_t offset;
char *p, *data;
static int max_reply_size = -1;
@@ -410,7 +418,8 @@ handle_pread (char *own_buf, int *new_packet_len)
static void
handle_pwrite (char *own_buf, int packet_len)
{
- int fd, ret, len, offset;
+ int fd, ret, len;
+ off_t offset;
char *p, *data;
p = own_buf + strlen ("vFile:pwrite:");
@@ -504,7 +513,48 @@ handle_stat (char *own_buf, int *new_packet_len)
return;
}
- if (lstat (filename, &st) == -1)
+ if (stat (filename, &st) == -1)
+ {
+ hostio_error (own_buf);
+ return;
+ }
+
+ host_to_fileio_stat (&st, &fst);
+
+ bytes_sent = hostio_reply_with_data (own_buf,
+ (char *) &fst, sizeof (fst),
+ new_packet_len);
+
+ /* If the response does not fit into a single packet, do not attempt
+ to return a partial response, but simply fail. */
+ if (bytes_sent < sizeof (fst))
+ write_enn (own_buf);
+}
+
+static void
+handle_lstat (char *own_buf, int *new_packet_len)
+{
+ int ret, bytes_sent;
+ char *p;
+ struct stat st;
+ struct fio_stat fst;
+ char filename[HOSTIO_PATH_MAX];
+
+ p = own_buf + strlen ("vFile:lstat:");
+
+ if (require_filename (&p, filename)
+ || require_end (p))
+ {
+ hostio_packet_error (own_buf);
+ return;
+ }
+
+ if (hostio_fs_pid != 0)
+ ret = the_target->multifs_lstat (hostio_fs_pid, filename, &st);
+ else
+ ret = lstat (filename, &st);
+
+ if (ret == -1)
{
hostio_error (own_buf);
return;
@@ -641,6 +691,8 @@ handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
handle_fstat (own_buf, new_packet_len);
else if (startswith (own_buf, "vFile:stat:"))
handle_stat (own_buf, new_packet_len);
+ else if (startswith (own_buf, "vFile:lstat:"))
+ handle_lstat (own_buf, new_packet_len);
else if (startswith (own_buf, "vFile:close:"))
handle_close (own_buf);
else if (startswith (own_buf, "vFile:unlink:"))
diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
index 4be0083..90824bd 100644
--- a/gdbserver/i387-fp.cc
+++ b/gdbserver/i387-fp.cc
@@ -21,7 +21,7 @@
#include "nat/x86-xstate.h"
/* Default to SSE. */
-static uint64_t x86_xcr0 = X86_XSTATE_SSE_MASK;
+static uint64_t x86_xstate_bv = X86_XSTATE_SSE_MASK;
static const int num_avx512_k_registers = 8;
static const int num_pkeys_registers = 1;
@@ -265,7 +265,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
/* The supported bits in `xstat_bv' are 8 bytes. Clear part in
vector registers if its bit in xstat_bv is zero. */
- clear_bv = (~fp->xstate_bv) & x86_xcr0;
+ clear_bv = (~fp->xstate_bv) & x86_xstate_bv;
/* Clear part in x87 and vector registers if its bit in xstat_bv is
zero. */
@@ -315,7 +315,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any x87 registers are changed. */
- if ((x86_xcr0 & X86_XSTATE_X87))
+ if ((x86_xstate_bv & X86_XSTATE_X87))
{
int st0_regnum = find_regno (regcache->tdesc, "st0");
@@ -332,7 +332,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any SSE registers are changed. */
- if ((x86_xcr0 & X86_XSTATE_SSE))
+ if ((x86_xstate_bv & X86_XSTATE_SSE))
{
int xmm0_regnum = find_regno (regcache->tdesc, "xmm0");
@@ -349,7 +349,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any AVX registers are changed. */
- if ((x86_xcr0 & X86_XSTATE_AVX))
+ if ((x86_xstate_bv & X86_XSTATE_AVX))
{
int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h");
@@ -366,7 +366,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any K registers are changed. */
- if ((x86_xcr0 & X86_XSTATE_K))
+ if ((x86_xstate_bv & X86_XSTATE_K))
{
int k0_regnum = find_regno (regcache->tdesc, "k0");
@@ -383,7 +383,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any of ZMM0H-ZMM15H registers are changed. */
- if ((x86_xcr0 & X86_XSTATE_ZMM_H))
+ if ((x86_xstate_bv & X86_XSTATE_ZMM_H))
{
int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h");
@@ -400,7 +400,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any of ZMM16-ZMM31 registers are changed. */
- if ((x86_xcr0 & X86_XSTATE_ZMM) && num_zmm_high_registers != 0)
+ if ((x86_xstate_bv & X86_XSTATE_ZMM) && num_zmm_high_registers != 0)
{
int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h");
int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h");
@@ -437,7 +437,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any PKEYS registers are changed. */
- if ((x86_xcr0 & X86_XSTATE_PKRU))
+ if ((x86_xstate_bv & X86_XSTATE_PKRU))
{
int pkru_regnum = find_regno (regcache->tdesc, "pkru");
@@ -453,7 +453,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
}
- if ((x86_xcr0 & X86_XSTATE_SSE) || (x86_xcr0 & X86_XSTATE_AVX))
+ if ((x86_xstate_bv & X86_XSTATE_SSE) || (x86_xstate_bv & X86_XSTATE_AVX))
{
collect_register_by_name (regcache, "mxcsr", raw);
if (memcmp (raw, &fp->mxcsr, 4) != 0)
@@ -465,7 +465,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
}
- if (x86_xcr0 & X86_XSTATE_X87)
+ if (x86_xstate_bv & X86_XSTATE_X87)
{
collect_register_by_name (regcache, "fioff", raw);
if (memcmp (raw, &fp->fioff, 4) != 0)
@@ -658,10 +658,10 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
/* The supported bits in `xstat_bv' are 8 bytes. Clear part in
vector registers if its bit in xstat_bv is zero. */
- clear_bv = (~fp->xstate_bv) & x86_xcr0;
+ clear_bv = (~fp->xstate_bv) & x86_xstate_bv;
/* Check if any x87 registers are changed. */
- if ((x86_xcr0 & X86_XSTATE_X87) != 0)
+ if ((x86_xstate_bv & X86_XSTATE_X87) != 0)
{
int st0_regnum = find_regno (regcache->tdesc, "st0");
@@ -678,7 +678,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
- if ((x86_xcr0 & X86_XSTATE_SSE) != 0)
+ if ((x86_xstate_bv & X86_XSTATE_SSE) != 0)
{
int xmm0_regnum = find_regno (regcache->tdesc, "xmm0");
@@ -695,7 +695,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
- if ((x86_xcr0 & X86_XSTATE_AVX) != 0)
+ if ((x86_xstate_bv & X86_XSTATE_AVX) != 0)
{
int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h");
@@ -712,7 +712,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
- if ((x86_xcr0 & X86_XSTATE_K) != 0)
+ if ((x86_xstate_bv & X86_XSTATE_K) != 0)
{
int k0_regnum = find_regno (regcache->tdesc, "k0");
@@ -729,7 +729,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
- if ((x86_xcr0 & X86_XSTATE_ZMM_H) != 0)
+ if ((x86_xstate_bv & X86_XSTATE_ZMM_H) != 0)
{
int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h");
@@ -746,7 +746,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
- if ((x86_xcr0 & X86_XSTATE_ZMM) != 0 && num_zmm_high_registers != 0)
+ if ((x86_xstate_bv & X86_XSTATE_ZMM) != 0 && num_zmm_high_registers != 0)
{
int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h");
int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h");
@@ -773,7 +773,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
- if ((x86_xcr0 & X86_XSTATE_PKRU) != 0)
+ if ((x86_xstate_bv & X86_XSTATE_PKRU) != 0)
{
int pkru_regnum = find_regno (regcache->tdesc, "pkru");
@@ -858,5 +858,5 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
std::pair<uint64_t *, x86_xsave_layout *>
i387_get_xsave_storage ()
{
- return { &x86_xcr0, &xsave_layout };
+ return { &x86_xstate_bv, &xsave_layout };
}
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 2eb3af6..9d3ac80 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -39,6 +39,7 @@
#include "gdb_proc_service.h"
#include "arch/aarch64.h"
+#include "arch/aarch64-gcs-linux.h"
#include "arch/aarch64-mte-linux.h"
#include "arch/aarch64-scalable-linux.h"
#include "linux-aarch32-tdesc.h"
@@ -321,6 +322,42 @@ aarch64_store_tlsregset (struct regcache *regcache, const void *buf)
supply_register (regcache, *regnum, tls_buf + sizeof (uint64_t));
}
+/* Fill BUF with the GCS registers from REGCACHE. */
+
+static void
+aarch64_fill_gcsregset (regcache *regcache, void *buf)
+{
+ user_gcs *regset = (user_gcs *) buf;
+ int gcspr_regnum = find_regno (regcache->tdesc, "gcspr");
+ int features_enabled_regnum = find_regno (regcache->tdesc,
+ "gcs_features_enabled");
+ int features_locked_regnum = find_regno (regcache->tdesc,
+ "gcs_features_locked");
+
+ collect_register (regcache, gcspr_regnum, &regset->gcspr_el0);
+ collect_register (regcache, features_enabled_regnum,
+ &regset->features_enabled);
+ collect_register (regcache, features_locked_regnum, &regset->features_locked);
+}
+
+/* Store the GCS registers in BUF to REGCACHE. */
+
+static void
+aarch64_store_gcsregset (regcache *regcache, const void *buf)
+{
+ const user_gcs *regset = (const user_gcs *) buf;
+ int gcspr_regnum = find_regno (regcache->tdesc, "gcspr");
+ int features_enabled_regnum = find_regno (regcache->tdesc,
+ "gcs_features_enabled");
+ int features_locked_regnum = find_regno (regcache->tdesc,
+ "gcs_features_locked");
+
+ supply_register (regcache, gcspr_regnum, &regset->gcspr_el0);
+ supply_register (regcache, features_enabled_regnum,
+ &regset->features_enabled);
+ supply_register (regcache, features_locked_regnum, &regset->features_locked);
+}
+
bool
aarch64_target::low_supports_breakpoints ()
{
@@ -846,6 +883,10 @@ static struct regset_info aarch64_regsets[] =
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TLS,
0, OPTIONAL_REGS,
aarch64_fill_tlsregset, aarch64_store_tlsregset },
+ /* Guarded Control Stack registers. */
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_GCS,
+ 0, OPTIONAL_REGS,
+ aarch64_fill_gcsregset, aarch64_store_gcsregset },
NULL_REGSET
};
@@ -909,6 +950,10 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
if (features.sme2)
regset->size = AARCH64_SME2_ZT0_SIZE;
break;
+ case NT_ARM_GCS:
+ if (features.gcs_linux)
+ regset->size = sizeof (user_gcs);
+ break;
default:
gdb_assert_not_reached ("Unknown register set found.");
}
@@ -940,6 +985,7 @@ aarch64_target::low_arch_setup ()
/* A-profile MTE is 64-bit only. */
features.mte = linux_get_hwcap2 (pid, 8) & HWCAP2_MTE;
features.tls = aarch64_tls_register_count (tid);
+ features.gcs = features.gcs_linux = linux_get_hwcap (pid, 8) & HWCAP_GCS;
/* Scalable Matrix Extension feature and size check. */
if (linux_get_hwcap2 (pid, 8) & HWCAP2_SME)
diff --git a/gdbserver/linux-amd64-ipa.cc b/gdbserver/linux-amd64-ipa.cc
index af4eb03..ec66367 100644
--- a/gdbserver/linux-amd64-ipa.cc
+++ b/gdbserver/linux-amd64-ipa.cc
@@ -82,7 +82,7 @@ get_raw_reg (const unsigned char *raw_regs, int regnum)
const struct target_desc *
get_ipa_tdesc (int idx)
{
- uint64_t xcr0 = x86_linux_tdesc_idx_to_xcr0 (idx);
+ uint64_t xstate_bv = x86_linux_tdesc_idx_to_xstate_bv (idx);
#if defined __ILP32__
bool is_x32 = true;
@@ -90,7 +90,7 @@ get_ipa_tdesc (int idx)
bool is_x32 = false;
#endif
- return amd64_linux_read_description (xcr0, is_x32);
+ return amd64_linux_read_description (xstate_bv, is_x32);
}
/* Allocate buffer for the jump pads. The branch instruction has a
@@ -159,9 +159,11 @@ initialize_low_tracepoint (void)
{
#if defined __ILP32__
for (int i = 0; i < x86_linux_x32_tdesc_count (); i++)
- amd64_linux_read_description (x86_linux_tdesc_idx_to_xcr0 (i), true);
+ amd64_linux_read_description
+ (x86_linux_tdesc_idx_to_xstate_bv (i), true);
#else
for (int i = 0; i < x86_linux_amd64_tdesc_count (); i++)
- amd64_linux_read_description (x86_linux_tdesc_idx_to_xcr0 (i), false);
+ amd64_linux_read_description
+ (x86_linux_tdesc_idx_to_xstate_bv (i), false);
#endif
}
diff --git a/gdbserver/linux-i386-ipa.cc b/gdbserver/linux-i386-ipa.cc
index 17af6eb..4f8398d 100644
--- a/gdbserver/linux-i386-ipa.cc
+++ b/gdbserver/linux-i386-ipa.cc
@@ -174,9 +174,9 @@ initialize_fast_tracepoint_trampoline_buffer (void)
const struct target_desc *
get_ipa_tdesc (int idx)
{
- uint64_t xcr0 = x86_linux_tdesc_idx_to_xcr0 (idx);
+ uint64_t xstate_bv = x86_linux_tdesc_idx_to_xstate_bv (idx);
- return i386_linux_read_description (xcr0);
+ return i386_linux_read_description (xstate_bv);
}
/* Allocate buffer for the jump pads. On i386, we can reach an arbitrary
@@ -199,5 +199,5 @@ initialize_low_tracepoint (void)
{
initialize_fast_tracepoint_trampoline_buffer ();
for (int i = 0; i < x86_linux_i386_tdesc_count (); i++)
- i386_linux_read_description (x86_linux_tdesc_idx_to_xcr0 (i));
+ i386_linux_read_description (x86_linux_tdesc_idx_to_xstate_bv (i));
}
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 1d223c1..e8c4eb8 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -751,7 +751,7 @@ linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
/* Set the event status. */
event_lwp->waitstatus.set_execd
(make_unique_xstrdup
- (linux_proc_pid_to_exec_file (event_thr->id.lwp ())));
+ (pid_to_exec_file (event_thr->id.lwp ())));
/* Mark the exec status as pending. */
event_lwp->stopped = 1;
@@ -5006,23 +5006,31 @@ regsets_fetch_inferior_registers (struct regsets_info *regsets_info,
if (res < 0)
{
if (errno == EIO
- || (errno == EINVAL && regset->type == OPTIONAL_REGS))
+ || (errno == EINVAL
+ && (regset->type == OPTIONAL_REGS
+ || regset->type == OPTIONAL_RUNTIME_REGS)))
{
/* If we get EIO on a regset, or an EINVAL and the regset is
- optional, do not try it again for this process mode. */
+ optional, do not try it again for this process mode.
+ Even if the regset can be enabled at runtime it is safe
+ to deactivate the regset in case of EINVAL, as we know
+ the regset itself was the invalid argument of the ptrace
+ call which means that it's unsupported by the kernel. */
disable_regset (regsets_info, regset);
}
- else if (errno == ENODATA)
+ else if (errno == ENODATA
+ || (errno == ENODEV
+ && regset->type == OPTIONAL_RUNTIME_REGS)
+ || errno == ESRCH)
{
- /* ENODATA may be returned if the regset is currently
- not "active". This can happen in normal operation,
- so suppress the warning in this case. */
- }
- else if (errno == ESRCH)
- {
- /* At this point, ESRCH should mean the process is
- already gone, in which case we simply ignore attempts
- to read its registers. */
+ /* ENODATA or ENODEV may be returned if the regset is
+ currently not "active". For ENODEV we additionally check
+ if the register set is of type OPTIONAL_RUNTIME_REGS.
+ This can happen in normal operation, so suppress the
+ warning in this case.
+ ESRCH should mean the process is already gone at this
+ point, in which case we simply ignore attempts to read
+ its registers. */
}
else
{
@@ -5104,12 +5112,26 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info,
if (res < 0)
{
if (errno == EIO
- || (errno == EINVAL && regset->type == OPTIONAL_REGS))
+ || (errno == EINVAL
+ && (regset->type == OPTIONAL_REGS
+ || regset->type == OPTIONAL_RUNTIME_REGS)))
{
/* If we get EIO on a regset, or an EINVAL and the regset is
- optional, do not try it again for this process mode. */
+ optional, do not try it again for this process mode.
+ Even if the regset can be enabled at runtime it is safe
+ to deactivate the regset in case of EINVAL, as we know
+ the regset itself was the invalid argument of the ptrace
+ call which means that it's unsupported by the kernel. */
disable_regset (regsets_info, regset);
}
+ else if (errno == ENODEV
+ && regset->type == OPTIONAL_RUNTIME_REGS)
+ {
+ /* If we get ENODEV on a regset and the regset can be
+ enabled at runtime try it again for this process mode.
+ This can happen in normal operation, so suppress the
+ warning in this case. */
+ }
else if (errno == ESRCH)
{
/* At this point, ESRCH should mean the process is
@@ -6033,7 +6055,7 @@ linux_process_target::supports_pid_to_exec_file ()
const char *
linux_process_target::pid_to_exec_file (int pid)
{
- return linux_proc_pid_to_exec_file (pid);
+ return linux_proc_pid_to_exec_file (pid, linux_ns_same (pid, LINUX_NS_MNT));
}
bool
@@ -6050,6 +6072,12 @@ linux_process_target::multifs_open (int pid, const char *filename,
}
int
+linux_process_target::multifs_lstat (int pid, const char *filename, struct stat *sb)
+{
+ return linux_mntns_lstat (pid, filename, sb);
+}
+
+int
linux_process_target::multifs_unlink (int pid, const char *filename)
{
return linux_mntns_unlink (pid, filename);
diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
index 7d3e35f..5710e49 100644
--- a/gdbserver/linux-low.h
+++ b/gdbserver/linux-low.h
@@ -42,7 +42,12 @@ enum regset_type {
GENERAL_REGS,
FP_REGS,
EXTENDED_REGS,
- OPTIONAL_REGS, /* Do not error if the regset cannot be accessed. */
+ OPTIONAL_REGS, /* Do not error if the regset cannot be accessed.
+ Disable the regset instead. */
+ OPTIONAL_RUNTIME_REGS, /* Some optional regsets can only be accessed
+ dependent on the execution flow. For such
+ access errors don't show a warning and don't
+ disable the regset. */
};
/* The arch's regsets array initializer must be terminated with a NULL
@@ -304,6 +309,8 @@ public:
int multifs_open (int pid, const char *filename, int flags,
mode_t mode) override;
+ int multifs_lstat (int pid, const char *filename, struct stat *st) override;
+
int multifs_unlink (int pid, const char *filename) override;
ssize_t multifs_readlink (int pid, const char *filename, char *buf,
diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc
index 918630d..44257d5 100644
--- a/gdbserver/linux-x86-low.cc
+++ b/gdbserver/linux-x86-low.cc
@@ -253,7 +253,8 @@ static const int x86_64_regmap[] =
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
- -1 /* pkru */
+ -1, /* pkru */
+ -1 /* CET user mode register PL3_SSP. */
};
#define X86_64_NUM_REGS (sizeof (x86_64_regmap) / sizeof (x86_64_regmap[0]))
@@ -406,6 +407,18 @@ x86_target::low_cannot_fetch_register (int regno)
}
static void
+x86_fill_ssp_reg (regcache *regcache, void *buf)
+{
+ collect_register_by_name (regcache, "pl3_ssp", buf);
+}
+
+static void
+x86_store_ssp_reg (regcache *regcache, const void *buf)
+{
+ supply_register_by_name (regcache, "pl3_ssp", buf);
+}
+
+static void
collect_register_i386 (struct regcache *regcache, int regno, void *buf)
{
collect_register (regcache, regno, buf);
@@ -544,6 +557,8 @@ static struct regset_info x86_regsets[] =
x86_fill_gregset, x86_store_gregset },
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_X86_XSTATE, 0,
EXTENDED_REGS, x86_fill_xstateregset, x86_store_xstateregset },
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_X86_SHSTK, 0,
+ OPTIONAL_RUNTIME_REGS, x86_fill_ssp_reg, x86_store_ssp_reg },
# ifndef __x86_64__
# ifdef HAVE_PTRACE_GETFPXREGS
{ PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, 0, sizeof (elf_fpxregset_t),
@@ -873,7 +888,7 @@ x86_linux_read_description ()
bool have_ptrace_getregset_was_unknown
= have_ptrace_getregset == TRIBOOL_UNKNOWN;
- /* Get pointers to where we should store the xcr0 and xsave_layout
+ /* Get pointers to where we should store the xstate_bv and xsave_layout
values. These will be filled in by x86_linux_tdesc_for_tid the first
time that the function is called. Subsequent calls will not modify
the stored values. */
@@ -894,7 +909,23 @@ x86_linux_read_description ()
regset++)
{
if (regset->get_request == PTRACE_GETREGSET)
- regset->size = xsave_len;
+ {
+ if (regset->nt_type == NT_X86_XSTATE)
+ regset->size = xsave_len;
+ else if (regset->nt_type == NT_X86_SHSTK)
+ {
+ /* We must configure the size of the NT_X86_SHSTK regset
+ from non-zero value to it's appropriate size, even though
+ the ptrace call is only tested for NT_X86_XSTATE request,
+ because the NT_X86_SHSTK regset is of type
+ OPTIONAL_RUNTIME_REGS. A ptrace call with NT_X86_SHSTK
+ request may only be successful later on, once shadow
+ stack is enabled for the current thread. */
+ regset->size = sizeof (CORE_ADDR);
+ }
+ else
+ gdb_assert_not_reached ("invalid regset type.");
+ }
else if (regset->type != GENERAL_REGS)
regset->size = 0;
}
@@ -2887,17 +2918,16 @@ x86_target::get_ipa_tdesc_idx ()
|| tdesc == tdesc_amd64_linux_no_xml.get ()
#endif /* __x86_64__ */
);
- return x86_linux_xcr0_to_tdesc_idx (X86_XSTATE_SSE_MASK);
+ return x86_linux_xstate_bv_to_tdesc_idx (X86_XSTATE_SSE_MASK);
}
- /* The xcr0 value and xsave layout value are cached when the target
+ /* The xstate_bv value and xsave layout value are cached when the target
description is read. Grab their cache location, and use the cached
value to calculate a tdesc index. */
std::pair<uint64_t *, x86_xsave_layout *> storage
= i387_get_xsave_storage ();
- uint64_t xcr0 = *storage.first;
- return x86_linux_xcr0_to_tdesc_idx (xcr0);
+ return x86_linux_xstate_bv_to_tdesc_idx (*storage.first);
}
/* The linux target ops object. */
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 0ce40ee..669c761 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -51,6 +51,9 @@
#include "gdbsupport/scoped_restore.h"
#include "gdbsupport/search.h"
#include "gdbsupport/gdb_argv_vec.h"
+#include "gdbsupport/remote-args.h"
+
+#include <getopt.h>
/* PBUFSIZ must also be at least as big as IPA_CMD_BUF_SIZE, because
the client state data is passed directly to some agent
@@ -140,6 +143,7 @@ unsigned long signal_pid;
in gdbserver, for the sake of testing GDB against stubs that don't
support them. */
bool disable_packet_vCont;
+bool disable_packet_vCont_step;
bool disable_packet_Tthread;
bool disable_packet_qC;
bool disable_packet_qfThreadInfo;
@@ -1017,20 +1021,15 @@ handle_general_set (char *own_buf)
});
}
- for (const auto &iter : set_options)
- {
- thread_info *thread = iter.first;
- gdb_thread_options options = iter.second;
-
- if (thread->thread_options != options)
- {
- threads_debug_printf ("[options for %s are now %s]\n",
- target_pid_to_str (thread->id).c_str (),
- to_string (options).c_str ());
+ for (const auto &[thread, options] : set_options)
+ if (thread->thread_options != options)
+ {
+ threads_debug_printf ("[options for %s are now %s]\n",
+ target_pid_to_str (thread->id).c_str (),
+ to_string (options).c_str ());
- thread->thread_options = options;
- }
- }
+ thread->thread_options = options;
+ }
write_ok (own_buf);
return;
@@ -2863,7 +2862,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
{
char *end_buf = own_buf + strlen (own_buf);
sprintf (end_buf, ";QThreadOptions=%s",
- phex_nz (supported_options, sizeof (supported_options)));
+ phex_nz (supported_options));
}
strcat (own_buf, ";QThreadEvents+");
@@ -3465,7 +3464,7 @@ handle_v_run (char *own_buf)
else
program_path.set (new_program_name.get ());
- program_args = construct_inferior_arguments (new_argv.get (), true);
+ program_args = gdb::remote_args::join (new_argv.get ());
try
{
@@ -3540,9 +3539,10 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
{
strcpy (own_buf, "vCont;c;C;t");
- if (target_supports_hardware_single_step ()
- || target_supports_software_single_step ()
- || !cs.vCont_supported)
+ if (!disable_packet_vCont_step
+ && (target_supports_hardware_single_step ()
+ || target_supports_software_single_step ()
+ || !cs.vCont_supported))
{
/* If target supports single step either by hardware or by
software, add actions s and S to the list of supported
@@ -3812,7 +3812,7 @@ static void
gdbserver_version (void)
{
printf ("GNU gdbserver %s%s\n"
- "Copyright (C) 2024 Free Software Foundation, Inc.\n"
+ "Copyright (C) 2025 Free Software Foundation, Inc.\n"
"gdbserver is free software, covered by the "
"GNU General Public License.\n"
"This gdbserver was configured as \"%s\"\n",
@@ -3875,7 +3875,7 @@ gdbserver_usage (FILE *stream)
" --disable-packet=OPT1[,OPT2,...]\n"
" Disable support for RSP packets or features.\n"
" Options:\n"
- " vCont, T, Tthread, qC, qfThreadInfo and \n"
+ " vCont, vConts, T, Tthread, qC, qfThreadInfo and\n"
" threads (disable all threading packets).\n"
"\n"
"For more information, consult the GDB manual (available as on-line \n"
@@ -4107,14 +4107,9 @@ static void test_registers_raw_compare_zero_length ()
[[noreturn]] static void
captured_main (int argc, char *argv[])
{
- int bad_attach;
int pid;
- char *arg_end;
- const char *port = NULL;
- char **next_arg = &argv[1];
- volatile int multi_mode = 0;
- volatile int attach = 0;
- int was_running;
+ volatile bool multi_mode = false;
+ volatile bool attach = false;
bool selftest = false;
#if GDB_SELF_TEST
std::vector<const char *> selftest_filters;
@@ -4134,184 +4129,280 @@ captured_main (int argc, char *argv[])
safe_strerror (errno));
}
- while (*next_arg != NULL && **next_arg == '-')
- {
- if (strcmp (*next_arg, "--version") == 0)
+ enum opts { OPT_VERSION = 1, OPT_HELP, OPT_ATTACH, OPT_MULTI, OPT_WRAPPER,
+ OPT_DEBUG, OPT_DEBUG_FILE, OPT_DEBUG_FORMAT, OPT_DISABLE_PACKET,
+ OPT_DISABLE_RANDOMIZATION, OPT_NO_DISABLE_RANDOMIZATION,
+ OPT_STARTUP_WITH_SHELL, OPT_NO_STARTUP_WITH_SHELL, OPT_ONCE,
+ OPT_SELFTEST,
+ };
+
+ static struct option longopts[] =
+ {
+ {"version", no_argument, nullptr, OPT_VERSION},
+ {"help", no_argument, nullptr, OPT_HELP},
+ {"attach", no_argument, nullptr, OPT_ATTACH},
+ {"multi", no_argument, nullptr, OPT_MULTI},
+ {"wrapper", no_argument, nullptr, OPT_WRAPPER},
+ {"debug", optional_argument, nullptr, OPT_DEBUG},
+ {"debug-file", required_argument, nullptr, OPT_DEBUG_FILE},
+ {"debug-format", required_argument, nullptr, OPT_DEBUG_FORMAT},
+ /* --disable-packet is optional_argument only so that we can print a
+ better help list when the argument is missing. */
+ {"disable-packet", optional_argument, nullptr, OPT_DISABLE_PACKET},
+ {"disable-randomization", no_argument, nullptr,
+ OPT_DISABLE_RANDOMIZATION},
+ {"no-disable-randomization", no_argument, nullptr,
+ OPT_NO_DISABLE_RANDOMIZATION},
+ {"startup-with-shell", no_argument, nullptr, OPT_STARTUP_WITH_SHELL},
+ {"no-startup-with-shell", no_argument, nullptr,
+ OPT_NO_STARTUP_WITH_SHELL},
+ {"once", no_argument, nullptr, OPT_ONCE},
+ {"selftest", optional_argument, nullptr, OPT_SELFTEST},
+ {nullptr, no_argument, nullptr, 0}
+ };
+
+ /* Ask getopt_long not to print error messages, we'll do that ourselves.
+ Look for handling of '?' from getopt_long. */
+ opterr = 0;
+
+ int optc, longindex;
+
+ /* The '+' passed to getopt_long here stops ARGV being reordered. In a
+ command line like: 'gdbserver PORT program --arg1 --arg2', the
+ '--arg1' and '--arg2' are arguments to 'program', not to gdbserver.
+ If getopt_long is free to reorder ARGV then it will try to steal those
+ arguments for itself. */
+ while ((longindex = -1,
+ optc = getopt_long (argc, argv, "+", longopts, &longindex)) != -1)
+ {
+ /* We only support '--option=value' form, not '--option value'. To
+ achieve this, if global OPTARG points to the start of the previous
+ ARGV entry, then we must have used the second (unsupported) form,
+ so set OPTARG to NULL and decrement OPTIND to make it appear that
+ there was no value passed. If the option requires an argument,
+ then this means we should convert OPTC to '?' to indicate an
+ error. */
+ if (longindex != -1
+ && longopts[longindex].has_arg != no_argument)
{
- gdbserver_version ();
- exit (0);
+ if (optarg == argv[optind - 1])
+ {
+ optarg = nullptr;
+ --optind;
+ }
+
+ if (longopts[longindex].has_arg == required_argument
+ && optarg == nullptr)
+ optc = '?';
}
- else if (strcmp (*next_arg, "--help") == 0)
+
+ switch (optc)
{
+ case OPT_VERSION:
+ gdbserver_version ();
+ exit (0);
+
+ case OPT_HELP:
gdbserver_usage (stdout);
exit (0);
- }
- else if (strcmp (*next_arg, "--attach") == 0)
- attach = 1;
- else if (strcmp (*next_arg, "--multi") == 0)
- multi_mode = 1;
- else if (strcmp (*next_arg, "--wrapper") == 0)
- {
- char **tmp;
- next_arg++;
+ case OPT_ATTACH:
+ attach = true;
+ break;
- tmp = next_arg;
- while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
- {
- wrapper_argv += *next_arg;
- wrapper_argv += ' ';
- next_arg++;
- }
+ case OPT_MULTI:
+ multi_mode = true;
+ break;
- if (!wrapper_argv.empty ())
- {
- /* Erase the last whitespace. */
- wrapper_argv.erase (wrapper_argv.end () - 1);
- }
+ case OPT_WRAPPER:
+ {
+ int original_optind = optind;
- if (next_arg == tmp || *next_arg == NULL)
- {
- gdbserver_usage (stderr);
- exit (1);
- }
+ while (argv[optind] != nullptr
+ && strcmp (argv[optind], "--") != 0)
+ {
+ wrapper_argv += argv[optind];
+ wrapper_argv += ' ';
+ ++optind;
+ }
- /* Consume the "--". */
- *next_arg = NULL;
- }
- else if (startswith (*next_arg, "--debug="))
- {
- try
- {
- parse_debug_options ((*next_arg) + sizeof ("--debug=") - 1);
- }
- catch (const gdb_exception_error &exception)
- {
- fflush (stdout);
- fprintf (stderr, "gdbserver: %s\n", exception.what ());
- exit (1);
- }
- }
- else if (strcmp (*next_arg, "--debug") == 0)
- {
- try
- {
- parse_debug_options ("");
- }
- catch (const gdb_exception_error &exception)
- {
- fflush (stdout);
- fprintf (stderr, "gdbserver: %s\n", exception.what ());
- exit (1);
- }
- }
- else if (startswith (*next_arg, "--debug-format="))
- {
- std::string error_msg
- = parse_debug_format_options ((*next_arg)
- + sizeof ("--debug-format=") - 1, 0);
+ if (!wrapper_argv.empty ())
+ {
+ /* Erase the last whitespace. */
+ wrapper_argv.erase (wrapper_argv.end () - 1);
+ }
- if (!error_msg.empty ())
- {
- fprintf (stderr, "%s", error_msg.c_str ());
- exit (1);
- }
- }
- else if (startswith (*next_arg, "--debug-file="))
- debug_set_output ((*next_arg) + sizeof ("--debug-file=") -1);
- else if (strcmp (*next_arg, "--disable-packet") == 0)
- {
- gdbserver_show_disableable (stdout);
- exit (0);
- }
- else if (startswith (*next_arg, "--disable-packet="))
- {
- char *packets = *next_arg += sizeof ("--disable-packet=") - 1;
- char *saveptr;
- for (char *tok = strtok_r (packets, ",", &saveptr);
- tok != NULL;
- tok = strtok_r (NULL, ",", &saveptr))
- {
- if (strcmp ("vCont", tok) == 0)
- disable_packet_vCont = true;
- else if (strcmp ("Tthread", tok) == 0)
- disable_packet_Tthread = true;
- else if (strcmp ("qC", tok) == 0)
- disable_packet_qC = true;
- else if (strcmp ("qfThreadInfo", tok) == 0)
- disable_packet_qfThreadInfo = true;
- else if (strcmp ("T", tok) == 0)
- disable_packet_T = true;
- else if (strcmp ("threads", tok) == 0)
- {
+ if (original_optind == optind || argv[optind] == nullptr)
+ {
+ gdbserver_usage (stderr);
+ exit (1);
+ }
+
+ /* Consume the "--". */
+ ++optind;
+ }
+ break;
+
+ case OPT_DEBUG:
+ {
+ const char *debug_opt = (optarg == nullptr) ? "" : optarg;
+ try
+ {
+ parse_debug_options (debug_opt);
+ }
+ catch (const gdb_exception_error &exception)
+ {
+ fflush (stdout);
+ fprintf (stderr, "gdbserver: %s\n", exception.what ());
+ exit (1);
+ }
+ }
+ break;
+
+ case OPT_DEBUG_FILE:
+ {
+ gdb_assert (optarg != nullptr);
+ debug_set_output (optarg);
+ }
+ break;
+
+ case OPT_DEBUG_FORMAT:
+ {
+ gdb_assert (optarg != nullptr);
+ std::string error_msg
+ = parse_debug_format_options (optarg, 0);
+
+ if (!error_msg.empty ())
+ {
+ fprintf (stderr, "%s", error_msg.c_str ());
+ exit (1);
+ }
+ }
+ break;
+
+ case OPT_DISABLE_PACKET:
+ {
+ char *packets = optarg;
+ if (packets == nullptr)
+ {
+ gdbserver_show_disableable (stdout);
+ exit (1);
+ }
+ char *saveptr;
+ for (char *tok = strtok_r (packets, ",", &saveptr);
+ tok != nullptr;
+ tok = strtok_r (nullptr, ",", &saveptr))
+ {
+ if (strcmp ("vCont", tok) == 0)
disable_packet_vCont = true;
+ else if (strcmp ("vConts", tok) == 0)
+ disable_packet_vCont_step = true;
+ else if (strcmp ("Tthread", tok) == 0)
disable_packet_Tthread = true;
+ else if (strcmp ("qC", tok) == 0)
disable_packet_qC = true;
+ else if (strcmp ("qfThreadInfo", tok) == 0)
disable_packet_qfThreadInfo = true;
- }
- else
- {
- fprintf (stderr, "Don't know how to disable \"%s\".\n\n",
- tok);
- gdbserver_show_disableable (stderr);
- exit (1);
- }
- }
- }
- else if (strcmp (*next_arg, "-") == 0)
- {
- /* "-" specifies a stdio connection and is a form of port
- specification. */
- port = STDIO_CONNECTION_NAME;
+ else if (strcmp ("T", tok) == 0)
+ disable_packet_T = true;
+ else if (strcmp ("threads", tok) == 0)
+ {
+ disable_packet_vCont = true;
+ disable_packet_Tthread = true;
+ disable_packet_qC = true;
+ disable_packet_qfThreadInfo = true;
+ }
+ else
+ {
+ fprintf (stderr, "Don't know how to disable \"%s\".\n\n",
+ tok);
+ gdbserver_show_disableable (stderr);
+ exit (1);
+ }
+ }
+ }
+ break;
- /* Implying --once here prevents a hang after stdin has been closed. */
- run_once = true;
+ case OPT_DISABLE_RANDOMIZATION:
+ cs.disable_randomization = 1;
+ break;
- next_arg++;
+ case OPT_NO_DISABLE_RANDOMIZATION:
+ cs.disable_randomization = 0;
+ break;
+
+ case OPT_STARTUP_WITH_SHELL:
+ startup_with_shell = true;
break;
- }
- else if (strcmp (*next_arg, "--disable-randomization") == 0)
- cs.disable_randomization = 1;
- else if (strcmp (*next_arg, "--no-disable-randomization") == 0)
- cs.disable_randomization = 0;
- else if (strcmp (*next_arg, "--startup-with-shell") == 0)
- startup_with_shell = true;
- else if (strcmp (*next_arg, "--no-startup-with-shell") == 0)
- startup_with_shell = false;
- else if (strcmp (*next_arg, "--once") == 0)
- run_once = true;
- else if (strcmp (*next_arg, "--selftest") == 0)
- selftest = true;
- else if (startswith (*next_arg, "--selftest="))
- {
- selftest = true;
+ case OPT_NO_STARTUP_WITH_SHELL:
+ startup_with_shell = false;
+ break;
+
+ case OPT_ONCE:
+ run_once = true;
+ break;
+
+ case OPT_SELFTEST:
+ {
+ selftest = true;
+ if (optarg != nullptr)
+ {
#if GDB_SELF_TEST
- const char *filter = *next_arg + strlen ("--selftest=");
- if (*filter == '\0')
- {
- fprintf (stderr, _("Error: selftest filter is empty.\n"));
- exit (1);
- }
+ if (*optarg == '\0')
+ {
+ fprintf (stderr, _("Error: selftest filter is empty.\n"));
+ exit (1);
+ }
- selftest_filters.push_back (filter);
+ selftest_filters.push_back (optarg);
#endif
- }
- else
- {
- fprintf (stderr, "Unknown argument: %s\n", *next_arg);
+ }
+ }
+ break;
+
+ case '?':
+ /* Figuring out which element of ARGV contained the invalid
+ argument is not simple. There are a couple of cases we need
+ to consider.
+
+ (1) Something like '-x'. gdbserver doesn't support single
+ character options, so a '-' followed by a character is
+ always invalid. In this case global OPTOPT will be set to
+ 'x', and global OPTIND will point to the next ARGV entry.
+
+ (2) Something like '-xyz'. gdbserver doesn't support single
+ dash arguments for its command line options. The
+ getopt_long call treats this like '-x -y -z', in which
+ case global OPTOPT is set to 'x' and global OPTIND will
+ point to this ARGV entry.
+
+ (3) Something like '--unknown'. This is just an unknown
+ double dash argument. Global OPTOPT is set to '\0', and
+ global OPTIND points to the next ARGV entry. */
+ std::string bad_arg;
+ if (optopt == '\0' || argv[optind] == nullptr
+ || argv[optind][0] != '-' || argv[optind][1] != optopt)
+ bad_arg = argv[optind - 1];
+ else
+ bad_arg = argv[optind];
+
+ fprintf (stderr, "Unknown argument: %s\n", bad_arg.c_str ());
exit (1);
}
-
- next_arg++;
- continue;
}
- if (port == NULL)
+ const char *port = argv[optind];
+ ++optind;
+ if (port != nullptr && strcmp (port, "-") == 0)
{
- port = *next_arg;
- next_arg++;
+ port = STDIO_CONNECTION_NAME;
+
+ /* Implying --once here prevents a hang after stdin has been closed. */
+ run_once = true;
}
+
+ char **next_arg = &argv[optind];
if ((port == NULL || (!attach && !multi_mode && *next_arg == NULL))
&& !selftest)
{
@@ -4332,24 +4423,25 @@ captured_main (int argc, char *argv[])
if (port != NULL)
remote_prepare (port);
- bad_attach = 0;
+ bool bad_attach = false;
pid = 0;
/* --attach used to come after PORT, so allow it there for
compatibility. */
if (*next_arg != NULL && strcmp (*next_arg, "--attach") == 0)
{
- attach = 1;
+ attach = true;
next_arg++;
}
+ char *arg_end;
if (attach
&& (*next_arg == NULL
|| (*next_arg)[0] == '\0'
|| (pid = strtoul (*next_arg, &arg_end, 0)) == 0
|| *arg_end != '\0'
|| next_arg[1] != NULL))
- bad_attach = 1;
+ bad_attach = true;
if (bad_attach)
{
@@ -4414,11 +4506,12 @@ captured_main (int argc, char *argv[])
if (current_thread != nullptr)
current_process ()->dlls_changed = false;
+ bool was_running;
if (cs.last_status.kind () == TARGET_WAITKIND_EXITED
|| cs.last_status.kind () == TARGET_WAITKIND_SIGNALLED)
- was_running = 0;
+ was_running = false;
else
- was_running = 1;
+ was_running = true;
if (!was_running && !multi_mode)
error ("No program to debug");
diff --git a/gdbserver/server.h b/gdbserver/server.h
index 5609584..b9dacb8 100644
--- a/gdbserver/server.h
+++ b/gdbserver/server.h
@@ -68,6 +68,7 @@ void initialize_low ();
extern bool server_waiting;
extern bool disable_packet_vCont;
+extern bool disable_packet_vCont_step;
extern bool disable_packet_Tthread;
extern bool disable_packet_qC;
extern bool disable_packet_qfThreadInfo;
diff --git a/gdbserver/target.cc b/gdbserver/target.cc
index 4838b39..c400174c 100644
--- a/gdbserver/target.cc
+++ b/gdbserver/target.cc
@@ -258,7 +258,7 @@ target_pid_to_str (ptid_t ptid)
else if (ptid.tid () != 0)
return string_printf("Thread %d.0x%s",
ptid.pid (),
- phex_nz (ptid.tid (), sizeof (ULONGEST)));
+ phex_nz (ptid.tid ()));
else if (ptid.lwp () != 0)
return string_printf("LWP %d.%ld",
ptid.pid (), ptid.lwp ());
@@ -773,6 +773,13 @@ process_stratum_target::multifs_open (int pid, const char *filename,
}
int
+process_stratum_target::multifs_lstat (int pid, const char *filename,
+ struct stat *sb)
+{
+ return lstat (filename, sb);
+}
+
+int
process_stratum_target::multifs_unlink (int pid, const char *filename)
{
return unlink (filename);
diff --git a/gdbserver/target.h b/gdbserver/target.h
index af788e2..66ca72f 100644
--- a/gdbserver/target.h
+++ b/gdbserver/target.h
@@ -31,6 +31,7 @@
#include "gdbsupport/btrace-common.h"
#include <vector>
#include "gdbsupport/byte-vector.h"
+#include <sys/stat.h>
struct emit_ops;
struct process_info;
@@ -441,6 +442,12 @@ public:
virtual int multifs_open (int pid, const char *filename,
int flags, mode_t mode);
+ /* Multiple-filesystem-aware lstat. Like lstat(2), but operating in
+ the filesystem as it appears to process PID. Systems where all
+ processes share a common filesystem should not override this.
+ The default behavior is to use lstat(2). */
+ virtual int multifs_lstat (int pid, const char *filename, struct stat *sb);
+
/* Multiple-filesystem-aware unlink. Like unlink(2), but operates
in the filesystem as it appears to process PID. Systems where
all processes share a common filesystem should not override this.
diff --git a/gdbserver/tracepoint.cc b/gdbserver/tracepoint.cc
index 715cc63..b308c82 100644
--- a/gdbserver/tracepoint.cc
+++ b/gdbserver/tracepoint.cc
@@ -3461,8 +3461,8 @@ cmd_qtstatus (char *packet)
free_space (), phex_nz (trace_buffer_hi - trace_buffer_lo, 0),
circular_trace_buffer,
disconnected_tracing,
- phex_nz (tracing_start_time, sizeof (tracing_start_time)),
- phex_nz (tracing_stop_time, sizeof (tracing_stop_time)),
+ phex_nz (tracing_start_time),
+ phex_nz (tracing_stop_time),
buf1, buf2);
}
@@ -4990,7 +4990,7 @@ build_traceframe_info_xml (char blocktype, unsigned char *dataptr, void *data)
dataptr += sizeof (mlen);
string_xml_appendf (*buffer,
"<memory start=\"0x%s\" length=\"0x%s\"/>\n",
- paddress (maddr), phex_nz (mlen, sizeof (mlen)));
+ paddress (maddr), phex_nz (mlen));
break;
}
case 'V':
diff --git a/gdbserver/utils.cc b/gdbserver/utils.cc
index 092fe47..a86405e 100644
--- a/gdbserver/utils.cc
+++ b/gdbserver/utils.cc
@@ -102,5 +102,5 @@ internal_vwarning (const char *file, int line, const char *fmt, va_list args)
const char *
paddress (CORE_ADDR addr)
{
- return phex_nz (addr, sizeof (CORE_ADDR));
+ return phex_nz (addr);
}