aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog-202112
-rw-r--r--gdb/Makefile.in10
-rw-r--r--gdb/NEWS18
-rw-r--r--gdb/config.in6
-rwxr-xr-xgdb/configure100
-rw-r--r--gdb/configure.ac17
-rw-r--r--gdb/doc/ChangeLog-1991-202110
-rw-r--r--gdb/doc/Makefile.in1
-rw-r--r--gdb/doc/gdb.texinfo4
-rw-r--r--gdb/doc/poke.texi371
-rw-r--r--gdb/poke.c789
-rw-r--r--gdb/poke/gdb.pk42
-rw-r--r--gdb/testsuite/gdb.poke/poke-types.c29
-rw-r--r--gdb/testsuite/gdb.poke/poke-types.exp36
-rw-r--r--gdb/testsuite/lib/gdb.exp7
-rw-r--r--gdb/top.c10
-rw-r--r--intl/aclocal.m44
-rwxr-xr-xintl/configure19
-rw-r--r--libiberty/aclocal.m44
-rwxr-xr-xlibiberty/configure26
20 files changed, 1495 insertions, 20 deletions
diff --git a/gdb/ChangeLog-2021 b/gdb/ChangeLog-2021
index f1071a7..e9dda50 100644
--- a/gdb/ChangeLog-2021
+++ b/gdb/ChangeLog-2021
@@ -1,3 +1,4 @@
+<<<<<<< HEAD:gdb/ChangeLog-2021
2021-07-06 Tom de Vries <tdevries@suse.de>
* dwarf2/read.c (scan_partial_symbols): Skip top-level imports of
@@ -576,6 +577,17 @@
* silent-rules.mk (ECHO_CCLD, ECHO_AR, ECHO_RANLIB): New.
2021-06-16 Tom de Vries <tdevries@suse.de>
+=======
+2021-05-10 Jose E. Marchesi <jose.marchesi@oracle.com>
+
+ * configure.ac: Support --enable-poke.
+ * configure: Regenerate.
+ * Makefile.in (POKE_OBS): Define based on @POKE_OBS@.
+ (DEPFILES): Add POKE_OBS.
+ * poke.c: New file.
+
+2021-05-07 Tom de Vries <tdevries@suse.de>
+>>>>>>> Integrate GNU poke in GDB:gdb/ChangeLog
PR symtab/26327
* dwarf2/cu.h (dwarf2_cu::ancestor): Remove.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 4049754..a535063 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -691,6 +691,9 @@ SER_HARDWIRE = @SER_HARDWIRE@
# This is remote-sim.o if a simulator is to be linked in.
SIM_OBS = @SIM_OBS@
+# Object files to integrate with GNU poke.
+POKE_OBS = @POKE_OBS@
+
# Target-dependent object files.
TARGET_OBS = @TARGET_OBS@
@@ -1617,7 +1620,8 @@ HFILES_WITH_SRCDIR = \
# variables analogous to SER_HARDWIRE which get defaulted in this
# Makefile.in
-DEPFILES = $(TARGET_OBS) $(SER_HARDWIRE) $(NATDEPFILES) $(SIM_OBS)
+DEPFILES = $(TARGET_OBS) $(SER_HARDWIRE) $(NATDEPFILES) $(SIM_OBS) \
+ $(POKE_OBS)
ALLDEPFILES = \
arch/aarch32.c \
@@ -2078,6 +2082,10 @@ install-guile:
install-python:
$(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(GDB_DATADIR)/python/gdb
+install-poke:
+ $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)/$(GDB_DATADIR)/poke
+ $(INSTALL) -m 644 $(srcdir)/poke/gdb.pk $(DESTDIR)/$(GDB_DATADIR)/poke
+
uninstall: force $(CONFIG_UNINSTALL)
transformed_name=`t='$(program_transform_name)'; \
echo gdb | sed -e $$t` ; \
diff --git a/gdb/NEWS b/gdb/NEWS
index 54b5da2..d9ca1a4 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -885,6 +885,12 @@ GNU/Linux/OpenRISC or1k*-*-linux*
need to focus on the command window for such key combinations to
work.
+* DDB now supports GNU poke, the extensible editor for structured
+ binary data.
+
+ To build GDB with poke support, pass --with-poke to configure (this
+ requires libpoke, the GNU poke library).
+
* New commands
set debug event-loop
@@ -950,6 +956,18 @@ show python dont-write-bytecode
When set to 'auto' (the default) Python will check the
PYTHONDONTWRITEBYTECODE environment variable.
+poke STR
+ Execute a Poke statement or declaration.
+
+poke-add-type EXPR
+ Make Poke aware of a GDB type given an expression.
+
+poke-add-types REGEXP
+ Make Poke aware of GDB types based on a regexp.
+
+poke-dump-types
+ Dump the definition of all the GDB types known to poke.
+
* Changed commands
break [PROBE_MODIFIER] [LOCATION] [thread THREADNUM]
diff --git a/gdb/config.in b/gdb/config.in
index a7da88b..b089001 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -259,6 +259,9 @@
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
+/* Define to 1 if you have the `poke' library (-lpoke). */
+#undef HAVE_LIBPOKE
+
/* Define to 1 if you have the <libunwind-ia64.h> header file. */
#undef HAVE_LIBUNWIND_IA64_H
@@ -316,6 +319,9 @@
/* Define to 1 if you have the `pipe2' function. */
#undef HAVE_PIPE2
+/* Define if building integration with GNU poke. */
+#undef HAVE_POKE
+
/* Define to 1 if you have the `poll' function. */
#undef HAVE_POLL
diff --git a/gdb/configure b/gdb/configure
index 5bb2a07..0031973 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -757,6 +757,7 @@ ZSTD_LIBS
ZSTD_CFLAGS
zlibinc
zlibdir
+POKE_OBS
MIG
WINDRES
DLLTOOL
@@ -874,6 +875,7 @@ infodir
docdir
oldincludedir
includedir
+runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -922,6 +924,7 @@ enable_profiling
enable_codesign
with_pkgversion
with_bugurl
+with_poke
with_system_zlib
with_zstd
enable_rpath
@@ -1033,6 +1036,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}'
@@ -1285,6 +1289,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1422,7 +1435,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir
+ libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1575,6 +1588,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -1680,6 +1694,7 @@ Optional Packages:
library
--with-pkgversion=PKG Use PKG in the version string in place of "GDB"
--with-bugurl=URL Direct users to URL to report a bug
+ --with-poke Build GDB with poke support (default is NO)
--with-system-zlib use installed libz
--with-zstd support zstd compressed debug sections
(default=auto)
@@ -4944,7 +4959,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -4990,7 +5005,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -5014,7 +5029,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -5059,7 +5074,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -5083,7 +5098,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -11448,7 +11463,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11451 "configure"
+#line 11466 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11554,7 +11569,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11557 "configure"
+#line 11572 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -19585,6 +19600,73 @@ if test "$ac_res" != no; then :
fi
+# Integration with GNU poke is done through the libpoke library.
+
+# Check whether --with-poke was given.
+if test "${with_poke+set}" = set; then :
+ withval=$with_poke; with_poke=$withval
+else
+ with_poke=no
+fi
+
+if test "x$with_poke" = "xyes"; then
+ # Note that we need a libpoke with support for registering foreign
+ # IO devices, hence the symbol pk_register_iod.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pk_register_iod in -lpoke" >&5
+$as_echo_n "checking for pk_register_iod in -lpoke... " >&6; }
+if ${ac_cv_lib_poke_pk_register_iod+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpoke $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pk_register_iod ();
+int
+main ()
+{
+return pk_register_iod ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_poke_pk_register_iod=yes
+else
+ ac_cv_lib_poke_pk_register_iod=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_poke_pk_register_iod" >&5
+$as_echo "$ac_cv_lib_poke_pk_register_iod" >&6; }
+if test "x$ac_cv_lib_poke_pk_register_iod" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPOKE 1
+_ACEOF
+
+ LIBS="-lpoke $LIBS"
+
+fi
+
+ POKE_OBS="poke.o"
+
+$as_echo "#define HAVE_POKE 1" >>confdefs.h
+
+ CONFIG_INSTALL="$CONFIG_INSTALL install-poke"
+else
+ POKE_OBS=
+fi
+
+
# Link in zlib/zstd if we can. This allows us to read compressed debug
# sections.
@@ -24063,6 +24145,8 @@ main ()
if (*(data + i) != *(data3 + i))
return 14;
close (fd);
+ free (data);
+ free (data3);
return 0;
}
_ACEOF
diff --git a/gdb/configure.ac b/gdb/configure.ac
index fb43cd1..dd90e9f 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -506,6 +506,23 @@ AC_SEARCH_LIBS(gethostbyname, nsl)
# Some systems (e.g. Solaris) have `socketpair' in libsocket.
AC_SEARCH_LIBS(socketpair, socket)
+# Integration with GNU poke is done through the libpoke library.
+AC_ARG_WITH([poke],
+ AS_HELP_STRING([--with-poke],
+ [Build GDB with poke support (default is NO)]),
+ [with_poke=$withval], [with_poke=no])
+if test "x$with_poke" = "xyes"; then
+ # Note that we need a libpoke with support for registering foreign
+ # IO devices, hence the symbol pk_register_iod.
+ AC_CHECK_LIB(poke, pk_register_iod)
+ POKE_OBS="poke.o"
+ AC_DEFINE(HAVE_POKE, 1, [Define if building integration with GNU poke.])
+ CONFIG_INSTALL="$CONFIG_INSTALL install-poke"
+else
+ POKE_OBS=
+fi
+AC_SUBST(POKE_OBS)
+
# Link in zlib/zstd if we can. This allows us to read compressed debug
# sections.
AM_ZLIB
diff --git a/gdb/doc/ChangeLog-1991-2021 b/gdb/doc/ChangeLog-1991-2021
index 0df8399..fc6ce39 100644
--- a/gdb/doc/ChangeLog-1991-2021
+++ b/gdb/doc/ChangeLog-1991-2021
@@ -1,4 +1,14 @@
+<<<<<<< HEAD:gdb/doc/ChangeLog-1991-2021
2021-07-02 Pedro Alves <pedro@palves.net>
+=======
+2021-05-10 Jose E. Marchesi <jose.marchesi@oracle.com>
+
+ * Makefile.in (GDB_DOC_FILES): Add poke.texi.
+ * poke.texi: New file.
+ * gdb.texinfo (Data): Add meny entry for Poke and @include poke.texi.
+
+2021-05-07 Tom de Vries <tdevries@suse.de>
+>>>>>>> Integrate GNU poke in GDB:gdb/doc/ChangeLog
* gdb.texinfo (TUI): <TUI Mouse Support>: New node/section.
diff --git a/gdb/doc/Makefile.in b/gdb/doc/Makefile.in
index 110b608..754e8e5 100644
--- a/gdb/doc/Makefile.in
+++ b/gdb/doc/Makefile.in
@@ -142,6 +142,7 @@ GDB_DOC_FILES = \
$(srcdir)/gdb.texinfo \
$(srcdir)/guile.texi \
$(srcdir)/python.texi \
+ $(srcdir)/poke.texi \
$(GDB_DOC_SOURCE_INCLUDES) \
$(GDB_DOC_BUILD_INCLUDES)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 263326d..55b568d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10617,6 +10617,7 @@ being passed the type of @var{arg} as the argument.
* Caching Target Data:: Data caching for targets
* Searching Memory:: Searching memory for a sequence of bytes
* Value Sizes:: Managing memory allocated for values
+* Poke:: Poking at data using GNU poke.
@end menu
@node Expressions
@@ -14281,6 +14282,9 @@ Show the maximum size of memory, in bytes, that @value{GDBN} will
allocate for the contents of a value.
@end table
+@c Poke docs live in a separate file.
+@include poke.texi
+
@node Optimized Code
@chapter Debugging Optimized Code
@cindex optimized code, debugging
diff --git a/gdb/doc/poke.texi b/gdb/doc/poke.texi
new file mode 100644
index 0000000..d5d4c31
--- /dev/null
+++ b/gdb/doc/poke.texi
@@ -0,0 +1,371 @@
+@c Copyright (C) 2022-2023 Free Software Foundation, Inc.
+@c Permission is granted to copy, distribute and/or modify this document
+@c under the terms of the GNU Free Documentation License, Version 1.3 or
+@c any later version published by the Free Software Foundation; with the
+@c Invariant Sections being ``Free Software'' and ``Free Software Needs
+@c Free Documentation'', with the Front-Cover Texts being ``A GNU Manual,''
+@c and with the Back-Cover Texts as in (a) below.
+@c
+@c (a) The FSF's Back-Cover Text is: ``You are free to copy and modify
+@c this GNU Manual. Buying copies from GNU Press supports the FSF in
+@c developing GNU and promoting software freedom.''
+
+@node Poke
+@section Poking at data using GNU @samp{poke}
+@cindex GNU poke
+@cindex poke
+
+@uref{http://jemarch.net/poke.html,GNU poke} is an interactive,
+extensible editor for binary data that implements a full-fledged
+procedural, interactive domain specific language called @dfn{Poke}
+(with capital P) that is specifically designed in order to describe
+the layout of structured binary data and to operate on it.
+
+@value{GDBN} integrates with GNU @samp{poke} by mean of the
+@file{libpoke} library and offers the possibility of executing Poke
+code from within the debugger, to inspect and modify data in the
+target's memory. This feature is available only if @value{GDBN} was
+configured using @option{--enable-poke}.
+
+As we shall see in the sections below, @value{GDBN} uses the
+integration mechanisms provided by @file{libpoke} in order to make
+certain @value{GDBN} abstractions (such as symbols and types) visible from the
+Poke side, making the integration bidirectional.
+
+Note that this section documents the integration of GNU @samp{poke}
+and @value{GDBN} and how to use it, but it doesn't describe GNU
+@samp{poke} nor the Poke language in detail. @xref{Top,,, poke, The
+GNU poke Manual}, for more information.
+
+@menu
+* The @code{poke} Command:: Executing Poke from @value{GDBN}.
+* Poking the Target Memory:: Accessing the target's memory from Poke.
+* @value{GDBN} Types and Poke:: Accessing @value{GDBN} types from Poke.
+* @value{GDBN} Values and Poke:: Accessing @value{GDBN} values from Poke.
+@end menu
+
+@node The @code{poke} Command
+@subsection The @code{poke} Command
+
+The @code{poke} command allows to execute arbitrary Poke code from the
+@value{GDBN} prompt.
+
+@table @code
+@item poke @var{src}
+@var{src} is either a Poke expression, statement or definition.
+@end table
+
+For example, this executes a simple Poke expression and shows the
+result:
+
+@smallexample
+(@value{GDBP}) poke 2 + 3UL
+0x5UL
+@end smallexample
+
+This declares a couple of Poke types and a variable:
+
+@smallexample
+(@value{GDBP}) type byte = uint<8>
+(@value{GDBP}) type Packet = struct @{ byte magic == 0x4a; byte sz; \
+ byte[sz] payload; @}
+(@value{GDBP}) poke Packet @{ sz = 4 @}
+Packet @{
+ magic=0x4aUB,
+ sz=0x4UB,
+ payload=[0x0UB,0x0UB,0x0UB,0x0UB]
+@}
+(@value{GDBP}) var p = Packet @{ sz = 4 @}
+(@value{GDBP}) poke p.payload
+[0x0UB,0x0UB,0x0UB,0x0UB]
+@end smallexample
+
+This executes a Poke statement:
+
+@smallexample
+(@value{GDBP}) poke for (i in [1,2,3]) printf "%v\n", i
+0x00000001
+0x00000002
+0x00000003
+@end smallexample
+
+This shows how the Poke incremental compiler handles and reports
+invalid input:
+
+@smallexample
+(@value{GDBP}) poke 2 + fjsdio
+<stdin>:1:5: error: undefined variable 'fjsdio'
+2 + fjsdio;
+ ^~~~~~
+@end smallexample
+
+The standard @command{load} Poke directive loads a Poke source file
+and executes it in the incremental compiler. The list of directories
+where @command{load} looks for files is in the variable
+@code{load_path}:
+
+@smallexample
+(@value{GDBP}) poke load_path
+".:/home/jemarch/.local/share/poke:%DATADIR%/pickles:%DATADIR%"
+@end smallexample
+
+This loads a file @file{foo.pk} if it is found in the load path:
+
+@smallexample
+(@value{GDBP}) poke load foo
+@end smallexample
+
+Poke source files often contain definitions that conceptually apply to
+some definite domain, like some given file format or a protocol. We
+call these files @dfn{pickles}. For example, @file{elf.pk} is a
+pickle that provides facilities to poke ELF object files. The GNU
+@samp{poke} editor comes with lots of already written pickles for many
+file formats and other domains. If you happen to have GNU poke
+installed (and not just @file{libpoke}) you can also use the many
+pickles distributed with the editor. For example:
+
+@smallexample
+(@value{GDBP}) poke load elf
+(@value{GDBP}) poke Elf64_Rela @{@}
+Elf64_Rela @{
+ r_offset=0x0UL#B,
+ r_info=Elf64_RelInfo @{
+ r_sym=0x0U,
+ r_type=0x0U
+ @},
+ r_addend=0x0L
+@}
+@end smallexample
+
+@node Poking the Target Memory
+@subsection Poking the Target Memory
+
+@value{GDBN} configures @file{libpoke} to access the target's memory
+as an IO space device called @code{<gdb>}, which is automatically
+opened when the poke incremental compiler is started.
+
+This means that the default IO space in the running poke will provide
+access to the virtual address space of the current @value{GDBN}
+inferior.
+
+For example, suppose that a string table is at offset 0x5ff0 bytes in
+the target's memory. We could map an array of Poke strings from it by
+issuing:
+
+@smallexample
+(@value{GDBP}) poke string[3] @@ 0x5ff0#B
+["int", "long", "_pid"]
+@end smallexample
+
+And we can write to the target's memory:
+
+@smallexample
+(@value{GDBP}) poke string[] @@ 0x5ff0#B = ["foo", "bar", "baz"]
+@end smallexample
+
+Note that the fact the current IO space is the @value{GDBN} target memory
+doesn't mean you cannot access other IO spaces. This is how you would
+write the string table above to a file @file{strtab.out}:
+
+@smallexample
+(@value{GDBP}) poke var f = open ("strtab.out", IOS_F_WRITE | IOS_F_CREATE)
+(@value{GDBP}) poke string[] @@ f : 0#B = string[3] @@ 0x5ff0#B
+(@value{GDBP}) poke close (f)
+@end smallexample
+
+If you close the default IO space you can re-open the @value{GDBN} target space
+with @code{open ("<gdb>")}.
+
+@node @value{GDBN} Types and Poke
+@subsection @value{GDBN} Types and Poke
+
+Maybe the strongest side of the Poke language is that it provides a
+very rich and dynamic mechanism to describe the layout of data
+structures. This is done by defining @dfn{Poke types}.
+
+For example, this is the definition of a signed 13-bit integral type
+that could be used to poke immediate fields in SPARC instructions:
+
+@smallexample
+type simm13 = int<13>;
+@end smallexample
+
+And this is a simplified version of the structure of a 64-bit ELF file
+showing more advanced Poke capabilities like field constraints, field
+labels, absent fields, and methods:
+
+@smallexample
+type Elf64_File =
+ struct
+ @{
+ Elf64_Ehdr ehdr : ehdr.e_ident.ei-mag == [0x7fUB, 'E', 'L', 'F'];
+
+ Elf64_Shdr[ehdr.e_shnum] shdr @@ ehdr.e_shoff
+ if ehdr.e_shnum > 0;
+
+ Elf64_Phdr[ehdr.e_phnum] phdr @@ ehdr.e_phoff
+ if ehdr.e_phnum > 0;
+
+ /* Given an offset into the ELF file's section string table, return
+ the string. */
+
+ method get_section_name = (offset<Elf_Word,B> offset) string:
+ @{
+ var strtab = ehdr.e_shstrndx;
+ return string @@ (shdr[strtab].sh_offset + offset);
+ @}
+ @};
+@end smallexample
+
+This is all good and well for GNU @samp{poke} as a standalone binary editor,
+but when it comes to @value{GDBN} we want to poke at data structures
+in the target memory of the debugged program. These structures are
+described by language-specific types, which @value{GDBN} abstracts as
+@value{GDBN} types, not Poke types.
+
+For example, say we are debugging a C program that contains the
+following type:
+
+@smallexample
+struct person
+@{
+ int age;
+ char *name;
+ char *postal_address;
+@};
+@end smallexample
+
+If we wanted to poke at a struct person from poke, we would need to
+write a Poke struct type that is equivalent to that C type. This is
+often not trivial, because the physical layout of data structures is
+almost always not well defined in programming languages.
+
+Fortunately, @value{GDBN} provides a few commands to translate
+@value{GDBN} types to Poke types and inspect them.
+
+@table @code
+@item poke-add-type @var{expr}
+@var{expr} is a @value{GDBN} expression that must evaluate to a type.
+
+Translate a @value{GDBN} type to Poke and define it in the running
+poke incremental compiler. If the given type depends on other types
+that are not known to poke, add these as well.
+
+Types for which @value{GDBN} doesn't know how to create a Poke
+equivalence are simply ignored.
+
+@item poke-add-types @var{regexp}
+@var{regexp} is a regular expression.
+
+Translate all known types whose name matches @var{regexp} to Poke and
+define them in the running poke incremental compiler. If the matched
+types depend on other types that are not known to poke, add these as
+well.
+
+Types for which @value{GDBN} doesn't know how to create a Poke
+equivalence are simply ignored.
+
+@item poke-dump-types
+Dump the Poke definition of all translated types, one definition per
+line.
+@end table
+
+Using these commands, we can add a type for the @code{struct person} C
+type above like this:
+
+@smallexample
+(@value{GDBN}) poke-add-type struct person
+added type int
+added type struct_person
+@end smallexample
+
+Note how two types are added: the requested @code{struct person} and
+also @code{int}, since the struct contains a field of that basic C
+type. Let's take a look to the type definitions:
+
+@smallexample
+(@value{GDBN}) poke-dump-types
+type int = int<32>;
+type struct_person = struct @{int age; offset<uint<64>,B> name @@ 8#B; \
+offset<uint<64>,B> postal_address;@};
+@end smallexample
+
+If now we want to access a given variable of type @code{struct person}
+in the current target, we just use the created Poke types:
+
+@smallexample
+(@value{GDBN}) poke struct_person @@ 0xf00e#B
+struct_person @{
+ age=0x28,
+ name=0x5555555547b4UL#B,
+ postal_address=0x5555555547c5UL#B
+@}
+(@value{GDBN}) poke string @@ (struct_person @@ 0xf00e#B).postal_address
+"Foo Street number 13"
+@end smallexample
+
+If we wanted to add all the types known to @value{GDBN} to poke, we could so do
+by:
+
+@smallexample
+(@value{GDBN}) poke-add-types .*
+@end smallexample
+
+The @command{poke-dump-types} is useful to generate Poke files with
+type definitions to be used in GNU @samp{poke}, like this:
+
+@smallexample
+$ gdb -batch -ex poke-add-types .\* -ex poke-dump-types \
+ -ex quit foo.so > foo-types.pk
+@end smallexample
+
+@node @value{GDBN} Values and Poke
+@subsection @value{GDBN} Values and Poke
+
+Poke variables are not the same than @value{GDBN} symbols, and live in
+a separated world of their own. However, it is possible to refer to
+GDB values by using the @code{$IDENTIFIER} notation in Poke programs.
+
+Consider for example a C program with the following variable:
+
+@smallexample
+short counter;
+@end smallexample
+
+In @value{GDBN} we can access to the value of that variable like this:
+
+@smallexample
+(@value{GDBN}) counter
+$1 = 0
+@end smallexample
+
+And from the poke side:
+
+@smallexample
+(@value{GDBN}) poke $counter
+0x0H
+@end smallexample
+
+Note how the @value{GDBN} value is visible using the right type, in
+the case above a signed 16-bit integer. If we accessed a C value of a
+pointer type, like @code{char *str;}, we would get an offset with unit
+bytes instead:
+
+@smallexample
+(@value{GDBN}) poke $str
+0x0UL#B
+@end smallexample
+
+Since many @value{GDBN} values are pointers, it is possible to access
+the address of a value by using the @code{$addr::IDENTIFIER} notation.
+For example, given the C @code{struct person} defined above and a
+variable @code{struct person jemarch;}:
+
+@smallexample
+(@value{GDBN}) poke struct_person @@ $addr::jemarch
+struct_person @{
+ age=0x28,
+ name=0x5555555547b4UL#B,
+ postal_address=0x5555555547c5UL#B
+@}
+@end smallexample
diff --git a/gdb/poke.c b/gdb/poke.c
new file mode 100644
index 0000000..65936b4
--- /dev/null
+++ b/gdb/poke.c
@@ -0,0 +1,789 @@
+/* GDB integration with GNU poke.
+
+ Copyright (C) 2021-2023 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 "defs.h"
+#include "command.h"
+#include "arch-utils.h"
+#include "target.h"
+#include "gdbcmd.h"
+extern "C" {
+#include <libpoke.h>
+}
+#include <ctype.h>
+#include <vector>
+#include <algorithm>
+
+/* Global poke incremental compiler. */
+
+static pk_compiler poke_compiler;
+static bool poke_compiler_lives = false;
+
+/* Global vector of the Poke code used to define types. This is
+ filled in by poke_add_type and used by poke_dump_types. */
+
+static std::vector<std::string> type_poke_strings;
+
+/* Terminal hook that flushes the terminal. */
+
+static void
+poke_term_flush (void)
+{
+ /* Do nothing here. */
+}
+
+/* Terminal hook that prints a fixed string. */
+
+static void
+poke_puts (const char *str)
+{
+ gdb_printf ("%s", str);
+}
+
+/* Terminal hook that prints a formatted string. */
+
+__attribute__ ((__format__ (__printf__, 1, 2)))
+static void
+poke_printf (const char *format, ...)
+{
+ va_list ap;
+ char *str;
+ int r;
+
+ va_start (ap, format);
+ r = vasprintf (&str, format, ap);
+ if (r == -1)
+ error (_("out of memory in vasprintf")); /* XXX fatal */
+ va_end (ap);
+
+ gdb_printf ("%s", str);
+ free (str);
+}
+
+/* Terminal hook that indents to a given level. */
+
+static void
+poke_term_indent (unsigned int lvl, unsigned int step)
+{
+ gdb_printf ("\n%*s", (step * lvl), "");
+}
+
+/* Terminal hook that starts a styling class. */
+
+static void
+poke_term_class (const char *class_name)
+{
+ /* Do nothing here. */
+}
+
+/* Terminal hook that finishes a styling class. */
+
+static int
+poke_term_end_class (const char *class_name)
+{
+ /* Just report success. */
+ return 1;
+}
+
+/* Terminal hook that starts a terminal hyperlink. */
+
+static void
+poke_term_hyperlink (const char *url, const char *id)
+{
+ /* Do nothing here. */
+}
+
+/* Terminal hook that finishes a terminal hyperlink. */
+
+static int
+poke_term_end_hyperlink (void)
+{
+ /* Just report success. */
+ return 1;
+}
+
+/* Terminal hook that returns the current terminal foreground
+ color. */
+
+static struct pk_color
+poke_term_get_color (void)
+{
+ /* Just return the default foreground color. */
+ struct pk_color dfl = {-1,-1,-1};
+ return dfl;
+}
+
+/* Terminal hook that returns the current terminal background
+ color. */
+
+static struct pk_color
+poke_term_get_bgcolor (void)
+{
+ /* Just return the default background color. */
+ struct pk_color dfl = {-1,-1,-1};
+ return dfl;
+}
+
+/* Terminal hook that sets the terminal foreground color. */
+
+static void
+poke_term_set_color (struct pk_color color)
+{
+ /* Do nothing. */
+}
+
+/* Terminal hook that sets the terminal background color. */
+
+static void
+poke_term_set_bgcolor (struct pk_color color)
+{
+ /* Do nothing. */
+}
+
+/* Implementation of the poke terminal interface, that uses the hooks
+ defined above. */
+
+static struct pk_term_if poke_term_if =
+ {
+ .flush_fn = poke_term_flush,
+ .puts_fn = poke_puts,
+ .printf_fn = poke_printf,
+ .indent_fn = poke_term_indent,
+ .class_fn = poke_term_class,
+ .end_class_fn = poke_term_end_class,
+ .hyperlink_fn = poke_term_hyperlink,
+ .end_hyperlink_fn = poke_term_end_hyperlink,
+ .get_color_fn = poke_term_get_color,
+ .get_bgcolor_fn = poke_term_get_bgcolor,
+ .set_color_fn = poke_term_set_color,
+ .set_bgcolor_fn = poke_term_set_bgcolor,
+ };
+
+/* Foreign IO device hook that returns an unique name identifying the
+ kind of device. */
+
+static const char *
+iod_get_if_name (void)
+{
+ return "GDB";
+}
+
+/* Foreign IO device hook that recognizes whether a given IO space
+ handler refer to this kind of device, and normalizes it for further
+ use. */
+
+static char *
+iod_handler_normalize (const char *handler, uint64_t flags, int *error)
+{
+ char *new_handler = NULL;
+
+ if (strcmp (handler, "gdb://inferior/mem") == 0)
+ new_handler = xstrdup (handler);
+ if (error)
+ *error = PK_IOD_OK;
+
+ return new_handler;
+}
+
+/* Foreign IO device hook that opens a new device. */
+
+static int iod_opened_p = 0;
+
+static void *
+iod_open (const char *handler, uint64_t flags, int *error, void *data)
+{
+ iod_opened_p = 1;
+ return &iod_opened_p;
+}
+
+/* Foreign IO device hook that reads data from a device. */
+
+static int
+iod_pread (void *dev, void *buf, size_t count, pk_iod_off offset)
+{
+ int ret = target_read_memory (offset, (gdb_byte *) buf, count);
+ return ret == -1 ? PK_IOD_ERROR : PK_IOD_OK;
+}
+
+/* Foreign IO device hook that writes data to a device. */
+
+static int
+iod_pwrite (void *dev, const void *buf, size_t count, pk_iod_off offset)
+{
+ int ret = target_write_memory (offset, (gdb_byte *) buf, count);
+ return ret == -1 ? PK_IOD_ERROR : PK_IOD_OK;
+}
+
+/* Foreign IO device hook that returns the flags of an IO device. */
+
+static uint64_t
+iod_get_flags (void *dev)
+{
+ return PK_IOS_F_READ | PK_IOS_F_WRITE;
+}
+
+/* Foreign IO device hook that returns the size of an IO device, in
+ bytes. */
+
+static pk_iod_off
+iod_size (void *dev)
+{
+ return (gdbarch_addr_bit (get_current_arch ()) == 32
+ ? 0xffffffff : 0xffffffffffffffff);
+}
+
+/* Foreign IO device hook that flushes an IO device. */
+
+static int
+iod_flush (void *dev, pk_iod_off offset)
+{
+ /* Do nothing here. */
+ return PK_OK;
+}
+
+/* Foreign IO device hook that closes a given device. */
+
+static int
+iod_close (void *dev)
+{
+ iod_opened_p = 0;
+ return PK_OK;
+}
+
+/* Implementation of the poke foreign IO device interface, that uses
+ the hooks defined above. */
+
+static struct pk_iod_if iod_if =
+ {
+ iod_get_if_name,
+ iod_handler_normalize,
+ iod_open,
+ iod_close,
+ iod_pread,
+ iod_pwrite,
+ iod_get_flags,
+ iod_size,
+ iod_flush
+ };
+
+/* Handler for alien tokens. */
+
+static struct pk_alien_token alien_token;
+
+static struct pk_alien_token *
+poke_alien_token_handler (const char *id, char **errmsg)
+{
+ /* In GDB alien poke tokens with the form $addr::FOO provide the
+ address of the symbol `FOO' as an offset in bytes, i.e. it
+ resolves to the GDB value &foo as a Poke offset with unit bytes
+ and a magnitude whose width is the number of bits conforming an
+ address in the target architecture.
+
+ $FOO, on the other hand, provides the value of the symbol FOO
+ incarnated in a proper Poke value, provided that FOO is of a type
+ that this handler knows how to handle. Otherwise the string is
+ not recognized as a token. */
+
+ if (strncmp (id, "addr::", 6) == 0)
+ {
+ CORE_ADDR addr;
+
+ std::string expr = "&";
+ expr += id + 6;
+
+ try
+ {
+ addr = parse_and_eval_address (expr.c_str ());
+ }
+ catch (const gdb_exception_error &except)
+ {
+ goto error;
+ }
+
+ alien_token.kind = PK_ALIEN_TOKEN_OFFSET;
+ alien_token.value.offset.magnitude = addr;
+ gdb_assert (gdbarch_addr_bit (get_current_arch ()) <= 64);
+ alien_token.value.offset.width = gdbarch_addr_bit (get_current_arch ());
+ alien_token.value.offset.signed_p = 0;
+ alien_token.value.offset.unit = 8;
+ }
+ else
+ {
+ struct value *value;
+
+ try
+ {
+ value = parse_and_eval (id);
+ }
+ catch (const gdb_exception_error &except)
+ {
+ goto error;
+ }
+
+ struct type *type = value->type ();
+
+ if (can_dereference (type))
+ {
+ alien_token.kind = PK_ALIEN_TOKEN_OFFSET;
+ alien_token.value.offset.magnitude
+ = value_as_address (value);
+ alien_token.value.offset.width = type->length () * 8;
+ alien_token.value.offset.signed_p = !type->is_unsigned ();
+ alien_token.value.offset.unit = 8;
+ }
+ else if (is_integral_type (type))
+ {
+ alien_token.kind = PK_ALIEN_TOKEN_INTEGER;
+ alien_token.value.integer.magnitude
+ = value_as_long (value);
+ alien_token.value.integer.width = type->length () * 8;
+ alien_token.value.integer.signed_p
+ = !type->is_unsigned ();
+ }
+ else
+ goto error;
+ }
+
+ *errmsg = NULL;
+ return &alien_token;
+
+ error:
+ std::string emsg = "can't access GDB variable '";
+ emsg += id;
+ emsg += "'";
+ *errmsg = xstrdup (emsg.c_str ());
+ return NULL;
+}
+
+/* Given a string, prefix it in order to avoid collision with Poke's
+ keywords. */
+
+static std::string
+normalize_poke_identifier (std::string prefix, std::string str)
+{
+ if (!pk_keyword_p (poke_compiler, str.c_str ()))
+ str = prefix + str;
+
+ return str;
+}
+
+/* Given a GDB type name, mangle it to a valid Poke type name. */
+
+static std::string
+gdb_type_name_to_poke (std::string str, struct type *type = NULL)
+{
+ for (int i = 0; i < str.length (); ++i)
+ if (!(str.begin()[i] == '_'
+ || (str.begin()[i] >= 'a' && str.begin()[i] <= 'z')
+ || (str.begin()[i] >= '0' && str.begin()[i] <= '9')
+ || (str.begin()[i] >= 'A' && str.begin()[i] <= 'Z')))
+ str.begin()[i] = '_';
+
+ if (type)
+ {
+ /* Prepend struct and union tags with suitable prefixes. This
+ is to avoid ending with recursive typedefs in C programs. */
+ if (type->code () == TYPE_CODE_STRUCT)
+ str = "struct_" + str;
+ else if (type->code () == TYPE_CODE_UNION)
+ str = "union_" + str;
+ }
+
+ return str;
+}
+
+/* Command to feed the poke compiler with the definition of some given
+ GDB type. */
+
+static void poke_command (const char *args, int from_tty);
+
+static std::string
+poke_add_type (struct type *type)
+{
+ std::string type_name;
+ std::string str = "";
+
+ if (type != nullptr)
+ {
+ if (type->name ())
+ type_name = type->name ();
+
+ /* Do not try to add a type that is already defined. */
+ if (type_name != ""
+ && pk_decl_p (poke_compiler,
+ gdb_type_name_to_poke (type_name, type).c_str (),
+ PK_DECL_KIND_TYPE))
+ return type_name;
+
+ switch (type->code ())
+ {
+ case TYPE_CODE_PTR:
+ {
+ str = ("offset<uint<"
+ + (std::to_string (type->length () * 8))
+ + ">,B>");
+ break;
+ }
+ case TYPE_CODE_TYPEDEF:
+ {
+ struct type *target_type = type->target_type ();
+ std::string target_type_code = poke_add_type (target_type);
+
+ if (target_type_code == "")
+ goto skip;
+
+ if (target_type->name ())
+ str += gdb_type_name_to_poke (target_type->name (), target_type);
+ else
+ str += target_type_code;
+ break;
+ }
+ case TYPE_CODE_INT:
+ {
+ size_t type_length = type->length () * 8;
+
+ if (type_length > 64)
+ goto skip;
+
+ if (type->is_unsigned ())
+ str += "u";
+ str += "int<";
+ str += std::to_string (type_length);
+ str += ">";
+ break;
+ }
+ case TYPE_CODE_ARRAY:
+ {
+ struct type *target_type = type->target_type ();
+ size_t target_type_length = target_type->length ();
+ std::string target_type_code
+ = poke_add_type (target_type);
+
+ if (target_type_code == "")
+ goto skip;
+
+ /* Poke doesn't have multi-dimensional arrays. */
+ if (type->is_multi_dimensional ())
+ goto skip;
+
+ if (target_type->name ())
+ str = gdb_type_name_to_poke (target_type->name (), target_type);
+ else
+ str = target_type_code;
+
+ str += "[";
+ str += std::to_string (type->length () / target_type_length);
+ str += "]";
+ break;
+ }
+ case TYPE_CODE_STRUCT:
+ {
+ size_t natural_bitpos = 0;
+ str += "struct {";
+
+ for (int idx = 0; idx < type->num_fields (); idx++)
+ {
+ std::string field_name
+ = normalize_poke_identifier ("__f", type->field (idx).name ());
+ struct type *field_type = type->field (idx).type ();
+ size_t field_bitpos = type->field (idx).loc_bitpos ();
+
+ if (idx > 0)
+ str += " ";
+ if (field_type->name ())
+ {
+ if (poke_add_type (field_type) == "")
+ goto skip;
+ str += gdb_type_name_to_poke (field_type->name (), field_type);
+ }
+ else
+ {
+ std::string pstr = poke_add_type (field_type);
+ if (pstr == "")
+ goto skip;
+ str += pstr;
+ }
+ str += " ";
+ if (field_name != "")
+ str += field_name;
+ if (field_bitpos != natural_bitpos)
+ str += " @ " + (field_bitpos % 8 == 0
+ ? std::to_string (field_bitpos / 8) + "#B"
+ : std::to_string (field_bitpos) + "#b");
+ str += ";";
+
+ natural_bitpos = field_bitpos + field_type->length () * 8;
+ }
+
+ str += "}";
+ break;
+ }
+ default:
+ goto skip;
+ break;
+ }
+
+ if (type_name != "")
+ {
+ std::string poke_type_name
+ = gdb_type_name_to_poke (type_name, type);
+
+ std::string deftype = "type ";
+ deftype += poke_type_name;
+ deftype += " = ";
+ deftype += str;
+
+ type_poke_strings.push_back (deftype);
+ poke_command (deftype.c_str(), 0 /* from_tty */);
+ gdb_printf ("added type %s\n", poke_type_name.c_str ());
+ }
+ }
+
+ return str;
+
+ skip:
+ if (type_name != "")
+ gdb_printf ("skipped type %s\n", type_name.c_str ());
+ return "";
+}
+
+/* Call the default poke exception handler. */
+
+static void
+poke_handle_exception (pk_val exception)
+{
+ pk_val handler = pk_decl_val (poke_compiler, "gdb_exception_handler");
+
+ if (handler == PK_NULL)
+ error (_("Couldn't get a handler for poke gdb_exception_handler"));
+ if (pk_call (poke_compiler, handler, NULL, NULL, 1, exception)
+ == PK_ERROR)
+ error (_("Couldn't call gdb_exception_handler in poke"));
+}
+
+/* Start the poke incremental compiler. */
+
+static void
+start_poke (void)
+{
+ /* Note how we are creating an incremental compiler without the
+ standard Poke types (int, etc) because they collide with the C
+ types. */
+ poke_compiler = pk_compiler_new_with_flags (&poke_term_if,
+ PK_F_NOSTDTYPES);
+ if (poke_compiler == NULL)
+ error (_("Couldn't start the poke incremental compiler."));
+
+ /* Install the handler for alien tokens that recognizes GDB
+ symbols. */
+ pk_set_alien_token_fn (poke_compiler, poke_alien_token_handler);
+
+ /* Use hexadecimal output by default. */
+ pk_set_obase (poke_compiler, 16);
+
+ /* Use `tree' printing mode by default. */
+ pk_set_omode (poke_compiler, PK_PRINT_TREE);
+
+ /* Install our foreign IO device interface to access the target's
+ memory. */
+ if (pk_register_iod (poke_compiler, &iod_if) != PK_OK)
+ error (_("Could not register the foreign IO device interface in poke."));
+
+ /* Provide access to pickles installed by poke applications, also to
+ the pickles installed by GDB. */
+ pk_val pk_load_path = pk_decl_val (poke_compiler, "load_path");
+ std::string load_path = pk_string_str (pk_load_path);
+ load_path += ":" + gdb_datadir + "/poke:%DATADIR%/pickles";
+ pk_decl_set_val (poke_compiler, "load_path",
+ pk_make_string (load_path.c_str ()));
+
+ /* Load the Poke components. */
+ if (pk_load (poke_compiler, "gdb") != PK_OK)
+ error (_("Could not load gdb.pk"));
+
+ poke_compiler_lives = true;
+}
+
+/* Function to finalize the poke subsystem. This is registered with
+ make_final_cleanup in _initialize_poke. */
+
+static void
+poke_finalize (void *arg)
+{
+ if (poke_compiler_lives)
+ {
+ pk_val val, exit_exception;
+ if (pk_compile_statement (poke_compiler,
+ "try close (get_ios); catch if E_no_ios {}",
+ NULL, &val, &exit_exception) != PK_OK
+ || exit_exception != PK_NULL)
+ error (_("Error while closing an IOS on exit."));
+
+ pk_compiler_free (poke_compiler);
+ poke_compiler_lives = false;
+ }
+}
+
+/* Command to dump the Poke definition of known types. */
+
+static void
+poke_dump_types (const char *args, int from_tty)
+{
+ if (!poke_compiler_lives)
+ start_poke ();
+
+ for (const std::string &s : type_poke_strings)
+ printf ("%s;\n", s.c_str ());
+}
+
+/* Commands to add GDB types to the running poke compiler. */
+
+static void
+poke_add_type_command (const char *args, int from_tty)
+{
+ if (!poke_compiler_lives)
+ start_poke ();
+
+ std::string type_name = skip_spaces (args);
+ type_name = gdb_type_name_to_poke (type_name);
+
+ expression_up expr = parse_expression (args);
+ struct value *val = evaluate_type (expr.get ());
+ struct type *type = val->type ();
+
+ poke_add_type (type);
+}
+
+static void
+poke_add_types (const char *args, int from_tty)
+{
+ if (!poke_compiler_lives)
+ start_poke ();
+
+ std::string symbol_name_regexp = skip_spaces (args);
+ global_symbol_searcher spec (TYPES_DOMAIN, symbol_name_regexp.c_str ());
+ std::vector<symbol_search> symbols = spec.search ();
+ for (const symbol_search &p : symbols)
+ {
+ QUIT;
+
+ struct symbol *sym = p.symbol;
+ struct type *type = sym->type ();
+
+ if (type)
+ poke_add_type (type);
+ }
+}
+
+/* Command to execute a poke statement or declaration. */
+
+static void
+poke_command (const char *args, int from_tty)
+{
+ if (!poke_compiler_lives)
+ start_poke ();
+
+ int what; /* 0 -> declaration, 1 -> statement */
+ const char *end;
+ std::string cmd;
+ pk_val exit_exception = PK_NULL;
+
+#define IS_COMMAND(input, cmd) \
+ (strncmp ((input), (cmd), sizeof (cmd) - 1) == 0 \
+ && ((input)[sizeof (cmd) - 1] == ' ' || (input)[sizeof (cmd) - 1] == '\t'))
+
+ args = skip_spaces (args);
+ if (args == NULL)
+ return;
+
+ if (IS_COMMAND (args, "fun"))
+ {
+ what = 0;
+ cmd = args;
+ }
+ else
+ {
+ if (IS_COMMAND (args, "var")
+ || IS_COMMAND (args, "type")
+ || IS_COMMAND (args, "unit"))
+ what = 0;
+ else
+ what = 1;
+
+ cmd = args;
+ cmd += ';';
+ }
+
+ pk_set_lexical_cuckolding_p (poke_compiler, 1);
+
+ if (what == 0)
+ {
+ /* Declaration. */
+ if (pk_compile_buffer (poke_compiler, cmd.c_str (),
+ &end, &exit_exception) != PK_OK
+ || exit_exception != PK_NULL)
+ goto error;
+ }
+ else
+ {
+ /* Statement. */
+ pk_val val;
+
+ if (pk_compile_statement (poke_compiler, cmd.c_str (), &end,
+ &val, &exit_exception) != PK_OK
+ || exit_exception != PK_NULL)
+ goto error;
+
+ if (val != PK_NULL)
+ {
+ pk_print_val (poke_compiler, val, &exit_exception);
+ poke_puts ("\n");
+ }
+ }
+
+ pk_set_lexical_cuckolding_p (poke_compiler, 0);
+#undef IS_COMMAND
+ error:
+ if (exit_exception != PK_NULL)
+ poke_handle_exception (exit_exception);
+}
+
+/* Initialize the poke GDB subsystem. */
+
+void _initialize_poke (void);
+void
+_initialize_poke ()
+{
+ add_com ("poke-add-type", class_vars, poke_add_type_command, _("\
+Make Poke aware of a GDB type given an expression.\n\
+Usage: poke-add-type EXPRESSION\n"));
+
+ add_com ("poke-add-types", class_vars, poke_add_types, _("\
+Make Poke aware of GDB types based on a regexp.\n\
+Usage: poke-add-types REGEXP\n"));
+
+ add_com ("poke-dump-types", class_vars, poke_dump_types, _("\
+Dump the definition of all the GDB types known to poke.\n\
+Usage: poke-dump-types\n"));
+
+ add_com ("poke", class_vars, poke_command, _("\
+Execute a Poke statement or declaration.\n\
+Usage: poke [STMT]\n"));
+
+ make_final_cleanup (poke_finalize, NULL);
+}
diff --git a/gdb/poke/gdb.pk b/gdb/poke/gdb.pk
new file mode 100644
index 0000000..e829689
--- /dev/null
+++ b/gdb/poke/gdb.pk
@@ -0,0 +1,42 @@
+/* GDB integration with GNU poke. Poke parts.
+
+ Copyright (C) 2023 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/>. */
+
+/* Exception handler. */
+
+fun gdb_exception_handler = (Exception exception) void:
+{
+ if (exception.code != EC_exit && exception.code != EC_signal)
+ {
+ print ("unhandled "
+ + (exception.name == "" ? "unknown" : exception.name)
+ + " exception\n");
+
+ if (exception.location != "" || exception.msg != "")
+ {
+ if (exception.location != "")
+ print (exception.location + " ");
+ print (exception.msg + "\n");
+ }
+ }
+}
+
+/* Open the memory of the inferior being debugged under GDB as the
+ current IO space. */
+
+open ("gdb://inferior/mem");
diff --git a/gdb/testsuite/gdb.poke/poke-types.c b/gdb/testsuite/gdb.poke/poke-types.c
new file mode 100644
index 0000000..8ab5774
--- /dev/null
+++ b/gdb/testsuite/gdb.poke/poke-types.c
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2023 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 <stdint.h>
+
+int32_t i32;
+int16_t i16;
+uint64_t u64;
+char *pointer;
+
+int
+main (void)
+{
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.poke/poke-types.exp b/gdb/testsuite/gdb.poke/poke-types.exp
new file mode 100644
index 0000000..01c086e
--- /dev/null
+++ b/gdb/testsuite/gdb.poke/poke-types.exp
@@ -0,0 +1,36 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2023 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/>.
+
+require allow_poke_tests
+
+global GDB_DATA_DIRECTORY
+if ![info exists GDB_DATA_DIRECTORY] {
+ set GDB_DATA_DIRECTORY [file normalize "$srcdir/.."]
+}
+
+standard_testfile
+if [prepare_for_testing "failed to prepare" $testfile $srcfile] {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+# Add all types
+gdb_test "poke-add-type int" "added type int"
+gdb_test "poke-dump-types" "type int = int<\[0-9\]*>;"
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index aed7e2d..80ed3fb 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -2537,6 +2537,13 @@ proc allow_rust_tests {} {
return 1
}
+# Return a 1 fo rconfigurations that support GNU poke integration.
+
+proc allow_poke_tests {} {
+ set output [remote_exec host $::GDB "$::INTERNAL_GDBFLAGS --configuration"]
+ return [expr {[string first "--with-poke" $output] != -1}]
+}
+
# Return a 1 for configurations that support Python scripting.
gdb_caching_proc allow_python_tests {} {
diff --git a/gdb/top.c b/gdb/top.c
index 81f74f7..38cc558 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1633,6 +1633,16 @@ This GDB was configured as follows:\n\
"));
#endif
+#if HAVE_POKE
+ gdb_printf (stream, _("\
+ --with-poke\n\
+"));
+#else
+ gdb_printf (stream, _("\
+ --without-poke\n\
+"));
+#endif
+
#if HAVE_AMD_DBGAPI
gdb_printf (stream, _("\
--with-amd-dbgapi\n\
diff --git a/intl/aclocal.m4 b/intl/aclocal.m4
index 0a42b42..abe4923 100644
--- a/intl/aclocal.m4
+++ b/intl/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
+# generated automatically by aclocal 1.16.3 -*- Autoconf -*-
-# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/intl/configure b/intl/configure
index e75f072..7f370f2 100755
--- a/intl/configure
+++ b/intl/configure
@@ -696,6 +696,7 @@ infodir
docdir
oldincludedir
includedir
+runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -775,6 +776,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}'
@@ -1027,6 +1029,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1164,7 +1175,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir
+ libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1317,6 +1328,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -4656,6 +4668,8 @@ main ()
if (*(data + i) != *(data3 + i))
return 14;
close (fd);
+ free (data);
+ free (data3);
return 0;
}
_ACEOF
@@ -6857,6 +6871,9 @@ case "${host}" in
# sets the default TLS model and affects inlining.
PICFLAG=-fPIC
;;
+ loongarch*-*-*)
+ PICFLAG=-fpic
+ ;;
mips-sgi-irix6*)
# PIC is the default.
;;
diff --git a/libiberty/aclocal.m4 b/libiberty/aclocal.m4
index 0757688..2ded717 100644
--- a/libiberty/aclocal.m4
+++ b/libiberty/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
+# generated automatically by aclocal 1.16.3 -*- Autoconf -*-
-# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/libiberty/configure b/libiberty/configure
index 1ccfac9..920dc7f 100755
--- a/libiberty/configure
+++ b/libiberty/configure
@@ -684,6 +684,7 @@ infodir
docdir
oldincludedir
includedir
+runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -763,6 +764,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}'
@@ -1015,6 +1017,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1152,7 +1163,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir
+ libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1305,6 +1316,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -4430,7 +4442,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -4476,7 +4488,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -4500,7 +4512,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -4545,7 +4557,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -4569,7 +4581,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -7727,6 +7739,8 @@ main ()
if (*(data + i) != *(data3 + i))
return 14;
close (fd);
+ free (data);
+ free (data3);
return 0;
}
_ACEOF