public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* RFA: Add support for DWARF-based fixed point types
@ 2020-11-08  6:30 Joel Brobecker
  2020-11-08  6:30 ` [PATCH 1/9] gdb/configure: Add --with-libgmp-prefix option Joel Brobecker
                   ` (11 more replies)
  0 siblings, 12 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-08  6:30 UTC (permalink / raw)
  To: gdb-patches

Hello,

This patch series adds support for fixed point types described
using a pure DWARF approach. While the main trigger was the desire
to deprecate the GNAT encodings used in the case of Ada fixed point
types, the implementation is done in a way that support is generic.
Other languages which have support for such kinds of types should
have little work to do to support them as well.

The implementation is based on top of GMP: We use GMP to store and
operate on rational values, with the added bonus that there is no
size limit on either the numerator nor denominator. As discussed
previously, the dependency on GMP is made mandatory
(https://sourceware.org/pipermail/gdb-patches/2018-March/147373.html).

One part that this patch series does not include is function calls
and returns. Since those changes are all arch-specific, I will
submit them in a separate series of its own, to avoid those other
patches getting lost in this patch series.

Each patch of this series has been tested on x86_64-linux using
our testsuite. In addition, these changes have been tested using
AdaCore's testing, on numerous architectures and OSes.

Looking forward to everyone's feedback!

Thank you,
-- 
Joel


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PATCH 1/9] gdb/configure: Add --with-libgmp-prefix option
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
@ 2020-11-08  6:30 ` Joel Brobecker
  2020-11-08  6:30 ` [PATCH 2/9] gdb: Make GMP a required dependency for building GDB Joel Brobecker
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-08  6:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This patch allows a user to tell gdb's configure script where
his GMP library is installed.

gdb/ChangeLog:

        * configure.ac: Add support for --with-libgmp-prefix.
        * Makefile.in (LIBGMP): New variable.
        (CLIBS): Include $(LIBGMP).
        * configure, config.in: Regenerate
---
 gdb/Makefile.in  |   5 +-
 gdb/config.in    |   3 +
 gdb/configure    | 488 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/configure.ac |   5 +
 4 files changed, 500 insertions(+), 1 deletion(-)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c46935e..c461964 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -203,6 +203,9 @@ LIBXXHASH = @LIBXXHASH@
 # Where is libipt?  This will be empty if libipt was not available.
 LIBIPT = @LIBIPT@
 
+# Where is libgmp?
+LIBGMP = @LIBGMP@
+
 # Where is libmpfr?  This will be empty if libmpfr was not available.
 LIBMPFR = @LIBMPFR@
 
@@ -632,7 +635,7 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) \
 	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
 	$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
 	$(WIN32LIBS) $(LIBGNU) $(LIBGNU_EXTRA_LIBS) $(LIBICONV) \
-	$(LIBMPFR) $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
+	$(LIBMPFR) $(LIBGMP) $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
 	$(DEBUGINFOD_LIBS)
 CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(CTF_DEPS) \
 	$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) \
diff --git a/gdb/config.in b/gdb/config.in
index 3e741c6..14a77c6 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -229,6 +229,9 @@
 /* Define if you have the expat library. */
 #undef HAVE_LIBEXPAT
 
+/* Define if you have the gmp library. */
+#undef HAVE_LIBGMP
+
 /* Define to 1 if you have the `libiconvlist' function. */
 #undef HAVE_LIBICONVLIST
 
diff --git a/gdb/configure b/gdb/configure
index 4a03cd9..2bf0856 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -732,6 +732,9 @@ python_prog_path
 LTLIBMPFR
 LIBMPFR
 HAVE_LIBMPFR
+LTLIBGMP
+LIBGMP
+HAVE_LIBGMP
 LTLIBEXPAT
 LIBEXPAT
 HAVE_LIBEXPAT
@@ -896,6 +899,8 @@ with_jit_reader_dir
 with_expat
 with_libexpat_prefix
 with_libexpat_type
+with_libgmp_prefix
+with_libgmp_type
 with_mpfr
 with_libmpfr_prefix
 with_libmpfr_type
@@ -1639,6 +1644,9 @@ Optional Packages:
   --with-libexpat-prefix[=DIR]  search for libexpat in DIR/include and DIR/lib
   --without-libexpat-prefix     don't search for libexpat in includedir and libdir
   --with-libexpat-type=TYPE     type of library to search for (auto/static/shared)
+  --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
+  --without-libgmp-prefix     don't search for libgmp in includedir and libdir
+  --with-libgmp-type=TYPE     type of library to search for (auto/static/shared)
   --with-mpfr             include MPFR support (auto/yes/no)
   --with-libmpfr-prefix[=DIR]  search for libmpfr in DIR/include and DIR/lib
   --without-libmpfr-prefix     don't search for libmpfr in includedir and libdir
@@ -9982,6 +9990,486 @@ done
   fi
 fi
 
+# Verify that we have a usable GMP library.
+
+
+
+
+
+
+
+
+    use_additional=yes
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+
+# Check whether --with-libgmp-prefix was given.
+if test "${with_libgmp_prefix+set}" = set; then :
+  withval=$with_libgmp_prefix;
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/lib"
+      fi
+    fi
+
+fi
+
+
+# Check whether --with-libgmp-type was given.
+if test "${with_libgmp_type+set}" = set; then :
+  withval=$with_libgmp_type;  with_libgmp_type=$withval
+else
+   with_libgmp_type=auto
+fi
+
+  lib_type=`eval echo \$with_libgmp_type`
+
+      LIBGMP=
+  LTLIBGMP=
+  INCGMP=
+  rpathdirs=
+  ltrpathdirs=
+  names_already_handled=
+  names_next_round='gmp '
+  while test -n "$names_next_round"; do
+    names_this_round="$names_next_round"
+    names_next_round=
+    for name in $names_this_round; do
+      already_handled=
+      for n in $names_already_handled; do
+        if test "$n" = "$name"; then
+          already_handled=yes
+          break
+        fi
+      done
+      if test -z "$already_handled"; then
+        names_already_handled="$names_already_handled $name"
+                        uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+        eval value=\"\$HAVE_LIB$uppername\"
+        if test -n "$value"; then
+          if test "$value" = yes; then
+            eval value=\"\$LIB$uppername\"
+            test -z "$value" || LIBGMP="${LIBGMP}${LIBGMP:+ }$value"
+            eval value=\"\$LTLIB$uppername\"
+            test -z "$value" || LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }$value"
+          else
+                                    :
+          fi
+        else
+                              found_dir=
+          found_la=
+          found_so=
+          found_a=
+          if test $use_additional = yes; then
+            if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext" && test x$lib_type != xstatic; then
+              found_dir="$additional_libdir"
+              found_so="$additional_libdir/lib$name.$shlibext"
+              if test -f "$additional_libdir/lib$name.la"; then
+                found_la="$additional_libdir/lib$name.la"
+              fi
+            elif test x$lib_type != xshared; then
+              if test -f "$additional_libdir/lib$name.$libext"; then
+                found_dir="$additional_libdir"
+                found_a="$additional_libdir/lib$name.$libext"
+                if test -f "$additional_libdir/lib$name.la"; then
+                  found_la="$additional_libdir/lib$name.la"
+                fi
+              fi
+            fi
+          fi
+          if test "X$found_dir" = "X"; then
+            for x in $LDFLAGS $LTLIBGMP; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+              case "$x" in
+                -L*)
+                  dir=`echo "X$x" | sed -e 's/^X-L//'`
+                  if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext" && test x$lib_type != xstatic; then
+                    found_dir="$dir"
+                    found_so="$dir/lib$name.$shlibext"
+                    if test -f "$dir/lib$name.la"; then
+                      found_la="$dir/lib$name.la"
+                    fi
+                  elif test x$lib_type != xshared; then
+                    if test -f "$dir/lib$name.$libext"; then
+                      found_dir="$dir"
+                      found_a="$dir/lib$name.$libext"
+                      if test -f "$dir/lib$name.la"; then
+                        found_la="$dir/lib$name.la"
+                      fi
+                    fi
+                  fi
+                  ;;
+              esac
+              if test "X$found_dir" != "X"; then
+                break
+              fi
+            done
+          fi
+          if test "X$found_dir" != "X"; then
+                        LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-L$found_dir -l$name"
+            if test "X$found_so" != "X"; then
+                                                        if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+                                LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
+              else
+                                                                                haveit=
+                for x in $ltrpathdirs; do
+                  if test "X$x" = "X$found_dir"; then
+                    haveit=yes
+                    break
+                  fi
+                done
+                if test -z "$haveit"; then
+                  ltrpathdirs="$ltrpathdirs $found_dir"
+                fi
+                                if test "$hardcode_direct" = yes; then
+                                                      LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
+                else
+                  if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+                                                            LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
+                                                            haveit=
+                    for x in $rpathdirs; do
+                      if test "X$x" = "X$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      rpathdirs="$rpathdirs $found_dir"
+                    fi
+                  else
+                                                                                haveit=
+                    for x in $LDFLAGS $LIBGMP; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                      if test "X$x" = "X-L$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      LIBGMP="${LIBGMP}${LIBGMP:+ }-L$found_dir"
+                    fi
+                    if test "$hardcode_minus_L" != no; then
+                                                                                        LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
+                    else
+                                                                                                                                                                                LIBGMP="${LIBGMP}${LIBGMP:+ }-l$name"
+                    fi
+                  fi
+                fi
+              fi
+            else
+              if test "X$found_a" != "X"; then
+                                LIBGMP="${LIBGMP}${LIBGMP:+ }$found_a"
+              else
+                                                LIBGMP="${LIBGMP}${LIBGMP:+ }-L$found_dir -l$name"
+              fi
+            fi
+                        additional_includedir=
+            case "$found_dir" in
+              */lib | */lib/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+                additional_includedir="$basedir/include"
+                ;;
+            esac
+            if test "X$additional_includedir" != "X"; then
+                                                                                                                if test "X$additional_includedir" != "X/usr/include"; then
+                haveit=
+                if test "X$additional_includedir" = "X/usr/local/include"; then
+                  if test -n "$GCC"; then
+                    case $host_os in
+                      linux*) haveit=yes;;
+                    esac
+                  fi
+                fi
+                if test -z "$haveit"; then
+                  for x in $CPPFLAGS $INCGMP; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                    if test "X$x" = "X-I$additional_includedir"; then
+                      haveit=yes
+                      break
+                    fi
+                  done
+                  if test -z "$haveit"; then
+                    if test -d "$additional_includedir"; then
+                                            INCGMP="${INCGMP}${INCGMP:+ }-I$additional_includedir"
+                    fi
+                  fi
+                fi
+              fi
+            fi
+                        if test -n "$found_la"; then
+                                                        save_libdir="$libdir"
+              case "$found_la" in
+                */* | *\\*) . "$found_la" ;;
+                *) . "./$found_la" ;;
+              esac
+              libdir="$save_libdir"
+                            for dep in $dependency_libs; do
+                case "$dep" in
+                  -L*)
+                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+                                                                                                                                                                if test "X$additional_libdir" != "X/usr/lib"; then
+                      haveit=
+                      if test "X$additional_libdir" = "X/usr/local/lib"; then
+                        if test -n "$GCC"; then
+                          case $host_os in
+                            linux*) haveit=yes;;
+                          esac
+                        fi
+                      fi
+                      if test -z "$haveit"; then
+                        haveit=
+                        for x in $LDFLAGS $LIBGMP; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                                                        LIBGMP="${LIBGMP}${LIBGMP:+ }-L$additional_libdir"
+                          fi
+                        fi
+                        haveit=
+                        for x in $LDFLAGS $LTLIBGMP; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                                                        LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-L$additional_libdir"
+                          fi
+                        fi
+                      fi
+                    fi
+                    ;;
+                  -R*)
+                    dir=`echo "X$dep" | sed -e 's/^X-R//'`
+                    if test "$enable_rpath" != no; then
+                                                                  haveit=
+                      for x in $rpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        rpathdirs="$rpathdirs $dir"
+                      fi
+                                                                  haveit=
+                      for x in $ltrpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        ltrpathdirs="$ltrpathdirs $dir"
+                      fi
+                    fi
+                    ;;
+                  -l*)
+                                        names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+                    ;;
+                  *.la)
+                                                                                names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+                    ;;
+                  *)
+                                        LIBGMP="${LIBGMP}${LIBGMP:+ }$dep"
+                    LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }$dep"
+                    ;;
+                esac
+              done
+            fi
+          else
+                                                            if test "x$lib_type" = "xauto" || test "x$lib_type" = "xshared"; then
+              LIBGMP="${LIBGMP}${LIBGMP:+ }-l$name"
+              LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-l$name"
+            else
+              LIBGMP="${LIBGMP}${LIBGMP:+ }-l:lib$name.$libext"
+              LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-l:lib$name.$libext"
+            fi
+          fi
+        fi
+      fi
+    done
+  done
+  if test "X$rpathdirs" != "X"; then
+    if test -n "$hardcode_libdir_separator"; then
+                        alldirs=
+      for found_dir in $rpathdirs; do
+        alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+      done
+            acl_save_libdir="$libdir"
+      libdir="$alldirs"
+      eval flag=\"$hardcode_libdir_flag_spec\"
+      libdir="$acl_save_libdir"
+      LIBGMP="${LIBGMP}${LIBGMP:+ }$flag"
+    else
+            for found_dir in $rpathdirs; do
+        acl_save_libdir="$libdir"
+        libdir="$found_dir"
+        eval flag=\"$hardcode_libdir_flag_spec\"
+        libdir="$acl_save_libdir"
+        LIBGMP="${LIBGMP}${LIBGMP:+ }$flag"
+      done
+    fi
+  fi
+  if test "X$ltrpathdirs" != "X"; then
+            for found_dir in $ltrpathdirs; do
+      LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-R$found_dir"
+    done
+  fi
+
+
+        ac_save_CPPFLAGS="$CPPFLAGS"
+
+  for element in $INCGMP; do
+    haveit=
+    for x in $CPPFLAGS; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+      if test "X$x" = "X$element"; then
+        haveit=yes
+        break
+      fi
+    done
+    if test -z "$haveit"; then
+      CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+    fi
+  done
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libgmp" >&5
+$as_echo_n "checking for libgmp... " >&6; }
+if ${ac_cv_libgmp+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    ac_save_LIBS="$LIBS"
+    LIBS="$LIBS $LIBGMP"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <gmp.h>
+int
+main ()
+{
+mpz_t n;
+                       mpz_init (n);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_libgmp=yes
+else
+  ac_cv_libgmp=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LIBS="$ac_save_LIBS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libgmp" >&5
+$as_echo "$ac_cv_libgmp" >&6; }
+  if test "$ac_cv_libgmp" = yes; then
+    HAVE_LIBGMP=yes
+
+$as_echo "#define HAVE_LIBGMP 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libgmp" >&5
+$as_echo_n "checking how to link with libgmp... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBGMP" >&5
+$as_echo "$LIBGMP" >&6; }
+  else
+    HAVE_LIBGMP=no
+            CPPFLAGS="$ac_save_CPPFLAGS"
+    LIBGMP=
+    LTLIBGMP=
+  fi
+
+
+
+
+
+
+
 
 # Check whether --with-mpfr was given.
 if test "${with_mpfr+set}" = set; then :
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 1b9548e..0264a4f 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -683,6 +683,11 @@ else
   fi
 fi
 
+# Verify that we have a usable GMP library.
+AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
+                      [mpz_t n;
+                       mpz_init (n);])
+
 AC_ARG_WITH(mpfr,
   AS_HELP_STRING([--with-mpfr], [include MPFR support (auto/yes/no)]),
   [], [with_mpfr=auto])
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PATCH 2/9] gdb: Make GMP a required dependency for building GDB
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
  2020-11-08  6:30 ` [PATCH 1/9] gdb/configure: Add --with-libgmp-prefix option Joel Brobecker
@ 2020-11-08  6:30 ` Joel Brobecker
  2020-12-15  6:55   ` Sebastian Huber
  2020-11-08  6:30 ` [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects Joel Brobecker
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-08  6:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This commit modifies gdb's configure script to trigger an error
if we cannot find a usable libgmp.

For the record, making this a requirement was discussed in March 2018:
https://sourceware.org/pipermail/gdb-patches/2018-March/147373.html

gdb/ChangeLog:

        * configure.ac: Generate an error if a usable GMP library
        could not be found.
        * configure: Regenerate.
---
 gdb/configure    | 3 +++
 gdb/configure.ac | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/gdb/configure b/gdb/configure
index 2bf0856..a3e73b4 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -10469,6 +10469,9 @@ $as_echo "$LIBGMP" >&6; }
 
 
 
+if test "$HAVE_LIBGMP" != yes; then
+  as_fn_error $? "GMP is missing or unusable" "$LINENO" 5
+fi
 
 
 # Check whether --with-mpfr was given.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 0264a4f..32f25d9 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -687,6 +687,9 @@ fi
 AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
                       [mpz_t n;
                        mpz_init (n);])
+if test "$HAVE_LIBGMP" != yes; then
+  AC_MSG_ERROR([GMP is missing or unusable])
+fi
 
 AC_ARG_WITH(mpfr,
   AS_HELP_STRING([--with-mpfr], [include MPFR support (auto/yes/no)]),
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
  2020-11-08  6:30 ` [PATCH 1/9] gdb/configure: Add --with-libgmp-prefix option Joel Brobecker
  2020-11-08  6:30 ` [PATCH 2/9] gdb: Make GMP a required dependency for building GDB Joel Brobecker
@ 2020-11-08  6:30 ` Joel Brobecker
  2020-11-10 20:15   ` Simon Marchi
  2020-11-16 16:34   ` Luis Machado
  2020-11-08  6:30 ` [PATCH 4/9] Move uinteger_pow gdb/valarith.c to gdb/utils.c and make it public Joel Brobecker
                   ` (8 subsequent siblings)
  11 siblings, 2 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-08  6:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This API was motivated by a number of reasons:
  - GMP's API does not handle "long long" and "unsigned long long",
    so using LONGEST and ULONGEST is not straightforward;
  - Automate the need to initialize GMP objects before use, and
    clear them when no longer used.

However, this API grew also to help with similar matter such
as formatting to a string, and also reading/writing fixed-point
values from byte buffers.

Dedicated unit testing is also added.

gdb/ChangeLog:

        * gmp-utils.h,  gmp-utils.h: New file.
        * unittests/gmp-utils-selftests.c: New file.
        * Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
        unittests/gmp-utils-selftests.c.
        (COMMON_SFILES) Add gmp-utils.c.
        (HFILES_NO_SRCDIR): Add gmp-utils.h.
---
 gdb/Makefile.in                     |   3 +
 gdb/gmp-utils.c                     | 172 ++++++++++++++
 gdb/gmp-utils.h                     | 282 ++++++++++++++++++++++
 gdb/unittests/gmp-utils-selftests.c | 460 ++++++++++++++++++++++++++++++++++++
 4 files changed, 917 insertions(+)
 create mode 100644 gdb/gmp-utils.c
 create mode 100644 gdb/gmp-utils.h
 create mode 100644 gdb/unittests/gmp-utils-selftests.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c461964..9b48f73 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -446,6 +446,7 @@ SELFTESTS_SRCS = \
 	unittests/filtered_iterator-selftests.c \
 	unittests/format_pieces-selftests.c \
 	unittests/function-view-selftests.c \
+	unittests/gmp-utils-selftests.c \
 	unittests/lookup_name_info-selftests.c \
 	unittests/memory-map-selftests.c \
 	unittests/memrange-selftests.c \
@@ -1059,6 +1060,7 @@ COMMON_SFILES = \
 	gdb_regex.c \
 	gdbarch.c \
 	gdbtypes.c \
+	gmp-utils.c \
 	gnu-v2-abi.c \
 	gnu-v3-abi.c \
 	go-lang.c \
@@ -1304,6 +1306,7 @@ HFILES_NO_SRCDIR = \
 	gdbthread.h \
 	gdbtypes.h \
 	glibc-tdep.h \
+	gmp-utils.h \
 	gnu-nat.h \
 	go-lang.h \
 	gregset.h \
diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
new file mode 100644
index 0000000..8ca3e8a
--- /dev/null
+++ b/gdb/gmp-utils.c
@@ -0,0 +1,172 @@
+/* Copyright (C) 2019-2020 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 "gmp-utils.h"
+
+/* See gmp-utils.h.  */
+
+gdb::unique_xmalloc_ptr<char>
+gmp_string_asprintf (const char *fmt, ...)
+{
+  va_list vp;
+  char *buf;
+
+  va_start (vp, fmt);
+  gmp_vasprintf (&buf, fmt, vp);
+  va_end (vp);
+
+  return gdb::unique_xmalloc_ptr<char> (buf);
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+	       bool unsigned_p)
+{
+  mpz_import (val, 1 /* count */, -1 /* order */, len /* size */,
+	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
+	      0 /* nails */, buf /* op */);
+
+  if (!unsigned_p)
+    {
+      /* The value was imported as if it was a positive value,
+	 as mpz_import does not handle signs. If the original value
+	 was in fact negative, we need to adjust VAL accordingly.  */
+      gdb_mpz max;
+
+      mpz_ui_pow_ui (max.val, 2, len * TARGET_CHAR_BIT - 1);
+      if (mpz_cmp (val, max.val) >= 0)
+	mpz_submul_ui (val, max.val, 2);
+    }
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpz::write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+		bool unsigned_p) const
+{
+  gdb_mpz exported_val (val);
+
+  if (mpz_cmp_ui (val, 0) < 0)
+    {
+      /* mpz_export does not handle signed values, so create a positive
+	 value whose bit representation as an unsigned of the same length
+	 would be the same as our negative value.  */
+      gdb_mpz neg_offset;
+
+      mpz_ui_pow_ui (neg_offset.val, 2, len * TARGET_CHAR_BIT);
+      mpz_add (exported_val.val, exported_val.val, neg_offset.val);
+    }
+
+  /* Start by clearing the buffer, as mpz_export only writes as many
+     bytes as it needs (including none, if the value to export is zero.  */
+  memset (buf, 0, len);
+  mpz_export (buf, NULL /* count */, -1 /* order */, len /* size */,
+	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
+	      0 /* nails */, exported_val.val);
+}
+
+/* See gmp-utils.h.  */
+
+gdb_mpz
+gdb_mpq::get_rounded () const
+{
+  /* Work with a positive number so as to make the "floor" rounding
+     always round towards zero.  */
+
+  gdb_mpq abs_val (val);
+  mpq_abs (abs_val.val, abs_val.val);
+
+  /* Convert our rational number into a quotient and remainder,
+     with "floor" rounding, which in our case means rounding
+     towards zero.  */
+
+  gdb_mpz quotient, remainder;
+  mpz_fdiv_qr (quotient.val, remainder.val,
+	       mpq_numref (abs_val.val), mpq_denref (abs_val.val));
+
+  /* Multiply the remainder by 2, and see if it is greater or equal
+     to abs_val's denominator.  If yes, round to the next integer.  */
+
+  mpz_mul_ui (remainder.val, remainder.val, 2);
+  if (mpz_cmp (remainder.val, mpq_denref (abs_val.val)) >= 0)
+    mpz_add_ui (quotient.val, quotient.val, 1);
+
+  /* Re-apply the sign if needed.  */
+  if (mpq_sgn (val) < 0)
+    mpz_neg (quotient.val, quotient.val);
+
+  return quotient;
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpq::read_fixed_point (const gdb_byte *buf, int len,
+			   enum bfd_endian byte_order, bool unsigned_p,
+			   const gdb_mpq &scaling_factor)
+{
+  gdb_mpz vz;
+  vz.read (buf, len, byte_order, unsigned_p);
+
+  mpq_set_z (val, vz.val);
+  mpq_mul (val, val, scaling_factor.val);
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpq::write_fixed_point (gdb_byte *buf, int len,
+			    enum bfd_endian byte_order, bool unsigned_p,
+			    const gdb_mpq &scaling_factor) const
+{
+  gdb_mpq unscaled (val);
+
+  mpq_div (unscaled.val, unscaled.val, scaling_factor.val);
+
+  gdb_mpz unscaled_z = unscaled.get_rounded ();
+  unscaled_z.write (buf, len, byte_order, unsigned_p);
+}
+
+/* A wrapper around xrealloc that we can then register with GMP
+   as the "realloc" function.  */
+
+static void *
+xrealloc_for_gmp (void *ptr, size_t old_size, size_t new_size)
+{
+  return xrealloc (ptr, new_size);
+}
+
+/* A wrapper around xfree that we can then register with GMP
+   as the "free" function.  */
+
+static void
+xfree_for_gmp (void *ptr, size_t size)
+{
+  xfree (ptr);
+}
+
+extern void _initialize_gmp_utils ();
+
+void
+_initialize_gmp_utils ()
+{
+  /* Tell GMP to use GDB's memory management routines.  */
+  mp_set_memory_functions (xmalloc, xrealloc_for_gmp, xfree_for_gmp);
+}
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
new file mode 100644
index 0000000..8a4fbfe
--- /dev/null
+++ b/gdb/gmp-utils.h
@@ -0,0 +1,282 @@
+/* Miscellaneous routines making it easier to use GMP within GDB's framework.
+
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GMP_UTILS_H
+#define GMP_UTILS_H
+
+#include "defs.h"
+
+/* Include <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
+   access to GMP's various formatting functions.  */
+#include <stdio.h>
+#include <stdarg.h>
+#include <gmp.h>
+#include "gdbsupport/traits.h"
+
+/* Same as gmp_asprintf, but returning a convenient wrapper type.  */
+
+gdb::unique_xmalloc_ptr<char> gmp_string_asprintf (const char *fmt, ...);
+
+/* A class to make it easier to use GMP's mpz_t values within GDB.  */
+
+struct gdb_mpz
+{
+  mpz_t val;
+
+  /* Constructors.  */
+  gdb_mpz () { mpz_init (val); }
+
+  explicit gdb_mpz (const mpz_t &from_val)
+  {
+    mpz_init (val);
+    mpz_set (val, from_val);
+  }
+
+  gdb_mpz (const gdb_mpz &from)
+  {
+    mpz_init (val);
+    mpz_set (val, from.val);
+  }
+
+  /* Initialize using the given integral value.
+
+     The main advantage of this method is that it handles both signed
+     and unsigned types, with no size restriction.  */
+  template<typename T, typename = gdb::Requires<std::is_integral<T>>>
+  explicit gdb_mpz (T src)
+  {
+    mpz_init (val);
+    set (src);
+  }
+
+  explicit gdb_mpz (gdb_mpz &&from)
+  {
+    mpz_init (val);
+    mpz_swap (val, from.val);
+  }
+
+  
+  gdb_mpz &operator= (const gdb_mpz &from)
+  {
+    mpz_set (val, from.val);
+    return *this;
+  }
+
+  gdb_mpz &operator== (gdb_mpz &&other)
+  {
+    mpz_swap (val, other.val);
+    return *this;
+  }
+
+  template<typename T, typename = gdb::Requires<std::is_integral<T>>>
+  gdb_mpz &operator= (T src)
+  {
+    set (src);
+    return *this;
+  }
+
+  /* Convert VAL to an integer of the given type.
+
+     The return type can signed or unsigned, with no size restriction.  */
+  template<typename T> T as_integer () const;
+
+  /* Set VAL by importing the number stored in the byte buffer (BUF),
+     given its size (LEN) and BYTE_ORDER.
+
+     UNSIGNED_P indicates whether the number has an unsigned type.  */
+  void read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+	     bool unsigned_p);
+
+  /* Write VAL into BUF as a LEN-bytes number with the given BYTE_ORDER.
+
+     UNSIGNED_P indicates whether the number has an unsigned type.  */
+  void write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+	      bool unsigned_p) const;
+
+  /* Return a string containing VAL.  */
+  gdb::unique_xmalloc_ptr<char> str () const
+  { return gmp_string_asprintf ("%Zd", val); }
+
+  /* The destructor.  */
+  ~gdb_mpz () { mpz_clear (val); }
+
+private:
+
+  /* Helper template for constructor and operator=.  */
+  template<typename T> void set (T src);
+};
+
+/* A class to make it easier to use GMP's mpq_t values within GDB.  */
+
+struct gdb_mpq
+{
+  mpq_t val;
+
+  /* Constructors.  */
+  gdb_mpq () { mpq_init (val); }
+
+  explicit gdb_mpq (const mpq_t &from_val)
+  {
+    mpq_init (val);
+    mpq_set (val, from_val);
+  }
+
+  gdb_mpq (const gdb_mpq &from)
+  {
+    mpq_init (val);
+    mpq_set (val, from.val);
+  }
+
+  explicit gdb_mpq (gdb_mpq &&from)
+  {
+    mpq_init (val);
+    mpq_swap (val, from.val);
+  }
+
+  /* Copy assignment operator.  */
+  gdb_mpq &operator= (const gdb_mpq &from)
+  {
+    mpq_set (val, from.val);
+    return *this;
+  }
+
+  gdb_mpq &operator= (gdb_mpq &&from)
+  {
+    mpq_swap (val, from.val);
+    return *this;
+  }
+
+  /* Return a string representing VAL as "<numerator> / <denominator>".  */
+  gdb::unique_xmalloc_ptr<char> str () const
+  { return gmp_string_asprintf ("%Qd", val); }
+
+  /* Return VAL rounded to the nearest integer.  */
+  gdb_mpz get_rounded () const;
+
+  /* Set VAL from the contents of the given buffer (BUF), which
+     contains the unscaled value of a fixed point type object
+     with the given size (LEN) and byte order (BYTE_ORDER).
+
+     UNSIGNED_P indicates whether the number has an unsigned type.
+     SCALING_FACTOR is the scaling factor to apply after having
+     read the unscaled value from our buffer.  */
+  void read_fixed_point (const gdb_byte *buf, int len,
+			 enum bfd_endian byte_order, bool unsigned_p,
+			 const gdb_mpq &scaling_factor);
+
+  /* Write VAL into BUF as a LEN-bytes fixed point value following
+     the given BYTE_ORDER.
+
+     UNSIGNED_P indicates whether the number has an unsigned type.
+     SCALING_FACTOR is the scaling factor to apply before writing
+     the unscaled value to our buffer.  */
+  void write_fixed_point (gdb_byte *buf, int len,
+			  enum bfd_endian byte_order, bool unsigned_p,
+			  const gdb_mpq &scaling_factor) const;
+
+  /* The destructor.  */
+  ~gdb_mpq () { mpq_clear (val); }
+};
+
+/* A class to make it easier to use GMP's mpz_t values within GDB.
+
+   Should MPFR become a required dependency, we should probably
+   drop this class in favor of using MPFR.  */
+
+struct gdb_mpf
+{
+  mpf_t val;
+
+  /* Constructors.  */
+  gdb_mpf () { mpf_init (val); }
+
+  DISABLE_COPY_AND_ASSIGN (gdb_mpf);
+
+  /* Set VAL from the contents of the given buffer (BUF), which
+     contains the unscaled value of a fixed point type object
+     with the given size (LEN) and byte order (BYTE_ORDER).
+
+     UNSIGNED_P indicates whether the number has an unsigned type.
+     SCALING_FACTOR is the scaling factor to apply after having
+     read the unscaled value from our buffer.  */
+  void read_fixed_point (const gdb_byte *buf, int len,
+			 enum bfd_endian byte_order, bool unsigned_p,
+			 const gdb_mpq &scaling_factor)
+  {
+    gdb_mpq tmp_q;
+
+    tmp_q.read_fixed_point (buf, len, byte_order, unsigned_p, scaling_factor);
+    mpf_set_q (val, tmp_q.val);
+  }
+
+  /* The destructor.  */
+  ~gdb_mpf () { mpf_clear (val); }
+};
+
+/* See declaration above.  */
+
+template<typename T>
+void
+gdb_mpz::set (T src)
+{
+  mpz_import (val, 1 /* count */, -1 /* order */,
+	      sizeof (T) /* size */, 0 /* endian (0 = native) */,
+	      0 /* nails */, &src /* op */);
+  if (std::is_signed<T>::value && src < 0)
+    {
+      /* mpz_import does not handle the sign, so our value was imported
+	 as an unsigned. Adjust that imported value so as to make it
+	 the correct negative value.  */
+      gdb_mpz neg_offset;
+
+      mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
+      mpz_sub (val, val, neg_offset.val);
+    }
+}
+
+/* See declaration above.  */
+
+template<typename T>
+T
+gdb_mpz::as_integer () const
+{
+  /* Initialize RESULT, because mpz_export only write the minimum
+     number of bytes, including none if our value is zero!  */
+  T result = 0;
+
+  gdb_mpz exported_val (val);
+  if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
+    {
+      /* We want to use mpz_export to set the return value, but
+	 this function does not handle the sign. So give exported_val
+	 a value which is at the same time positive, and has the same
+	 bit representation as our negative value.  */
+      gdb_mpz neg_offset;
+
+      mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
+      mpz_add (exported_val.val, exported_val.val, neg_offset.val);
+    }
+
+  mpz_export (&result, NULL /* count */, -1 /* order */,
+	      sizeof (T) /* size */, 0 /* endian (0 = native) */,
+	      0 /* nails */, exported_val.val);
+  return result;
+}
+
+#endif
diff --git a/gdb/unittests/gmp-utils-selftests.c b/gdb/unittests/gmp-utils-selftests.c
new file mode 100644
index 0000000..b5738eb
--- /dev/null
+++ b/gdb/unittests/gmp-utils-selftests.c
@@ -0,0 +1,460 @@
+/* Self tests of the gmp-utils API.
+
+   Copyright (C) 2019-2020 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 "gmp-utils.h"
+#include "gdbsupport/selftest.h"
+
+#include <math.h>
+
+namespace selftests {
+
+/* Perform a series of general tests of gdb_mpz's as_integer method.
+
+   This function tries to be reasonably exhaustive, by testing the edges,
+   as well as a resonable set of values including negative ones, zero,
+   and positive values.  */
+
+static void
+gdb_mpz_as_integer ()
+{
+  /* Test a range of values, both as LONGEST and ULONGEST.  */
+  gdb_mpz v;
+  LONGEST l_expected;
+  ULONGEST ul_expected;
+
+  /* Start with the smallest LONGEST  */
+  l_expected = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
+
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
+  mpz_neg (v.val, v.val);
+
+  SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
+
+  /* Try with a small range of integers including negative, zero,
+     and positive values.  */
+  for (int i = -256; i <= 256; i++)
+    {
+      l_expected = (LONGEST) i;
+      mpz_set_si (v.val, i);
+      SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
+
+      if (i >= 0)
+	{
+	  ul_expected = (ULONGEST) i;
+	  mpz_set_ui (v.val, i);
+	  SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
+	}
+    }
+
+  /* Try with LONGEST_MAX.  */
+  l_expected = LONGEST_MAX;
+  ul_expected = (ULONGEST) l_expected;
+
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
+  mpz_sub_ui (v.val, v.val, 1);
+
+  SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
+  SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
+
+  /* Try with ULONGEST_MAX.  */
+  ul_expected = ULONGEST_MAX;
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8);
+  mpz_sub_ui (v.val, v.val, 1);
+
+  SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
+}
+
+/* A helper function to store the given integer value into a buffer,
+   before reading it back into a gdb_mpz.  Sets ACTUAL to the value
+   read back, while at the same time setting EXPECTED as the value
+   we would expect to be read back.
+
+   Note that this function does not perform the comparison between
+   EXPECTED and ACTUAL.  The caller will do it inside a SELF_CHECK
+   call, allowing the line information shown when the test fails
+   to provide a bit more information about the kind of values
+   that were used when the check failed.  This makes the writing
+   of the tests a little more verbose, but the debugging in case
+   of problems should hopefuly be easier.  */
+
+template<typename T>
+void
+store_and_read_back (T val, int buf_len, enum bfd_endian byte_order,
+		     gdb_mpz &expected, gdb_mpz &actual)
+{
+  gdb_byte *buf;
+
+  expected = val;
+
+  buf = (gdb_byte *) alloca (buf_len);
+  store_integer (buf, buf_len, byte_order, val);
+
+  /* Pre-initialize ACTUAL to something that's not the expected value.  */
+  mpz_set (actual.val, expected.val);
+  mpz_sub_ui (actual.val, actual.val, 500);
+
+  actual.read (buf, buf_len, byte_order, !std::is_signed<T>::value);
+}
+
+/* Test the gdb_mpz::read method over a reasonable range of values.
+
+   The testing is done by picking an arbitrary buffer length, after
+   which we test every possible value that this buffer allows, both
+   with signed numbers as well as unsigned ones.  */
+
+static void
+gdb_mpz_read_all_from_small ()
+{
+  /* Start with a type whose size is small enough that we can afford
+     to check the complete range.  */
+
+  int buf_len = 1;
+  LONGEST l_min = -pow (2, buf_len * 8 - 1);
+  LONGEST l_max = pow (2, buf_len * 8 - 1) - 1;
+
+  for (LONGEST l = l_min; l <= l_max; l++)
+    {
+      gdb_mpz expected, actual;
+
+      store_and_read_back (l, buf_len, BFD_ENDIAN_BIG, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+      store_and_read_back (l, buf_len, BFD_ENDIAN_LITTLE, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+    }
+
+  /* Do the same as above, but with an unsigned type.  */
+  ULONGEST ul_min = 0;
+  ULONGEST ul_max = pow (2, buf_len * 8) - 1;
+
+  for (ULONGEST ul = ul_min; ul <= ul_max; ul++)
+    {
+      gdb_mpz expected, actual;
+
+      store_and_read_back (ul, buf_len, BFD_ENDIAN_BIG, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+      store_and_read_back (ul, buf_len, BFD_ENDIAN_LITTLE, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+    }
+}
+
+/* Test the gdb_mpz::read the extremes of LONGEST and ULONGEST.  */
+
+static void
+gdb_mpz_read_min_max ()
+{
+  gdb_mpz expected, actual;
+
+  /* Start with the smallest LONGEST.  */
+
+  LONGEST l_min = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
+
+  store_and_read_back (l_min, sizeof (LONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (l_min, sizeof (LONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  /* Same with LONGEST_MAX.  */
+
+  LONGEST l_max = LONGEST_MAX;
+
+  store_and_read_back (l_max, sizeof (LONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (l_max, sizeof (LONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  /* Same with the smallest ULONGEST.  */
+
+  ULONGEST ul_min = 0;
+
+  store_and_read_back (ul_min, sizeof (ULONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (ul_min, sizeof (ULONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  /* Same with ULONGEST_MAX.  */
+
+  ULONGEST ul_max = ULONGEST_MAX;
+
+  store_and_read_back (ul_max, sizeof (ULONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (ul_max, sizeof (ULONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+}
+
+/* A helper function which creates a gdb_mpz object from the given
+   integer VAL, and then writes it using its gdb_mpz::write method.
+
+   The written value is then extracted from the buffer and returned,
+   for comparison with the original.
+
+   Note that this function does not perform the comparison between
+   VAL and the returned value.  The caller will do it inside a SELF_CHECK
+   call, allowing the line information shown when the test fails
+   to provide a bit more information about the kind of values
+   that were used when the check failed.  This makes the writing
+   of the tests a little more verbose, but the debugging in case
+   of problems should hopefuly be easier.  */
+
+template<typename T>
+T
+write_and_extract (T val, int buf_len, enum bfd_endian byte_order)
+{
+  gdb_mpz v (val);
+
+  SELF_CHECK (v.as_integer<T> () == val);
+
+  gdb_byte *buf = (gdb_byte *) alloca (buf_len);
+  v.write (buf, buf_len, byte_order, !std::is_signed<T>::value);
+
+  return extract_integer<T> (buf, buf_len, byte_order);
+}
+
+/* Test the gdb_mpz::write method over a reasonable range of values.
+
+   The testing is done by picking an arbitrary buffer length, after
+   which we test every possible value that this buffer allows.  */
+
+static void
+gdb_mpz_write_all_from_small ()
+{
+  int buf_len = 1;
+  LONGEST l_min = -pow (2, buf_len * 8 - 1);
+  LONGEST l_max = pow (2, buf_len * 8 - 1) - 1;
+
+  for (LONGEST l = l_min; l <= l_max; l++)
+    {
+      SELF_CHECK (write_and_extract (l, buf_len, BFD_ENDIAN_BIG) == l);
+      SELF_CHECK (write_and_extract (l, buf_len, BFD_ENDIAN_LITTLE) == l);
+    }
+
+    /* Do the same as above, but with an unsigned type.  */
+  ULONGEST ul_min = 0;
+  ULONGEST ul_max = pow (2, buf_len * 8) - 1;
+
+  for (ULONGEST ul = ul_min; ul <= ul_max; ul++)
+    {
+      SELF_CHECK (write_and_extract (ul, buf_len, BFD_ENDIAN_BIG) == ul);
+      SELF_CHECK (write_and_extract (ul, buf_len, BFD_ENDIAN_LITTLE) == ul);
+    }
+}
+
+/* Test the gdb_mpz::write the extremes of LONGEST and ULONGEST.  */
+
+static void
+gdb_mpz_write_min_max ()
+{
+  /* Start with the smallest LONGEST.  */
+
+  LONGEST l_min = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
+  SELF_CHECK (write_and_extract (l_min, sizeof (LONGEST), BFD_ENDIAN_BIG)
+	      == l_min);
+  SELF_CHECK (write_and_extract (l_min, sizeof (LONGEST), BFD_ENDIAN_LITTLE)
+	      == l_min);
+
+  /* Same with LONGEST_MAX.  */
+
+  LONGEST l_max = LONGEST_MAX;
+  SELF_CHECK (write_and_extract (l_max, sizeof (LONGEST), BFD_ENDIAN_BIG)
+	      == l_max);
+  SELF_CHECK (write_and_extract (l_max, sizeof (LONGEST), BFD_ENDIAN_LITTLE)
+	      == l_max);
+
+  /* Same with the smallest ULONGEST.  */
+
+  ULONGEST ul_min = (ULONGEST) 1 << (sizeof (ULONGEST) * 8 - 1);
+  SELF_CHECK (write_and_extract (ul_min, sizeof (ULONGEST), BFD_ENDIAN_BIG)
+	      == ul_min);
+  SELF_CHECK (write_and_extract (ul_min, sizeof (ULONGEST), BFD_ENDIAN_LITTLE)
+	      == ul_min);
+
+  /* Same with ULONGEST_MAX.  */
+
+  ULONGEST ul_max = ULONGEST_MAX;
+  SELF_CHECK (write_and_extract (ul_max, sizeof (ULONGEST), BFD_ENDIAN_BIG)
+	      == ul_max);
+  SELF_CHECK (write_and_extract (ul_max, sizeof (ULONGEST), BFD_ENDIAN_LITTLE)
+	      == ul_max);
+}
+
+/* A helper function which stores the signed number, the unscaled value
+   of a fixed point object, into a buffer, and then uses gdb_mpq's
+   read_fixed_point to read it as a fixed_point value, with
+   the given parameters.
+
+   EXPECTED is set to the value we expected to get after the call
+   to read_fixed_point.  ACTUAL is the value we actually do get.
+
+   Note that this function does not perform the comparison between
+   EXPECTED and ACTUAL.  The caller will do it inside a SELF_CHECK
+   call, allowing the line information shown when the test fails
+   to provide a bit more information about the kind of values
+   that were used when the check failed.  This makes the writing
+   of the tests a little more verbose, but the debugging in case
+   of problems should hopefuly be easier.  */
+
+static void
+read_fp_test (int unscaled, const gdb_mpq &scaling_factor,
+	      enum bfd_endian byte_order,
+	      gdb_mpq &expected, gdb_mpq &actual)
+{
+  /* For this kind of testing, we'll use a buffer the same size as
+     our unscaled parameter.  */
+  const int len = sizeof (unscaled);
+  gdb_byte buf[len];
+  store_signed_integer (buf, len, byte_order, unscaled);
+
+  actual.read_fixed_point (buf, len, byte_order, 0, scaling_factor);
+
+  mpq_set_si (expected.val, unscaled, 1);
+  mpq_mul (expected.val, expected.val, scaling_factor.val);
+}
+
+/* Perform various tests of the gdb_mpq::read_fixed_point method.  */
+
+static void
+gdb_mpq_read_fixed_point ()
+{
+  gdb_mpq expected, actual;
+  gdb_mpq scaling_factor;
+
+  /* Pick an arbitrary scaling_factor; this operation is trivial enough
+     thanks to GMP that the value we use isn't really important.  */
+  mpq_set_ui (scaling_factor.val, 3, 5);
+
+  /* Try a few values, both negative and positive... */
+
+  read_fp_test (-256, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (-256, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (-1, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (-1, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (0, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (0, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (1, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (1, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (1025, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (1025, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+}
+
+/* A helper function which builds a gdb_mpq object from the given
+   NUMERATOR and DENOMINATOR, and then calls gdb_mpq's write_fixed_point
+   method to write it to a buffer.
+
+   The value written into the buffer is then read back as is,
+   and returned.  */
+
+static LONGEST
+write_fp_test (int numerator, unsigned int denominator,
+	       const gdb_mpq &scaling_factor,
+	       enum bfd_endian byte_order)
+{
+  /* For this testing, we'll use a buffer the size of LONGEST.
+     This is really an arbitrary decision, as long as the buffer
+     is long enough to hold the unscaled values that we'll be
+     writing.  */
+  const int len = sizeof (LONGEST);
+  gdb_byte buf[len];
+  memset (buf, 0, len);
+
+  gdb_mpq v;
+  mpq_set_ui (v.val, numerator, denominator);
+  mpq_canonicalize (v.val);
+  v.write_fixed_point (buf, len, byte_order, 0, scaling_factor);
+
+  return extract_unsigned_integer (buf, len, byte_order);
+}
+
+/* Perform various tests of the gdb_mpq::write_fixed_point method.  */
+
+static void
+gdb_mpq_write_fixed_point ()
+{
+  /* Pick an arbitrary factor; this operations is sufficiently trivial
+     with the use of GMP that the value of this factor is not really
+     all that important.  */
+  gdb_mpq scaling_factor;
+  mpq_set_ui (scaling_factor.val, 1, 3);
+
+  gdb_mpq vq;
+
+  /* Try a few multiples of the scaling factor, both negative,
+     and positive... */
+
+  SELF_CHECK (write_fp_test (-8, 1, scaling_factor, BFD_ENDIAN_BIG) == -24);
+  SELF_CHECK (write_fp_test (-8, 1, scaling_factor, BFD_ENDIAN_LITTLE) == -24);
+
+  SELF_CHECK (write_fp_test (-2, 3, scaling_factor, BFD_ENDIAN_BIG) == -2);
+  SELF_CHECK (write_fp_test (-2, 3, scaling_factor, BFD_ENDIAN_LITTLE) == -2);
+
+  SELF_CHECK (write_fp_test (0, 3, scaling_factor, BFD_ENDIAN_BIG) == 0);
+  SELF_CHECK (write_fp_test (0, 3, scaling_factor, BFD_ENDIAN_LITTLE) == 0);
+
+  SELF_CHECK (write_fp_test (5, 3, scaling_factor, BFD_ENDIAN_BIG) == 5);
+  SELF_CHECK (write_fp_test (5, 3, scaling_factor, BFD_ENDIAN_LITTLE) == 5);
+}
+
+}
+
+extern void _initialize_gmp_utils_selftests ();
+
+void
+_initialize_gmp_utils_selftests ()
+{
+  selftests::register_test ("gdb_mpz_as_integer",
+			    selftests::gdb_mpz_as_integer);
+  selftests::register_test ("gdb_mpz_read_all_from_small",
+			    selftests::gdb_mpz_read_all_from_small);
+  selftests::register_test ("gdb_mpz_read_min_max",
+			    selftests::gdb_mpz_read_min_max);
+  selftests::register_test ("gdb_mpz_write_all_from_small",
+			    selftests::gdb_mpz_write_all_from_small);
+  selftests::register_test ("gdb_mpz_write_min_max",
+			    selftests::gdb_mpz_write_min_max);
+  selftests::register_test ("gdb_mpq_read_fixed_point",
+			    selftests::gdb_mpq_read_fixed_point);
+  selftests::register_test ("gdb_mpq_write_fixed_point",
+			    selftests::gdb_mpq_write_fixed_point);
+}
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PATCH 4/9] Move uinteger_pow gdb/valarith.c to gdb/utils.c and make it public
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
                   ` (2 preceding siblings ...)
  2020-11-08  6:30 ` [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects Joel Brobecker
@ 2020-11-08  6:30 ` Joel Brobecker
  2020-11-08  6:30 ` [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects Joel Brobecker
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-08  6:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This is a generic function which I would like to use in a followup
patch adding support for fixed-point types. So this commit moves it
out of valarith.c into util.c, and makes it non-static.

gdb/ChangeLog:

        * utils.h (uinteger_pow): Add declaration.
        * utils.c (uinteger_pow): Moved here (without changes)...
        * valarith.c (uinteger_pow): ... from here.
---
 gdb/utils.c    | 30 ++++++++++++++++++++++++++++++
 gdb/utils.h    |  7 +++++++
 gdb/valarith.c | 31 -------------------------------
 3 files changed, 37 insertions(+), 31 deletions(-)

diff --git a/gdb/utils.c b/gdb/utils.c
index ab931c3..3226656 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -709,6 +709,36 @@ myread (int desc, char *addr, int len)
   return orglen;
 }
 
+/* See utils.h.  */
+
+ULONGEST
+uinteger_pow (ULONGEST v1, LONGEST v2)
+{
+  if (v2 < 0)
+    {
+      if (v1 == 0)
+	error (_("Attempt to raise 0 to negative power."));
+      else
+	return 0;
+    }
+  else
+    {
+      /* The Russian Peasant's Algorithm.  */
+      ULONGEST v;
+
+      v = 1;
+      for (;;)
+	{
+	  if (v2 & 1L)
+	    v *= v1;
+	  v2 >>= 1;
+	  if (v2 == 0)
+	    return v;
+	  v1 *= v1;
+	}
+    }
+}
+
 void
 print_spaces (int n, struct ui_file *file)
 {
diff --git a/gdb/utils.h b/gdb/utils.h
index 6948908..a8c65ed 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -593,6 +593,13 @@ extern pid_t wait_to_die_with_timeout (pid_t pid, int *status, int timeout);
 
 extern int myread (int, char *, int);
 
+/* Integer exponentiation: Return V1**V2, where both arguments
+   are integers.
+
+   Requires V1 != 0 if V2 < 0.
+   Returns 1 for 0 ** 0.  */
+extern ULONGEST uinteger_pow (ULONGEST v1, LONGEST v2);
+
 /* Resource limits used by getrlimit and setrlimit.  */
 
 enum resource_limit_kind
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 21b597a..f6caf3d 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -819,37 +819,6 @@ integer_pow (LONGEST v1, LONGEST v2)
     }
 }
 
-/* Integer exponentiation: V1**V2, where both arguments are
-   integers.  Requires V1 != 0 if V2 < 0.  Returns 1 for 0 ** 0.  */
-
-static ULONGEST
-uinteger_pow (ULONGEST v1, LONGEST v2)
-{
-  if (v2 < 0)
-    {
-      if (v1 == 0)
-	error (_("Attempt to raise 0 to negative power."));
-      else
-	return 0;
-    }
-  else 
-    {
-      /* The Russian Peasant's Algorithm.  */
-      ULONGEST v;
-      
-      v = 1;
-      for (;;)
-	{
-	  if (v2 & 1L) 
-	    v *= v1;
-	  v2 >>= 1;
-	  if (v2 == 0)
-	    return v;
-	  v1 *= v1;
-	}
-    }
-}
-
 /* Obtain argument values for binary operation, converting from
    other types if one of them is not floating point.  */
 static void
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
                   ` (3 preceding siblings ...)
  2020-11-08  6:30 ` [PATCH 4/9] Move uinteger_pow gdb/valarith.c to gdb/utils.c and make it public Joel Brobecker
@ 2020-11-08  6:30 ` Joel Brobecker
  2020-11-10 21:06   ` Simon Marchi
  2020-11-08  6:30 ` [PATCH 6/9] fix printing of DWARF fixed-point type objects with format modifier Joel Brobecker
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-08  6:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This commit introduces a new kind of type, meant to describe
fixed-point types, using a new code added specifically for
this purpose (TYPE_CODE_FIXED_POINT).

It then adds handling of fixed-point base types in the DWARF reader.

And finally, as a first step, this commit adds support for printing
the value of fixed-point type objects.

Note that this commit has a known issue: Trying to print the value
of a fixed-point object with a format letter (e.g. "print /x NAME")
causes the wrong value to be printed because the scaling factor
is not applied. Since the fix for this issue is isolated, and
this is not a regression, the fix will be made in a pach of its own.
This is meant to simplify review and archeology.

Also, other functionalities related to fixed-point type handling
(ptype, arithmetics, etc), will be added piecemeal as well, for
the same reasons (faciliate reviews and archeology). Related to this,
the testcase gdb.ada/fixed_cmp.exp is adjusted to compile the test
program with -fgnat-encodings=all, so as to force the use of GNAT
encodings, rather than rely on the compiler's default to use them.
The intent is to enhance this testcase to also test the pure DWARF
approach using -fgnat-encodings=minimal as soon as the corresponding
suport gets added in. Thus, the modification to the testcase is made
in a way that it prepares this testcase to be tested in both modes.

gdb/ChangeLog:

        * ada-valprint.c (ada_value_print_1): Add fixed-point type handling.
        * dwarf2/read.c (get_dwarf2_rational_constant)
        (get_dwarf2_unsigned_rational_constant, finish_fixed_point_type)
        (has_zero_over_zero_small_attribute): New functions.
        read_base_type, set_die_type): Add fixed-point type handling.
        * gdb-gdb.py.in: Add fixed-point type handling.
        * gdbtypes.c: #include "gmp-utils.h".
        (create_range_type, set_type_code): Add fixed-point type handling.
        (init_fixed_point_type): New function.
        (is_integral_type, is_scalar_type): Add fixed-point type handling.
        (print_fixed_point_type_info): New function.
        (recursive_dump_type, copy_type_recursive): Add fixed-point type
        handling.
        (fixed_point_type_storage): New typedef.
        (fixed_point_objfile_key): New static global.
        (allocate_fixed_point_type_info, is_fixed_point_type): New functions.
        (fixed_point_type_base_type, fixed_point_scaling_factor): New
        functions.
        * gdbtypes.h: #include "gmp-utils.h".
        (enum type_code) <TYPE_SPECIFIC_FIXED_POINT>: New enum.
        (union type_specific) <fixed_point_info>: New field.
        (struct fixed_point_type_info): New struct.
        (INIT_FIXED_POINT_SPECIFIC, TYPE_FIXED_POINT_INFO): New macros.
        (init_fixed_point_type, is_fixed_point_type)
        (fixed_point_type_base_type, fixed_point_scaling_factor)
        (allocate_fixed_point_type_info): Add declarations.
        * valprint.c (generic_val_print_fixed_point): New function.
        (generic_value_print): Add fixed-point type handling.
        * value.c (value_as_address, unpack_long): Add fixed-point type
        handling.

gdb/testsuite/ChangeLog:

        * gdb.ada/fixed_cmp.exp: Force compilation to use -fgnat-encodings=all.
        * gdb.ada/fixed_points.exp: Add fixed-point variables printing tests.
        * gdb.ada/fixed_points/pck.ads, gdb.ada/fixed_points/pck.adb:
        New files.
        * gdb.ada/fixed_points/fixed_points.adb: Add use of package Pck.

        * gdb.dwarf2/dw2-fixed-point.c, gdb.dwarf2/dw2-fixed-point.exp:
        New files.
---
 gdb/ada-valprint.c                                 |   3 +
 gdb/dwarf2/read.c                                  | 211 +++++++++++++++++++++
 gdb/gdb-gdb.py.in                                  |   5 +
 gdb/gdbtypes.c                                     | 133 ++++++++++++-
 gdb/gdbtypes.h                                     |  53 +++++-
 gdb/testsuite/gdb.ada/fixed_cmp.exp                |  34 ++--
 gdb/testsuite/gdb.ada/fixed_points.exp             |  11 ++
 .../gdb.ada/fixed_points/fixed_points.adb          |   4 +
 gdb/testsuite/gdb.ada/fixed_points/pck.adb         |  22 +++
 gdb/testsuite/gdb.ada/fixed_points/pck.ads         |  30 +++
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c         |  49 +++++
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp       | 132 +++++++++++++
 gdb/valprint.c                                     |  33 ++++
 gdb/value.c                                        |  14 ++
 14 files changed, 716 insertions(+), 18 deletions(-)
 create mode 100644 gdb/testsuite/gdb.ada/fixed_points/pck.adb
 create mode 100644 gdb/testsuite/gdb.ada/fixed_points/pck.ads
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp

diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c
index d7704f0..482069a 100644
--- a/gdb/ada-valprint.c
+++ b/gdb/ada-valprint.c
@@ -1027,6 +1027,9 @@ ada_value_print_1 (struct value *val, struct ui_file *stream, int recurse,
       deprecated_set_value_type (val, type);
     }
 
+  if (is_fixed_point_type (type))
+    type = fixed_point_type_base_type (type);
+
   switch (type->code ())
     {
     default:
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index dbf0a3e..1f5152d 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -18130,6 +18130,157 @@ read_typedef (struct die_info *die, struct dwarf2_cu *cu)
   return this_type;
 }
 
+/* Assuming DIE is a rational DW_TAG_constant, read the DIE's
+   numerator and denominator into NUMERATOR and DENOMINATOR (resp).
+
+   If the numerator and/or numerator attribute is missing,
+   a complaint is filed, and NUMERATOR and DENOMINATOR are left
+   untouched.  */
+
+static void
+get_dwarf2_rational_constant (struct die_info *die, struct dwarf2_cu *cu,
+			      LONGEST *numerator, LONGEST *denominator)
+{
+  struct attribute *num_attr, *denom_attr;
+
+  num_attr = dwarf2_attr (die, DW_AT_GNU_numerator, cu);
+  if (num_attr == NULL)
+    complaint (_("DW_AT_GNU_numerator missing in %s DIE at %s"),
+	       dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
+
+  denom_attr = dwarf2_attr (die, DW_AT_GNU_denominator, cu);
+  if (denom_attr == NULL)
+    complaint (_("DW_AT_GNU_denominator missing in %s DIE at %s"),
+	       dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
+
+  if (num_attr == NULL || denom_attr == NULL)
+    return;
+
+  *numerator = num_attr->constant_value (1);
+  *denominator = denom_attr->constant_value (1);
+}
+
+/* Same as get_dwarf2_rational_constant, but extracting an unsigned
+   rational constant, rather than a signed one.
+
+   If the rational constant is has a negative value, a complaint
+   is filed, and NUMERATOR and DENOMINATOR are left untouched.  */
+
+static void
+get_dwarf2_unsigned_rational_constant (struct die_info *die,
+				       struct dwarf2_cu *cu,
+				       ULONGEST *numerator,
+				       ULONGEST *denominator)
+{
+  LONGEST num = 1, denom = 1;
+
+  get_dwarf2_rational_constant (die, cu, &num, &denom);
+  if (num < 0 && denom < 0)
+    {
+      num = -num;
+      denom = -denom;
+    }
+  else if (num < 0)
+    {
+      complaint (_("unexpected negative value for DW_AT_GNU_numerator"
+		   " in DIE at %s"),
+		 sect_offset_str (die->sect_off));
+      return;
+    }
+  else if (denom < 0)
+    {
+      complaint (_("unexpected negative value for DW_AT_GNU_denominator"
+		   " in DIE at %s"),
+		 sect_offset_str (die->sect_off));
+      return;
+    }
+
+  *numerator = num;
+  *denominator = denom;
+}
+
+/* Assiuming DIE corresponds to a fixed point type, finish the creation
+   of the corresponding TYPE by setting its TYPE_FIXED_POINT_INFO.
+   CU is the DIE's CU.  */
+
+static void
+finish_fixed_point_type (struct type *type, struct die_info *die,
+			 struct dwarf2_cu *cu)
+{
+  struct attribute *attr;
+  /* Numerator and denominator of our fixed-point type's scaling factor.
+     The default is a scaling factor of 1, which we use as a fallback
+     when we are not able to decode it (problem with the debugging info,
+     unsupported forms, bug in GDB, etc...).  Using that as the default
+     allows us to at least print the unscaled value, which might still
+     be useful to a user.  */
+  ULONGEST scale_num = 1;
+  ULONGEST scale_denom = 1;
+
+  gdb_assert (type->code () == TYPE_CODE_FIXED_POINT
+	      && TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_FIXED_POINT);
+
+  attr = dwarf2_attr (die, DW_AT_binary_scale, cu);
+  if (!attr)
+    attr = dwarf2_attr (die, DW_AT_decimal_scale, cu);
+  if (!attr)
+    attr = dwarf2_attr (die, DW_AT_small, cu);
+
+  if (attr == NULL)
+    {
+      /* Scaling factor not found.  Assume a scaling factor of 1,
+	 and hope for the best.  At least the user will be able to see
+	 the encoded value.  */
+      complaint (_("no scale found for fixed-point type (DIE at %s)"),
+		 sect_offset_str (die->sect_off));
+    }
+  else if (attr->name == DW_AT_binary_scale)
+    {
+      LONGEST scale_exp = attr->constant_value (0);
+      ULONGEST *num_or_denom = scale_exp > 0 ? &scale_num : &scale_denom;
+
+      *num_or_denom = 1 << abs (scale_exp);
+    }
+  else if (attr->name == DW_AT_decimal_scale)
+    {
+      LONGEST scale_exp = attr->constant_value (0);
+      ULONGEST *num_or_denom = scale_exp > 0 ? &scale_num : &scale_denom;
+
+      *num_or_denom = uinteger_pow (10, abs (scale_exp));
+    }
+  else if (attr->name == DW_AT_small)
+    {
+      struct die_info *scale_die;
+      struct dwarf2_cu *scale_cu = cu;
+
+      scale_die = follow_die_ref (die, attr, &scale_cu);
+      if (scale_die->tag == DW_TAG_constant)
+	get_dwarf2_unsigned_rational_constant (scale_die, scale_cu,
+					       &scale_num, &scale_denom);
+      else
+	complaint (_("%s DIE not supported as target of DW_AT_small attribute"
+		     " (DIE at %s)"),
+		   dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
+    }
+  else
+    {
+      complaint (("unsupported scale attribute %s for fixed-point type"
+		   " (DIE at %s)"),
+		 dwarf_attr_name (attr->name),
+		 sect_offset_str (die->sect_off));
+    }
+
+  gdb_mpq &scaling_factor = TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+
+  gdb_mpz tmp_z (scale_num);
+  mpz_set (mpq_numref (scaling_factor.val), tmp_z.val);
+
+  tmp_z = scale_denom;
+  mpz_set (mpq_denref (scaling_factor.val), tmp_z.val);
+
+  mpq_canonicalize (scaling_factor.val);
+}
+
 /* Allocate a floating-point type of size BITS and name NAME.  Pass NAME_HINT
    (which may be different from NAME) to the architecture back-end to allow
    it to guess the correct format if necessary.  */
@@ -18171,6 +18322,32 @@ dwarf2_init_integer_type (struct dwarf2_cu *cu, struct objfile *objfile,
   return type;
 }
 
+/* Return true if DIE has a DW_AT_small attribute whose value is
+   a constant rational, where both the numerator and denominator
+   are equal to zero.
+
+   CU is the DIE's Compilation Unit.  */
+
+static bool
+has_zero_over_zero_small_attribute (struct die_info *die,
+				    struct dwarf2_cu *cu)
+{
+  struct attribute *attr = dwarf2_attr (die, DW_AT_small, cu);
+  if (attr == NULL)
+    return false;
+
+  struct dwarf2_cu *scale_cu = cu;
+  struct die_info *scale_die
+    = follow_die_ref (die, attr, &scale_cu);
+
+  if (scale_die->tag != DW_TAG_constant)
+    return false;
+
+  LONGEST num = 1, denom = 1;
+  get_dwarf2_rational_constant (scale_die, cu, &num, &denom);
+  return (num == 0 && denom == 0);
+}
+
 /* Initialise and return a floating point type of size BITS suitable for
    use as a component of a complex number.  The NAME_HINT is passed through
    when initialising the floating point type and is the name of the complex
@@ -18281,6 +18458,31 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
 	}
     }
 
+  if ((encoding == DW_ATE_signed_fixed || encoding == DW_ATE_unsigned_fixed)
+      && cu->language == language_ada
+      && has_zero_over_zero_small_attribute (die, cu))
+    {
+      /* brobecker/2018-02-24: This is a fixed point type for which
+	 the scaling factor is represented as fraction whose value
+	 does not make sense (zero divided by zero), so we should
+	 normally never see these.  However, there is a small category
+	 of fixed point types for which GNAT is unable to provide
+	 the scaling factor via the standard DWARF mechanisms, and
+	 for which the info is provided via the GNAT encodings instead.
+	 This is likely what this DIE is about.
+
+	 Ideally, GNAT should be declaring this type the same way
+	 it declares other fixed point types when using the legacy
+	 GNAT encoding, which is to use a simple signed or unsigned
+	 base type.  A report to the GNAT team has been created to
+	 look into it.  In the meantime, pretend this type is a simple
+	 signed or unsigned integral, rather than a fixed point type,
+	 to avoid any confusion later on as to how to process this type.  */
+      encoding = (encoding == DW_ATE_signed_fixed
+		  ? DW_ATE_signed
+		  : DW_ATE_unsigned);
+    }
+
   switch (encoding)
     {
       case DW_ATE_address:
@@ -18357,6 +18559,14 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
 	  return set_die_type (die, type, cu);
 	}
 	break;
+      case DW_ATE_signed_fixed:
+	type = init_fixed_point_type (objfile, bits, 0, name);
+	finish_fixed_point_type (type, die, cu);
+	break;
+      case DW_ATE_unsigned_fixed:
+	type = init_fixed_point_type (objfile, bits, 1, name);
+	finish_fixed_point_type (type, die, cu);
+	break;
 
       default:
 	complaint (_("unsupported DW_AT_encoding: '%s'"),
@@ -24789,6 +24999,7 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
       && type->code () != TYPE_CODE_METHODPTR
       && type->code () != TYPE_CODE_MEMBERPTR
       && type->code () != TYPE_CODE_METHOD
+      && type->code () != TYPE_CODE_FIXED_POINT
       && !HAVE_GNAT_AUX_INFO (type))
     INIT_GNAT_SPECIFIC (type);
 
diff --git a/gdb/gdb-gdb.py.in b/gdb/gdb-gdb.py.in
index 6594ac1..ff68bd7 100644
--- a/gdb/gdb-gdb.py.in
+++ b/gdb/gdb-gdb.py.in
@@ -229,6 +229,11 @@ class StructMainTypePrettyPrinter:
             # tail_call_list is not printed.
         elif type_specific_kind == "TYPE_SPECIFIC_SELF_TYPE":
             img = "self_type = %s" % type_specific['self_type']
+        elif type_specific_kind == "TYPE_SPECIFIC_FIXED_POINT":
+            # The scaling factor is an opaque structure, so we cannot
+            # decode its value from Python (not without insider knowledge).
+            img = ('scaling_factor: <opaque> (call __gmpz_dump with '
+                   ' _mp_num and _mp_den fields if needed)')
         else:
             img = ("type_specific = ??? (unknown type_secific_kind: %s)"
                    % type_specific_kind)
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 686edaf..a3a6f07 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -40,6 +40,7 @@
 #include "gdbcore.h"
 #include "floatformat.h"
 #include <algorithm>
+#include "gmp-utils.h"
 
 /* Initialize BADNESS constants.  */
 
@@ -950,6 +951,8 @@ create_range_type (struct type *result_type, struct type *index_type,
 
   result_type->set_bounds (bounds);
 
+  if (index_type->code () == TYPE_CODE_FIXED_POINT)
+    result_type->set_is_unsigned (index_type->is_unsigned ());
   /* Note that the signed-ness of a range type can't simply be copied
      from the underlying type.  Consider a case where the underlying
      type is 'int', but the range type can hold 0..65535, and where
@@ -957,7 +960,7 @@ create_range_type (struct type *result_type, struct type *index_type,
      case, if we copy the underlying type's sign, then reading some
      range values will cause an unwanted sign extension.  So, we have
      some heuristics here instead.  */
-  if (low_bound->kind () == PROP_CONST && low_bound->const_val () >= 0)
+  else if (low_bound->kind () == PROP_CONST && low_bound->const_val () >= 0)
     result_type->set_is_unsigned (true);
   /* Ada allows the declaration of range types whose upper bound is
      less than the lower bound, so checking the lower bound is not
@@ -3136,6 +3139,9 @@ set_type_code (struct type *type, enum type_code code)
 	break;
       case TYPE_CODE_FUNC:
 	INIT_FUNC_SPECIFIC (type);
+        break;
+      case TYPE_CODE_FIXED_POINT:
+	INIT_FIXED_POINT_SPECIFIC (type);
 	break;
     }
 }
@@ -3352,6 +3358,24 @@ init_pointer_type (struct objfile *objfile,
   return t;
 }
 
+/* Allocate a TYPE_CODE_FIXED_POINT type structure associated with OBJFILE.
+   BIT is the pointer type size in bits.
+   UNSIGNED_P should be nonzero if the type is unsigned.
+   NAME is the type name.  */
+
+struct type *
+init_fixed_point_type (struct objfile *objfile,
+		       int bit, int unsigned_p, const char *name)
+{
+  struct type *t;
+
+  t = init_type (objfile, TYPE_CODE_FIXED_POINT, bit, name);
+  if (unsigned_p)
+    t->set_is_unsigned (true);
+
+  return t;
+}
+
 /* See gdbtypes.h.  */
 
 unsigned
@@ -3498,6 +3522,7 @@ is_integral_type (struct type *t)
   t = check_typedef (t);
   return
     ((t != NULL)
+     && !is_fixed_point_type (t)
      && ((t->code () == TYPE_CODE_INT)
 	 || (t->code () == TYPE_CODE_ENUM)
 	 || (t->code () == TYPE_CODE_FLAGS)
@@ -3523,6 +3548,9 @@ is_scalar_type (struct type *type)
 {
   type = check_typedef (type);
 
+  if (is_fixed_point_type (type))
+    return 0; /* Implemented as a scalar, but more like a floating point.  */
+
   switch (type->code ())
     {
     case TYPE_CODE_ARRAY:
@@ -4887,6 +4915,16 @@ print_gnat_stuff (struct type *type, int spaces)
     }
 }
 
+/* Print the contents of the TYPE's type_specific union, assuming that
+   its type-specific kind is TYPE_SPECIFIC_FIXED_POINT.  */
+
+static void
+print_fixed_point_type_info (struct type *type, int spaces)
+{
+  printfi_filtered (spaces + 2, "scaling factor: %s\n",
+		    fixed_point_scaling_factor (type).str ().get ());
+}
+
 static struct obstack dont_print_type_obstack;
 
 /* Print the dynamic_prop PROP.  */
@@ -5025,6 +5063,9 @@ recursive_dump_type (struct type *type, int spaces)
     case TYPE_CODE_NAMESPACE:
       printf_filtered ("(TYPE_CODE_NAMESPACE)");
       break;
+    case TYPE_CODE_FIXED_POINT:
+      printf_filtered ("(TYPE_CODE_FIXED_POINT)");
+      break;
     default:
       printf_filtered ("(UNKNOWN TYPE CODE)");
       break;
@@ -5217,6 +5258,12 @@ recursive_dump_type (struct type *type, int spaces)
 	puts_filtered ("\n");
 	break;
 
+      case TYPE_SPECIFIC_FIXED_POINT:
+	printfi_filtered (spaces, "fixed_point_info ");
+	print_fixed_point_type_info (type, spaces);
+	puts_filtered ("\n");
+	break;
+
     case TYPE_SPECIFIC_INT:
       if (type->bit_size_differs_p ())
 	{
@@ -5449,6 +5496,11 @@ copy_type_recursive (struct objfile *objfile,
 			  copy_type_recursive (objfile, TYPE_SELF_TYPE (type),
 					       copied_types));
       break;
+    case TYPE_SPECIFIC_FIXED_POINT:
+      INIT_FIXED_POINT_SPECIFIC (new_type);
+      TYPE_FIXED_POINT_INFO (new_type)->scaling_factor
+	= TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+      break;
     case TYPE_SPECIFIC_INT:
       TYPE_SPECIFIC_FIELD (new_type) = TYPE_SPECIFIC_INT;
       TYPE_MAIN_TYPE (new_type)->type_specific.int_stuff
@@ -5752,6 +5804,85 @@ append_composite_type_field (struct type *t, const char *name,
   append_composite_type_field_aligned (t, name, field, 0);
 }
 
+\f
+
+/* We manage the lifetimes of fixed_point_type_info objects by
+   attaching them to the objfile.  Currently, these objects are
+   modified during construction, and GMP does not provide a way to
+   hash the contents of an mpq_t; so it's a bit of a pain to hash-cons
+   them.  If we did do this, they could be moved to the per-BFD and
+   shared across objfiles.  */
+typedef std::vector<std::unique_ptr<fixed_point_type_info>>
+    fixed_point_type_storage;
+
+/* Key used for managing the storage of fixed-point type info.  */
+static const struct objfile_key<fixed_point_type_storage>
+    fixed_point_objfile_key;
+
+/* See gdbtypes.h.  */
+
+fixed_point_type_info *
+allocate_fixed_point_type_info (struct type *type)
+{
+  std::unique_ptr<fixed_point_type_info> up (new fixed_point_type_info);
+  fixed_point_type_info *result;
+
+  if (TYPE_OBJFILE_OWNED (type))
+    {
+      fixed_point_type_storage *storage
+	= fixed_point_objfile_key.get (TYPE_OBJFILE (type));
+      if (storage == nullptr)
+	storage = fixed_point_objfile_key.emplace (TYPE_OBJFILE (type));
+      result = up.get ();
+      storage->push_back (std::move (up));
+    }
+  else
+    {
+      /* We just leak the memory, because that's what we do generally
+	 for non-objfile-attached types.  */
+      result = up.release ();
+    }
+
+  return result;
+}
+
+/* See gdbtypes.h.  */
+
+int
+is_fixed_point_type (struct type *type)
+{
+  while (check_typedef (type)->code () == TYPE_CODE_RANGE)
+    type = TYPE_TARGET_TYPE (check_typedef (type));
+  type = check_typedef (type);
+
+  return type->code () == TYPE_CODE_FIXED_POINT;
+}
+
+/* See gdbtypes.h.  */
+
+struct type *
+fixed_point_type_base_type (struct type *type)
+{
+  while (check_typedef (type)->code () == TYPE_CODE_RANGE)
+    type = TYPE_TARGET_TYPE (check_typedef (type));
+  type = check_typedef (type);
+
+  gdb_assert (type->code () == TYPE_CODE_FIXED_POINT);
+  return type;
+}
+
+/* See gdbtypes.h.  */
+
+const gdb_mpq &
+fixed_point_scaling_factor (struct type *type)
+{
+  type = fixed_point_type_base_type (type);
+
+  return TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+}
+
+\f
+
 static struct gdbarch_data *gdbtypes_data;
 
 const struct builtin_type *
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 4d574e2..254f227 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -52,6 +52,7 @@
 #include "gdbsupport/print-utils.h"
 #include "dwarf2.h"
 #include "gdb_obstack.h"
+#include "gmp-utils.h"
 
 /* Forward declarations for prototypes.  */
 struct field;
@@ -189,7 +190,10 @@ enum type_code
     TYPE_CODE_INTERNAL_FUNCTION,
 
     /* * Methods implemented in extension languages.  */
-    TYPE_CODE_XMETHOD
+    TYPE_CODE_XMETHOD,
+
+    /* * Fixed Point type.  */
+    TYPE_CODE_FIXED_POINT,
   };
 
 /* * Some bits for the type's instance_flags word.  See the macros
@@ -600,7 +604,8 @@ enum type_specific_kind
   /* Note: This is used by TYPE_CODE_FUNC and TYPE_CODE_METHOD.  */
   TYPE_SPECIFIC_FUNC,
   TYPE_SPECIFIC_SELF_TYPE,
-  TYPE_SPECIFIC_INT
+  TYPE_SPECIFIC_INT,
+  TYPE_SPECIFIC_FIXED_POINT,
 };
 
 union type_owner
@@ -766,6 +771,10 @@ union type_specific
 
   struct type *self_type;
 
+  /* * For TYPE_CODE_FIXED_POINT types, the info necessary to decode
+     values of that type.  */
+  struct fixed_point_type_info *fixed_point_info;
+
   /* * An integer-like scalar type may be stored in just part of its
      enclosing storage bytes.  This structure describes this
      situation.  */
@@ -1678,6 +1687,14 @@ struct call_site
     struct call_site_parameter parameter[1];
   };
 
+/* The type-specific info for TYPE_CODE_FIXED_POINT types.  */
+
+struct fixed_point_type_info
+{
+  /* The fixed point type's scaling factor.  */
+  gdb_mpq scaling_factor;
+};
+
 /* * The default value of TYPE_CPLUS_SPECIFIC(T) points to this shared
    static structure.  */
 
@@ -1725,6 +1742,13 @@ extern void allocate_gnat_aux_type (struct type *);
      TYPE_ZALLOC (type,							       \
 		  sizeof (*TYPE_MAIN_TYPE (type)->type_specific.func_stuff)))
 
+/* "struct fixed_point_type_info" has a field that has a destructor.
+   See allocate_fixed_point_type_info to understand how this is
+   handled.  */
+#define INIT_FIXED_POINT_SPECIFIC(type) \
+  (TYPE_SPECIFIC_FIELD (type) = TYPE_SPECIFIC_FIXED_POINT, \
+   TYPE_FIXED_POINT_INFO (type) = allocate_fixed_point_type_info (type))
+
 #define TYPE_MAIN_TYPE(thistype) (thistype)->main_type
 #define TYPE_TARGET_TYPE(thistype) TYPE_MAIN_TYPE(thistype)->target_type
 #define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type
@@ -1821,6 +1845,9 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
   (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits == NULL ? 0 \
     : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index)))
 
+#define TYPE_FIXED_POINT_INFO(thistype) \
+  (TYPE_MAIN_TYPE(thistype)->type_specific.fixed_point_info)
+
 #define FIELD_NAME(thisfld) ((thisfld).name)
 #define FIELD_LOC_KIND(thisfld) ((thisfld).loc_kind)
 #define FIELD_BITPOS_LVAL(thisfld) ((thisfld).loc.bitpos)
@@ -2192,6 +2219,8 @@ extern struct type *init_decfloat_type (struct objfile *, int, const char *);
 extern struct type *init_complex_type (const char *, struct type *);
 extern struct type *init_pointer_type (struct objfile *, int, const char *,
 				       struct type *);
+extern struct type *init_fixed_point_type (struct objfile *, int, int,
+					   const char *);
 
 /* Helper functions to construct architecture-owned types.  */
 extern struct type *arch_type (struct gdbarch *, enum type_code, int,
@@ -2529,6 +2558,26 @@ extern int type_not_allocated (const struct type *type);
 
 extern int type_not_associated (const struct type *type);
 
+/* Return True if TYPE is a TYPE_CODE_FIXED_POINT or if TYPE is
+   range whose base type is a TYPE_CODE_FIXED_POINT.  */
+extern int is_fixed_point_type (struct type *type);
+
+/* Assuming that TYPE is a fixed point type, return its base type.
+
+   In other words, this returns the type after having peeled all
+   intermediate type layers (such as TYPE_CODE_RANGE, for instance).
+   The TYPE_CODE of the type returned is guaranteed to be
+   a TYPE_CODE_FIXED_POINT.  */
+extern struct type *fixed_point_type_base_type (struct type *type);
+
+/* Given TYPE, which is a fixed point type, return its scaling factor.  */
+extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);
+
+/* Allocate a fixed-point type info for TYPE.  This should only be
+   called by INIT_FIXED_POINT_SPECIFIC.  */
+extern fixed_point_type_info *allocate_fixed_point_type_info
+  (struct type *type);
+
 /* * When the type includes explicit byte ordering, return that.
    Otherwise, the byte ordering from gdbarch_byte_order for 
    get_type_arch is returned.  */
diff --git a/gdb/testsuite/gdb.ada/fixed_cmp.exp b/gdb/testsuite/gdb.ada/fixed_cmp.exp
index 38e41c4..10e2c9a 100644
--- a/gdb/testsuite/gdb.ada/fixed_cmp.exp
+++ b/gdb/testsuite/gdb.ada/fixed_cmp.exp
@@ -19,25 +19,29 @@ if { [skip_ada_tests] } { return -1 }
 
 standard_ada_testfile fixed
 
-if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug ]] != "" } {
-  return -1
-}
+foreach_with_prefix scenario {all} {
+    set flags [list debug additional_flags=-fgnat-encodings=$scenario]
+
+    if {[gdb_compile_ada "${srcfile}" "${binfile}" executable $flags] != "" } {
+      return -1
+    }
 
-clean_restart ${testfile}
+    clean_restart ${testfile}
 
-set bp_location [gdb_get_line_number "STOP" ${testdir}/fixed.adb]
-runto "fixed.adb:$bp_location"
+    set bp_location [gdb_get_line_number "STOP" ${testdir}/fixed.adb]
+    runto "fixed.adb:$bp_location"
 
-gdb_test "print My_Var > 10.0" \
-         "= true"
+    gdb_test "print My_Var > 10.0" \
+             "= true"
 
-gdb_test "print My_Var > 20.0" \
-         "= false"
+    gdb_test "print My_Var > 20.0" \
+             "= false"
 
-# Do the same, but with integer values.
+    # Do the same, but with integer values.
 
-gdb_test "print My_Var > 10" \
-         "= true"
+    gdb_test "print My_Var > 10" \
+             "= true"
 
-gdb_test "print My_Var > 20" \
-         "= false"
+    gdb_test "print My_Var > 20" \
+             "= false"
+}
diff --git a/gdb/testsuite/gdb.ada/fixed_points.exp b/gdb/testsuite/gdb.ada/fixed_points.exp
index f991f56..655ee95 100644
--- a/gdb/testsuite/gdb.ada/fixed_points.exp
+++ b/gdb/testsuite/gdb.ada/fixed_points.exp
@@ -49,3 +49,14 @@ gdb_test "print Overprecise_Object" \
 
 gdb_test "ptype Overprecise_Object" \
          "= delta 0.135791"
+
+# FP*_Var...
+
+gdb_test "print fp1_var" \
+         " = 0.25"
+
+gdb_test "print fp2_var" \
+         " = -0.01"
+
+gdb_test "print fp3_var" \
+         " = 0.1"
diff --git a/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb b/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb
index a2720e3..f0a34ba 100644
--- a/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb
+++ b/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb
@@ -14,6 +14,7 @@
 --  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 with System;
+with Pck; use Pck;
 
 procedure Fixed_Points is
 
@@ -59,4 +60,7 @@ begin
    Subtype_Object := 1.0/16.0;
    New_Type_Object := 1.0/16.0;
    Overprecise_Object := Overprecise_Fixed_Point'Small * 2;
+   Do_Nothing (FP1_Var'Address);
+   Do_Nothing (FP2_Var'Address);
+   Do_Nothing (FP3_Var'Address);
 end Fixed_Points;
diff --git a/gdb/testsuite/gdb.ada/fixed_points/pck.adb b/gdb/testsuite/gdb.ada/fixed_points/pck.adb
new file mode 100644
index 0000000..16f0384
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/fixed_points/pck.adb
@@ -0,0 +1,22 @@
+--  Copyright 2016-2020 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/>.
+
+package body Pck is
+   procedure Do_Nothing (A : System.Address) is
+   begin
+      null;
+   end Do_Nothing;
+end pck;
+
diff --git a/gdb/testsuite/gdb.ada/fixed_points/pck.ads b/gdb/testsuite/gdb.ada/fixed_points/pck.ads
new file mode 100644
index 0000000..4d900dc
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/fixed_points/pck.ads
@@ -0,0 +1,30 @@
+--  Copyright 2016-2020 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/>.
+
+with System;
+
+package Pck is
+   type FP1_Type is delta 0.1 range -1.0 .. +1.0;
+   FP1_Var : FP1_Type := 0.25;
+
+   type FP2_Type is delta 0.01 digits 14;
+   FP2_Var : FP2_Type := -0.01;
+
+   type FP3_Type is delta 0.1 range 0.0 .. 1.0 with Small => 0.1/3.0;
+   FP3_Var : FP3_Type := 0.1;
+
+   procedure Do_Nothing (A : System.Address);
+end pck;
+
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
new file mode 100644
index 0000000..d9c811c
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
@@ -0,0 +1,49 @@
+/* Copyright 2016-2020 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 <stdint.h>
+
+/* Simulate an Ada variable declared inside package Pck as follow:
+      type FP1_Type is delta 0.1 range -1.0 .. +1.0;
+      FP1_Var : FP1_Type := 0.25;  */
+int8_t pck__fp1_var = 4;
+
+/* Simulate an Ada variable declared inside package Pck as follow:
+      type FP2_Type is delta 0.01 digits 14;
+      FP2_Var : FP2_Type := -0.01;  */
+int32_t pck__fp2_var = -1;
+
+/* Simulate an Ada variable declared inside package Pck as follow:
+      type FP3_Type is delta 0.1 range 0.0 .. 1.0 with Small => 0.1/3.0;
+      FP3_Var : FP3_Type := 0.1;  */
+int8_t pck__fp3_var = 3;
+
+/* Simulate an Ada variable declared inside package Pck as follow:
+      type FP1_Type is delta 0.1 range -1.0 .. +1.0;
+      FP1_Var : FP1_Type := 1.0;  */
+int8_t pck__fp1_range_var = 16;
+
+int
+main (void)
+{
+  pck__fp1_var++;
+  pck__fp2_var++;
+  pck__fp3_var++;
+  pck__fp1_range_var++;
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
new file mode 100644
index 0000000..bf88ffe
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
@@ -0,0 +1,132 @@
+# Copyright 2016-2020 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/>.
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+standard_testfile dw2-fixed-point.c dw2-fixed-point-dw.S
+
+# Make some DWARF for the test.
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    cu {} {
+ 	DW_TAG_compile_unit {
+                {DW_AT_language @DW_LANG_Ada95}
+                {DW_AT_name     pck.ads}
+                {DW_AT_comp_dir /tmp}
+        } {
+            declare_labels fp1_base_type fp2_base_type fp3_small \
+                fp3_base_type fp1_range_type
+
+            fp1_base_type: DW_TAG_base_type {
+                {DW_AT_byte_size     1 DW_FORM_sdata}
+                {DW_AT_encoding      @DW_ATE_signed_fixed}
+                {DW_AT_name          pck__fp1_type}
+                {DW_AT_binary_scale  -4 DW_FORM_sdata}
+            }
+
+            DW_TAG_variable {
+                {DW_AT_name pck__fp1_var}
+                {DW_AT_type :$fp1_base_type}
+                {DW_AT_location {
+                    DW_OP_addr [gdb_target_symbol pck__fp1_var]
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+
+            fp2_base_type: DW_TAG_base_type {
+                {DW_AT_byte_size     1 DW_FORM_sdata}
+                {DW_AT_encoding      @DW_ATE_signed_fixed}
+                {DW_AT_name          pck__fp2_type}
+                {DW_AT_decimal_scale -2 DW_FORM_sdata}
+            }
+
+            DW_TAG_variable {
+                {DW_AT_name pck__fp2_var}
+                {DW_AT_type :$fp2_base_type}
+                {DW_AT_location {
+                    DW_OP_addr [gdb_target_symbol pck__fp2_var]
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+
+            fp3_small: DW_TAG_constant {
+                {DW_AT_GNU_numerator   1 DW_FORM_data1}
+                {DW_AT_GNU_denominator 30 DW_FORM_sdata}
+            }
+
+            fp3_base_type: DW_TAG_base_type {
+                {DW_AT_byte_size     1 DW_FORM_sdata}
+                {DW_AT_encoding      @DW_ATE_signed_fixed}
+                {DW_AT_name          pck__fp3_type}
+                {DW_AT_small         :$fp3_small}
+            }
+
+            DW_TAG_variable {
+                {DW_AT_name pck__fp3_var}
+                {DW_AT_type :$fp3_base_type}
+                {DW_AT_location {
+                    DW_OP_addr [gdb_target_symbol pck__fp3_var]
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+
+            fp1_range_type: DW_TAG_subrange_type {
+                 {DW_AT_lower_bound 0xf0 DW_FORM_data1}
+                 {DW_AT_upper_bound 0x10 DW_FORM_data1}
+                 {DW_AT_name foo__fp1_range_type}
+                 {DW_AT_type :$fp1_base_type}
+             }
+
+             DW_TAG_variable {
+                 {DW_AT_name pck__fp1_range_var}
+                 {DW_AT_type :$fp1_range_type}
+                 {DW_AT_location {
+                     DW_OP_addr [gdb_target_symbol pck__fp1_range_var]
+                 } SPECIAL_expr}
+                 {external 1 flag}
+             }
+	}
+    }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+	  [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+# Do the testing in Ada mode, since this is the language for which
+# this feature has been implemented, and where we know the language
+# has the concept of fixed-point types.
+gdb_test_no_output "set lang ada"
+
+gdb_test "print pck.fp1_var" \
+         " = 0.25"
+
+gdb_test "print pck.fp2_var" \
+         " = -0.01"
+
+gdb_test "print pck.fp3_var" \
+         " = 0.1"
+
+gdb_test "print pck.fp1_range_var" \
+         " = 1"
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 2d9d1fb..38ae0bd 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -794,6 +794,31 @@ generic_val_print_float (struct type *type, struct ui_file *stream,
   print_floating (valaddr, type, stream);
 }
 
+/* generic_val_print helper for TYPE_CODE_FIXED_POINT.  */
+
+static void
+generic_val_print_fixed_point (struct value *val, struct ui_file *stream,
+			       const struct value_print_options *options)
+{
+  if (options->format)
+    value_print_scalar_formatted (val, options, 0, stream);
+  else
+    {
+      struct type *type = value_type (val);
+
+      const gdb_byte *valaddr = value_contents_for_printing (val);
+      gdb_mpf f;
+
+      f.read_fixed_point (valaddr, TYPE_LENGTH (type),
+			  type_byte_order (type), type->is_unsigned (),
+			  fixed_point_scaling_factor (type));
+
+      const char *fmt = TYPE_LENGTH (type) < 4 ? "%.11Fg" : "%.17Fg";
+      gdb::unique_xmalloc_ptr<char> str = gmp_string_asprintf (fmt, f.val);
+      fprintf_filtered (stream, "%s", str.get ());
+    }
+}
+
 /* generic_value_print helper for TYPE_CODE_COMPLEX.  */
 
 static void
@@ -844,6 +869,10 @@ generic_value_print (struct value *val, struct ui_file *stream, int recurse,
   struct type *type = value_type (val);
 
   type = check_typedef (type);
+
+  if (is_fixed_point_type (type))
+    type = fixed_point_type_base_type (type);
+
   switch (type->code ())
     {
     case TYPE_CODE_ARRAY:
@@ -909,6 +938,10 @@ generic_value_print (struct value *val, struct ui_file *stream, int recurse,
 	generic_val_print_float (type, stream, val, options);
       break;
 
+    case TYPE_CODE_FIXED_POINT:
+      generic_val_print_fixed_point (val, stream, options);
+      break;
+
     case TYPE_CODE_VOID:
       fputs_filtered (decorations->void_name, stream);
       break;
diff --git a/gdb/value.c b/gdb/value.c
index 7db3d3e..3b207cd 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2758,6 +2758,9 @@ value_as_address (struct value *val)
 LONGEST
 unpack_long (struct type *type, const gdb_byte *valaddr)
 {
+  if (is_fixed_point_type (type))
+    type = fixed_point_type_base_type (type);
+
   enum bfd_endian byte_order = type_byte_order (type);
   enum type_code code = type->code ();
   int len = TYPE_LENGTH (type);
@@ -2806,6 +2809,17 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
     case TYPE_CODE_DECFLOAT:
       return target_float_to_longest (valaddr, type);
 
+    case TYPE_CODE_FIXED_POINT:
+      {
+	gdb_mpq vq;
+	vq.read_fixed_point (valaddr, len, byte_order, nosign,
+			     fixed_point_scaling_factor (type));
+
+	gdb_mpz vz;
+	mpz_tdiv_q (vz.val, mpq_numref (vq.val), mpq_denref (vq.val));
+	return vz.as_integer<LONGEST> ();
+      }
+
     case TYPE_CODE_PTR:
     case TYPE_CODE_REF:
     case TYPE_CODE_RVALUE_REF:
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PATCH 6/9] fix printing of DWARF fixed-point type objects with format modifier
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
                   ` (4 preceding siblings ...)
  2020-11-08  6:30 ` [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects Joel Brobecker
@ 2020-11-08  6:30 ` Joel Brobecker
  2020-11-10 22:50   ` Simon Marchi
  2020-11-08  6:30 ` [PATCH 7/9] Add ptype support for DWARF-based fixed-point types Joel Brobecker
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-08  6:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

Consider a fixed-point type such the scaling factor is 1/16,
as the following Ada code snippet would create:

      type FP1_Type is delta 0.1 range -1.0 .. +1.0;
      FP1_Var : FP1_Type := 0.25;

Printing the value of this variable with a format modifier yields
the wrong value. E.g.:

    (gdb) p /x fp1_var
    $6 = 0x4

Since the real value is 0.25, we therefore expected...

    (gdb) p /x fp1_var
    $6 = 0x0

What happens, in this case, is that the value being printed is
actually the "raw" value of our object, before the scaling factor
gets applied.

This commit fixes the issue by using approach as for float values,
where we convert the value into an integer value, prior to printing,
knowing that the conversion takes the scaling factor into account.

gdb/ChangeLog:

        * printcmd.c (print_scalar_formatted): Add fixed-point type
        handling when options->format is set.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-fixed-point.exp: Add "print /x" tests.
---
 gdb/printcmd.c                               |  3 ++-
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp | 12 ++++++++++++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index f7186c2..6651424 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -421,7 +421,8 @@ print_scalar_formatted (const gdb_byte *valaddr, struct type *type,
      range case, we want to avoid this, so we store the unpacked value
      here for possible use later.  */
   gdb::optional<LONGEST> val_long;
-  if ((type->code () == TYPE_CODE_FLT
+  if (((type->code () == TYPE_CODE_FLT
+	|| is_fixed_point_type (type))
        && (options->format == 'o'
 	   || options->format == 'x'
 	   || options->format == 't'
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
index bf88ffe..27c549c 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
@@ -122,11 +122,23 @@ gdb_test_no_output "set lang ada"
 gdb_test "print pck.fp1_var" \
          " = 0.25"
 
+gdb_test "print /x pck.fp1_var" \
+         " = 0x0"
+
 gdb_test "print pck.fp2_var" \
          " = -0.01"
 
+gdb_test "print /x pck.fp2_var" \
+         " = 0x0"
+
 gdb_test "print pck.fp3_var" \
          " = 0.1"
 
+gdb_test "print /x pck.fp3_var" \
+         " = 0x0"
+
 gdb_test "print pck.fp1_range_var" \
          " = 1"
+
+gdb_test "print /x pck.fp1_range_var" \
+         " = 0x1"
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PATCH 7/9] Add ptype support for DWARF-based fixed-point types
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
                   ` (5 preceding siblings ...)
  2020-11-08  6:30 ` [PATCH 6/9] fix printing of DWARF fixed-point type objects with format modifier Joel Brobecker
@ 2020-11-08  6:30 ` Joel Brobecker
  2020-11-10 23:00   ` Simon Marchi
  2020-11-08  6:30 ` [PATCH 8/9] Add support for fixed-point type arithmetic Joel Brobecker
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-08  6:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

Note that the ptype information printed for types described
via pure DWARF debug info is slightly less informative as
the one printed when the information is encoded in the type's
name, via the GNAT encoding. As a result, the output in
the case of DWARF-described fixed point types is slightly
different. In pratice, this is no real loss because the information
not available in DWARF has no bearing on how the type is actually
stored in memory.

gdb/ChangeLog:

        * ada-typeprint.c (ada_print_type): Add handing of fixed-point
        range types.
        * c-typeprint.c (c_type_print_varspec_prefix)
        (c_type_print_varspec_suffix, c_type_print_base_1): Add
        TYPE_CODE_FIXED_POINT handling.
        * p-typeprint.c (pascal_type_print_varspec_prefix)
        (pascal_type_print_varspec_suffix): Likewise.
        * typeprint.c (print_type_fixed_point): New function.
        * typeprint.h (print_type_fixed_point): Add declaration.

gdb/testsuite/ChangeLog:

        * gdb.ada/fixed_points.exp: Add ptype tests.
        * gdb.dwarf2/dw2-fixed-point.exp: Likewise.
---
 gdb/ada-typeprint.c                          |  6 ++++
 gdb/c-typeprint.c                            |  6 ++++
 gdb/p-typeprint.c                            |  2 ++
 gdb/testsuite/gdb.ada/fixed_points.exp       | 39 ++++++++++++++++++++++++
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp | 44 ++++++++++++++++++++++++++++
 gdb/typeprint.c                              | 13 ++++++++
 gdb/typeprint.h                              |  2 ++
 7 files changed, 112 insertions(+)

diff --git a/gdb/ada-typeprint.c b/gdb/ada-typeprint.c
index 5388247..8abb65b 100644
--- a/gdb/ada-typeprint.c
+++ b/gdb/ada-typeprint.c
@@ -1046,6 +1046,12 @@ ada_print_type (struct type *type0, const char *varstring,
       case TYPE_CODE_RANGE:
 	if (ada_is_gnat_encoded_fixed_point_type (type))
 	  print_gnat_encoded_fixed_point_type (type, stream);
+	else if (is_fixed_point_type (type))
+	  {
+	    fprintf_filtered (stream, "<");
+	    print_type_fixed_point (type, stream);
+	    fprintf_filtered (stream, ">");
+	  }
 	else if (ada_is_modular_type (type))
 	  fprintf_filtered (stream, "mod %s", 
 			    int_string (ada_modulus (type), 10, 0, 0, 1));
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index e72fdaa..10631ff 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -465,6 +465,7 @@ c_type_print_varspec_prefix (struct type *type,
     case TYPE_CODE_COMPLEX:
     case TYPE_CODE_NAMESPACE:
     case TYPE_CODE_DECFLOAT:
+    case TYPE_CODE_FIXED_POINT:
       /* These types need no prefix.  They are listed here so that
 	 gcc -Wall will reveal any types that haven't been handled.  */
       break;
@@ -844,6 +845,7 @@ c_type_print_varspec_suffix (struct type *type,
     case TYPE_CODE_COMPLEX:
     case TYPE_CODE_NAMESPACE:
     case TYPE_CODE_DECFLOAT:
+    case TYPE_CODE_FIXED_POINT:
       /* These types do not need a suffix.  They are listed so that
 	 gcc -Wall will report types that may not have been
 	 considered.  */
@@ -1683,6 +1685,10 @@ c_type_print_base_1 (struct type *type, struct ui_file *stream,
       fprintf_styled (stream, metadata_style.style (), _("<range type>"));
       break;
 
+    case TYPE_CODE_FIXED_POINT:
+      print_type_fixed_point (type, stream);
+      break;
+
     case TYPE_CODE_NAMESPACE:
       fputs_filtered ("namespace ", stream);
       fputs_filtered (type->name (), stream);
diff --git a/gdb/p-typeprint.c b/gdb/p-typeprint.c
index ef0f254..c2c182a 100644
--- a/gdb/p-typeprint.c
+++ b/gdb/p-typeprint.c
@@ -296,6 +296,7 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
     case TYPE_CODE_STRING:
     case TYPE_CODE_COMPLEX:
     case TYPE_CODE_TYPEDEF:
+    case TYPE_CODE_FIXED_POINT:
       /* These types need no prefix.  They are listed here so that
 	 gcc -Wall will reveal any types that haven't been handled.  */
       break;
@@ -429,6 +430,7 @@ pascal_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
     case TYPE_CODE_STRING:
     case TYPE_CODE_COMPLEX:
     case TYPE_CODE_TYPEDEF:
+    case TYPE_CODE_FIXED_POINT:
       /* These types do not need a suffix.  They are listed so that
 	 gcc -Wall will report types that may not have been considered.  */
       break;
diff --git a/gdb/testsuite/gdb.ada/fixed_points.exp b/gdb/testsuite/gdb.ada/fixed_points.exp
index 655ee95..6455d35 100644
--- a/gdb/testsuite/gdb.ada/fixed_points.exp
+++ b/gdb/testsuite/gdb.ada/fixed_points.exp
@@ -55,8 +55,47 @@ gdb_test "ptype Overprecise_Object" \
 gdb_test "print fp1_var" \
          " = 0.25"
 
+set test "ptype fp1_var"
+gdb_test_multiple "$test" $test {
+    -re "type = <1-byte fixed point \\(small = 0\\.0625\\)>\r\n$gdb_prompt $" {
+        pass $test
+    }
+    -re "type = delta 0\\.1 <'small = 0\\.0625>\r\n$gdb_prompt $" {
+        # The (legacy) output we obtain when the compiler described
+        # our fixed point types using the GNAT encodings rather than
+        # standard DWARF.  OK as well.
+        pass $test
+    }
+}
+
 gdb_test "print fp2_var" \
          " = -0.01"
 
+set test "ptype fp2_var"
+gdb_test_multiple "$test" $test {
+    -re "type = <8-byte fixed point \\(small = 0\\.01\\)>\r\n$gdb_prompt $" {
+        pass $test
+    }
+    -re "type = delta 0\\.01\r\n$gdb_prompt $" {
+        # The (legacy) output we obtain when the compiler described
+        # our fixed point types using the GNAT encodings rather than
+        # standard DWARF.  OK as well.
+        pass $test
+    }
+}
+
 gdb_test "print fp3_var" \
          " = 0.1"
+
+set test "ptype fp3_var"
+gdb_test_multiple "$test" $test {
+    -re "type = <1-byte fixed point \\(small = 0\\.0333333\\)>\r\n$gdb_prompt $" {
+        pass $test
+    }
+    -re "type = delta 0\\.1 <'small = 0\\.0333333>\r\n$gdb_prompt $" {
+        # The (legacy) output we obtain when the compiler described
+        # our fixed point types using the GNAT encodings rather than
+        # standard DWARF.  OK as well.
+        pass $test
+    }
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
index 27c549c..2e72bff 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
@@ -142,3 +142,47 @@ gdb_test "print pck.fp1_range_var" \
 
 gdb_test "print /x pck.fp1_range_var" \
          " = 0x1"
+
+# Set the language to LANG and do a ptype test on pck__fp1_var,
+# pck__fp2_var and pck__fp3_var, verifying that the output matches
+# FP1_RE, FP2_RE, FP2_RE (resp.).
+
+proc do_ptype_test {lang fp1_re fp2_re fp3_re fp1_range_re} {
+    with_test_prefix "$lang" {
+        gdb_test_no_output "set language $lang" \
+            "set language to $lang for ptype test"
+
+        gdb_test "ptype pck__fp1_var" $fp1_re
+
+        gdb_test "ptype pck__fp2_var" $fp2_re
+
+        gdb_test "ptype pck__fp3_var" $fp3_re
+
+        if { $lang == "modula-2" || $lang == "pascal" } {
+            setup_xfail "*-*-*" "not supported by language"
+        }
+        gdb_test "ptype pck__fp1_range_var" $fp1_range_re
+    }
+}
+
+do_ptype_test "ada" \
+              " = <1-byte fixed point \\(small = 1/16\\)>" \
+              " = <1-byte fixed point \\(small = 1/100\\)>" \
+              " = <1-byte fixed point \\(small = 1/30\\)>" \
+              " = <1-byte fixed point \\(small = 1/16\\)>"
+
+foreach lang [list "c" "d" "go" "objective-c" "opencl" ] {
+    do_ptype_test $lang \
+                  " = 1-byte fixed point \\(small = 1/16\\)" \
+                  " = 1-byte fixed point \\(small = 1/100\\)" \
+                  " = 1-byte fixed point \\(small = 1/30\\)" \
+                  " = <range type>"
+}
+
+foreach lang [list "fortran" "modula-2" "pascal" ] {
+    do_ptype_test $lang \
+                  " = pck__fp1_type" \
+                  " = pck__fp2_type" \
+                  " = pck__fp3_type" \
+                  " = <range type>"
+}
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index acaee44..6a07b33 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -662,6 +662,19 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream)
     }
 }
 
+/* Assuming the TYPE is a fixed point type, print its type description
+   on STREAM.  */
+
+void
+print_type_fixed_point (struct type *type, struct ui_file *stream)
+{
+  gdb::unique_xmalloc_ptr<char> small_img
+    = fixed_point_scaling_factor (type).str ();
+
+  fprintf_filtered (stream, "%s-byte fixed point (small = %s)",
+		    pulongest (TYPE_LENGTH (type)), small_img.get ());
+}
+
 /* Dump details of a type specified either directly or indirectly.
    Uses the same sort of type lookup mechanism as ptype_command()
    and whatis_command().  */
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index 8936b9a..339c746 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -151,6 +151,8 @@ class typedef_hash_table
 
 void print_type_scalar (struct type * type, LONGEST, struct ui_file *);
 
+void print_type_fixed_point (struct type *type, struct ui_file *stream);
+
 void c_type_print_args (struct type *, struct ui_file *, int, enum language,
 			const struct type_print_options *);
 
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PATCH 8/9] Add support for fixed-point type arithmetic
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
                   ` (6 preceding siblings ...)
  2020-11-08  6:30 ` [PATCH 7/9] Add ptype support for DWARF-based fixed-point types Joel Brobecker
@ 2020-11-08  6:30 ` Joel Brobecker
  2020-11-10 23:18   ` Simon Marchi
  2020-11-08  6:30 ` [PATCH 9/9] Add support for fixed-point type comparison operators Joel Brobecker
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-08  6:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This patch adds support for binary operations on fixed-point values,
as well as for the negative unary operator.

gdb/ChangeLog:

        * eval.c (binop_promote): Add fixed-point type handling.
        * valarith.c (fixed_point_binop): New function.
        (scalar_binop): Add fixed-point type handling.
        (value_neg): Add fixed-point type handling.
        * valops.c (value_cast_to_fixed_point): New function.
        (value_cast): Add fixed-point type handling.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-fixed-point.exp: Add arithmetic tests.
---
 gdb/eval.c                                   |  3 +
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp | 18 ++++++
 gdb/valarith.c                               | 91 +++++++++++++++++++++++++++-
 gdb/valops.c                                 | 74 +++++++++++++++++++++-
 4 files changed, 183 insertions(+), 3 deletions(-)

diff --git a/gdb/eval.c b/gdb/eval.c
index 8d0c574..308f477 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -430,6 +430,9 @@ binop_promote (const struct language_defn *language, struct gdbarch *gdbarch,
 	  && !is_integral_type (type2)))
     return;
 
+  if (is_fixed_point_type (type1) || is_fixed_point_type (type2))
+        return;
+
   if (type1->code () == TYPE_CODE_DECFLOAT
       || type2->code () == TYPE_CODE_DECFLOAT)
     {
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
index 2e72bff..a3c8ff1 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
@@ -143,6 +143,24 @@ gdb_test "print pck.fp1_range_var" \
 gdb_test "print /x pck.fp1_range_var" \
          " = 0x1"
 
+gdb_test "print pck.fp1_var + 0.25" \
+         " = 0.5"
+
+gdb_test "print pck.fp2_var - pck.fp2_var" \
+         " = 0"
+
+gdb_test "print pck.fp3_var * 1" \
+         " = 0.1"
+
+gdb_test "print pck.fp3_var / pck.fp3_var" \
+         " = 1"
+
+gdb_test "print pck.fp1_range_var - 0.5" \
+         " = 0.5"
+
+gdb_test "print -pck.fp1_var" \
+         " = -0.25"
+
 # Set the language to LANG and do a ptype test on pck__fp1_var,
 # pck__fp2_var and pck__fp3_var, verifying that the output matches
 # FP1_RE, FP2_RE, FP2_RE (resp.).
diff --git a/gdb/valarith.c b/gdb/valarith.c
index f6caf3d..65a6f13 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -881,6 +881,84 @@ value_args_as_target_float (struct value *arg1, struct value *arg2,
 	     type2->name ());
 }
 
+/* Assuming at last one of ARG1 or ARG2 is a fixed point value,
+   perform the binary operation OP on these two operands, and return
+   the resulting value (also as a fixed point).  */
+
+static struct value *
+fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
+{
+  struct type *type1 = check_typedef (value_type (arg1));
+  struct type *type2 = check_typedef (value_type (arg2));
+
+  struct value *val;
+
+  gdb_assert (is_fixed_point_type (type1) || is_fixed_point_type (type2));
+  if (!is_fixed_point_type (type1))
+    {
+      arg1 = value_cast (type2, arg1);
+      type1 = type2;
+    }
+  if (!is_fixed_point_type (type2))
+    {
+      arg2 = value_cast (type1, arg2);
+      type2 = type1;
+    }
+
+  gdb_mpq v1, v2, res;
+  v1.read_fixed_point (value_contents (arg1), TYPE_LENGTH (type1),
+		       type_byte_order (type1), type1->is_unsigned (),
+		       fixed_point_scaling_factor (type1));
+  v2.read_fixed_point (value_contents (arg2), TYPE_LENGTH (type2),
+		       type_byte_order (type2), type2->is_unsigned (),
+		       fixed_point_scaling_factor (type2));
+
+#define INIT_VAL_WITH_FIXED_POINT_VAL(RESULT) \
+  do { \
+      val = allocate_value (type1); \
+      (RESULT).write_fixed_point			\
+        (value_contents_raw (val), TYPE_LENGTH (type1), \
+	 type_byte_order (type1), type1->is_unsigned (), \
+	 fixed_point_scaling_factor (type1)); \
+     } while (0)
+
+  switch (op)
+    {
+    case BINOP_ADD:
+      mpq_add (res.val, v1.val, v2.val);
+      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      break;
+
+    case BINOP_SUB:
+      mpq_sub (res.val, v1.val, v2.val);
+      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      break;
+
+    case BINOP_MIN:
+      INIT_VAL_WITH_FIXED_POINT_VAL (mpq_cmp (v1.val, v2.val) < 0 ? v1 : v2);
+      break;
+
+    case BINOP_MAX:
+      INIT_VAL_WITH_FIXED_POINT_VAL (mpq_cmp (v1.val, v2.val) > 0 ? v1 : v2);
+      break;
+
+    case BINOP_MUL:
+      mpq_mul (res.val, v1.val, v2.val);
+      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      break;
+
+    case BINOP_DIV:
+      mpq_div (res.val, v1.val, v2.val);
+      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      break;
+
+    default:
+      error (_("Integer-only operation on fixed point number."));
+    }
+
+  return val;
+}
+
 /* A helper function that finds the type to use for a binary operation
    involving TYPE1 and TYPE2.  */
 
@@ -1054,10 +1132,17 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
       || type2->code () == TYPE_CODE_COMPLEX)
     return complex_binop (arg1, arg2, op);
 
-  if ((!is_floating_value (arg1) && !is_integral_type (type1))
-      || (!is_floating_value (arg2) && !is_integral_type (type2)))
+  if ((!is_floating_value (arg1)
+       && !is_integral_type (type1)
+       && !is_fixed_point_type (type1))
+      || (!is_floating_value (arg2)
+	  && !is_integral_type (type2)
+	  && !is_fixed_point_type (type2)))
     error (_("Argument to arithmetic operation not a number or boolean."));
 
+  if (is_fixed_point_type (type1) || is_fixed_point_type (type2))
+    return fixed_point_binop (arg1, arg2, op);
+
   if (is_floating_type (type1) || is_floating_type (type2))
     {
       result_type = promotion_type (type1, type2);
@@ -1753,6 +1838,8 @@ value_neg (struct value *arg1)
 
   if (is_integral_type (type) || is_floating_type (type))
     return value_binop (value_from_longest (type, 0), arg1, BINOP_SUB);
+  else if (is_fixed_point_type (type))
+    return value_binop (value_zero (type, not_lval), arg1, BINOP_SUB);
   else if (type->code () == TYPE_CODE_ARRAY && type->is_vector ())
     {
       struct value *tmp, *val = allocate_value (type);
diff --git a/gdb/valops.c b/gdb/valops.c
index 4df2538..0f84a70 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -331,6 +331,60 @@ value_cast_pointers (struct type *type, struct value *arg2,
   return arg2;
 }
 
+/* Assuming that TO_TYPE is a fixed point type, return a value
+   corresponding to the cast of FROM_VAL to that type.  */
+
+static struct value *
+value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
+{
+  struct type *from_type = value_type (from_val);
+
+  if (from_type == to_type)
+    return from_val;
+
+  gdb_mpq vq;
+
+  /* Extract the value as a rational number.  */
+
+  if (is_floating_type (from_type))
+    {
+      double d = target_float_to_host_double (value_contents (from_val),
+					      from_type);
+      mpq_set_d (vq.val, d);
+    }
+
+  else if (is_integral_type (from_type) || is_fixed_point_type (from_type))
+    {
+      gdb_mpz vz;
+
+      vz.read (value_contents (from_val), TYPE_LENGTH (from_type),
+	       type_byte_order (from_type), from_type->is_unsigned ());
+      mpq_set_z (vq.val, vz.val);
+
+      if (is_fixed_point_type (from_type))
+	mpq_mul (vq.val, vq.val, fixed_point_scaling_factor (from_type).val);
+    }
+
+  else
+    error (_("Invalid conversion from type %s to fixed point type %s"),
+	   from_type->name (), to_type->name ());
+
+  /* Divide that value by the scaling factor to obtain the unscaled
+     value, first in rational form, and then in integer form.  */
+
+  mpq_div (vq.val, vq.val, fixed_point_scaling_factor (to_type).val);
+  gdb_mpz unscaled = vq.get_rounded ();
+
+  /* Finally, create the result value, and pack the unscaled value
+     in it.  */
+  struct value *result = allocate_value (to_type);
+  unscaled.write (value_contents_raw (result),
+		  TYPE_LENGTH (to_type), type_byte_order (to_type),
+		  to_type->is_unsigned ());
+
+  return result;
+}
+
 /* Cast value ARG2 to type TYPE and return as a value.
    More general than a C cast: accepts any two types of the same length,
    and if ARG2 is an lvalue it can be cast into anything at all.  */
@@ -349,6 +403,9 @@ value_cast (struct type *type, struct value *arg2)
   if (value_type (arg2) == type)
     return arg2;
 
+  if (is_fixed_point_type (type))
+    return value_cast_to_fixed_point (type, arg2);
+
   /* Check if we are casting struct reference to struct reference.  */
   if (TYPE_IS_REFERENCE (check_typedef (type)))
     {
@@ -439,7 +496,8 @@ value_cast (struct type *type, struct value *arg2)
 
   scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT
 	    || code2 == TYPE_CODE_DECFLOAT || code2 == TYPE_CODE_ENUM
-	    || code2 == TYPE_CODE_RANGE);
+	    || code2 == TYPE_CODE_RANGE
+	    || is_fixed_point_type (type2));
 
   if ((code1 == TYPE_CODE_STRUCT || code1 == TYPE_CODE_UNION)
       && (code2 == TYPE_CODE_STRUCT || code2 == TYPE_CODE_UNION)
@@ -460,6 +518,20 @@ value_cast (struct type *type, struct value *arg2)
 				value_contents_raw (v), type);
 	  return v;
 	}
+      else if (is_fixed_point_type (type2))
+	{
+	  gdb_mpq fp_val;
+
+	  fp_val.read_fixed_point
+	    (value_contents (arg2), TYPE_LENGTH (type2),
+	     type_byte_order (type2), type2->is_unsigned (),
+	     fixed_point_scaling_factor (type2));
+
+	  struct value *v = allocate_value (to_type);
+	  target_float_from_host_double (value_contents_raw (v),
+					 to_type, mpq_get_d (fp_val.val));
+	  return v;
+	}
 
       /* The only option left is an integral type.  */
       if (type2->is_unsigned ())
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PATCH 9/9] Add support for fixed-point type comparison operators
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
                   ` (7 preceding siblings ...)
  2020-11-08  6:30 ` [PATCH 8/9] Add support for fixed-point type arithmetic Joel Brobecker
@ 2020-11-08  6:30 ` Joel Brobecker
  2020-11-10 23:21 ` RFA: Add support for DWARF-based fixed point types Simon Marchi
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-08  6:30 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

This patch adds support for binary comparison operators with
fixed-point type values.

gdb/ChangeLog:

        * valarith.c (fixed_point_binop): Add BINOP_EQUAL and BINOP_LESS
        handling.
        (value_less): Add fixed-point handling.

gdb/testsuite/ChangeLog:

        * gdb.ada/fixed_cmp.exp: Add -fgnat-encodings=minimal testing.
        * gdb.dwarf2/dw2-fixed-point.c (pck__fp1_var2): New global.
        (main): Add reference to pck__fp1_var2.
        * gdb.dwarf2/dw2-fixed-point.exp: Add comparison operator testing.
---
 gdb/testsuite/gdb.ada/fixed_cmp.exp          |   2 +-
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c   |   7 ++
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp | 102 +++++++++++++++++++++++++++
 gdb/valarith.c                               |  15 +++-
 4 files changed, 124 insertions(+), 2 deletions(-)

diff --git a/gdb/testsuite/gdb.ada/fixed_cmp.exp b/gdb/testsuite/gdb.ada/fixed_cmp.exp
index 10e2c9a..4b2e89b 100644
--- a/gdb/testsuite/gdb.ada/fixed_cmp.exp
+++ b/gdb/testsuite/gdb.ada/fixed_cmp.exp
@@ -19,7 +19,7 @@ if { [skip_ada_tests] } { return -1 }
 
 standard_ada_testfile fixed
 
-foreach_with_prefix scenario {all} {
+foreach_with_prefix scenario {all minimal} {
     set flags [list debug additional_flags=-fgnat-encodings=$scenario]
 
     if {[gdb_compile_ada "${srcfile}" "${binfile}" executable $flags] != "" } {
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
index d9c811c..971a7a8 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
@@ -23,6 +23,12 @@
 int8_t pck__fp1_var = 4;
 
 /* Simulate an Ada variable declared inside package Pck as follow:
+      type FP1_Type is delta 0.1 range -1.0 .. +1.0;
+      FP1_Var2 : FP1_Type := 0.50;
+   Basically, the same as FP1_Var, but with a different value.  */
+int8_t pck__fp1_var2 = 8;
+
+/* Simulate an Ada variable declared inside package Pck as follow:
       type FP2_Type is delta 0.01 digits 14;
       FP2_Var : FP2_Type := -0.01;  */
 int32_t pck__fp2_var = -1;
@@ -41,6 +47,7 @@ int
 main (void)
 {
   pck__fp1_var++;
+  pck__fp1_var2++;
   pck__fp2_var++;
   pck__fp3_var++;
   pck__fp1_range_var++;
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
index a3c8ff1..cb00ce9 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
@@ -49,6 +49,15 @@ Dwarf::assemble $asm_file {
                 {external 1 flag}
             }
 
+            DW_TAG_variable {
+                {DW_AT_name pck__fp1_var2}
+                {DW_AT_type :$fp1_base_type}
+                {DW_AT_location {
+                    DW_OP_addr [gdb_target_symbol pck__fp1_var2]
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+
             fp2_base_type: DW_TAG_base_type {
                 {DW_AT_byte_size     1 DW_FORM_sdata}
                 {DW_AT_encoding      @DW_ATE_signed_fixed}
@@ -161,6 +170,99 @@ gdb_test "print pck.fp1_range_var - 0.5" \
 gdb_test "print -pck.fp1_var" \
          " = -0.25"
 
+gdb_test "print pck.fp1_var = pck.fp1_var" \
+         " = true"
+
+gdb_test "print pck.fp1_var = pck.fp1_var2" \
+         " = false"
+
+gdb_test "print pck.fp1_var /= pck.fp1_var" \
+         " = false"
+
+gdb_test "print pck.fp1_var /= pck.fp1_var2" \
+         " = true"
+
+gdb_test "print pck.fp1_var < pck.fp1_var" \
+         " = false"
+
+gdb_test "print pck.fp1_var < pck.fp1_var2" \
+         " = true"
+
+gdb_test "print pck.fp1_var <= pck.fp1_var2" \
+         " = true"
+
+gdb_test "print pck.fp1_var <= pck.fp1_var" \
+         " = true"
+
+gdb_test "print pck.fp1_var > pck.fp1_var2" \
+         " = false"
+
+gdb_test "print pck.fp1_var2 > pck.fp1_var" \
+         " = true"
+
+gdb_test "print pck.fp1_var >= pck.fp1_var" \
+         " = true"
+
+gdb_test "print pck.fp1_var >= pck.fp1_var2" \
+         " = false"
+
+# Same as above, but with litterals...
+
+gdb_test "print pck.fp1_var = 0.25" \
+         " = true"
+
+gdb_test "print pck.fp1_var = 0.5" \
+         " = false"
+
+gdb_test "print pck.fp1_var = 1" \
+         " = false"
+
+gdb_test "print pck.fp1_var /= 0.25" \
+         " = false"
+
+gdb_test "print pck.fp1_var /= 0.5" \
+         " = true"
+
+gdb_test "print pck.fp1_var /= 1" \
+         " = true"
+
+gdb_test "print pck.fp1_var < 0.25" \
+         " = false"
+
+gdb_test "print pck.fp1_var <  0.5" \
+         " = true"
+
+gdb_test "print pck.fp1_var <  1" \
+         " = true"
+
+gdb_test "print pck.fp1_var <= 0.25" \
+         " = true"
+
+gdb_test "print pck.fp1_var <= 0.5" \
+         " = true"
+
+gdb_test "print pck.fp1_var <= 1" \
+         " = true"
+
+gdb_test "print pck.fp1_var > 0.25" \
+         " = false"
+
+gdb_test "print pck.fp1_var > 0.5" \
+         " = false"
+
+gdb_test "print pck.fp1_var > 1" \
+         " = false"
+
+gdb_test "print pck.fp1_var >= 0.25" \
+         " = true"
+
+gdb_test "print pck.fp1_var >= 0.5" \
+         " = false"
+
+gdb_test "print pck.fp1_var >= 1" \
+         " = false"
+
+
 # Set the language to LANG and do a ptype test on pck__fp1_var,
 # pck__fp2_var and pck__fp3_var, verifying that the output matches
 # FP1_RE, FP2_RE, FP2_RE (resp.).
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 65a6f13..f4497cd 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -890,7 +890,9 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
 {
   struct type *type1 = check_typedef (value_type (arg1));
   struct type *type2 = check_typedef (value_type (arg2));
+  const struct language_defn *language = current_language;
 
+  struct gdbarch *gdbarch = get_type_arch (type1);
   struct value *val;
 
   gdb_assert (is_fixed_point_type (type1) || is_fixed_point_type (type2));
@@ -952,6 +954,16 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
       INIT_VAL_WITH_FIXED_POINT_VAL (res);
       break;
 
+    case BINOP_EQUAL:
+      val = value_from_ulongest (language_bool_type (language, gdbarch),
+				 mpq_cmp (v1.val, v2.val) == 0 ? 1 : 0);
+      break;
+
+    case BINOP_LESS:
+      val = value_from_ulongest (language_bool_type (language, gdbarch),
+				 mpq_cmp (v1.val, v2.val) < 0 ? 1 : 0);
+      break;
+
     default:
       error (_("Integer-only operation on fixed point number."));
     }
@@ -1774,7 +1786,8 @@ value_less (struct value *arg1, struct value *arg2)
   is_int1 = is_integral_type (type1);
   is_int2 = is_integral_type (type2);
 
-  if (is_int1 && is_int2)
+  if ((is_int1 && is_int2)
+      || (is_fixed_point_type (type1) && is_fixed_point_type (type2)))
     return longest_to_int (value_as_long (value_binop (arg1, arg2,
 						       BINOP_LESS)));
   else if ((is_floating_value (arg1) || is_int1)
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects
  2020-11-08  6:30 ` [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects Joel Brobecker
@ 2020-11-10 20:15   ` Simon Marchi
  2020-11-13  8:12     ` Joel Brobecker
  2020-11-16 16:34   ` Luis Machado
  1 sibling, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-10 20:15 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

On 2020-11-08 1:30 a.m., Joel Brobecker wrote:
> This API was motivated by a number of reasons:
>   - GMP's API does not handle "long long" and "unsigned long long",
>     so using LONGEST and ULONGEST is not straightforward;
>   - Automate the need to initialize GMP objects before use, and
>     clear them when no longer used.
>
> However, this API grew also to help with similar matter such
> as formatting to a string, and also reading/writing fixed-point
> values from byte buffers.
>
> Dedicated unit testing is also added.

Here are some comments.  Most of them are really just suggestions, what you
have looks good to me.  The suggestions can easily be implemented later, so you
don't have to re-do your patch series.

> +extern void _initialize_gmp_utils ();

You can drop "extern".

> +
> +void
> +_initialize_gmp_utils ()
> +{
> +  /* Tell GMP to use GDB's memory management routines.  */
> +  mp_set_memory_functions (xmalloc, xrealloc_for_gmp, xfree_for_gmp);

What you have is fine, but if you prefer you could also use lambda
functions, since they are trivial wrappers:

  /* Tell GMP to use GDB's memory management routines.  */
  mp_set_memory_functions (xmalloc,
			   [] (void *ptr, size_t old_size, size_t new_size)
			   {
			     return xrealloc (ptr, new_size);
			   },
			   [] (void *ptr, size_t size)
			   {
			     return xfree (ptr);
			   });

> +}
> diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
> new file mode 100644
> index 0000000..8a4fbfe
> --- /dev/null
> +++ b/gdb/gmp-utils.h
> @@ -0,0 +1,282 @@
> +/* Miscellaneous routines making it easier to use GMP within GDB's framework.
> +
> +   Copyright (C) 2019-2020 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GMP_UTILS_H
> +#define GMP_UTILS_H
> +
> +#include "defs.h"
> +
> +/* Include <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
> +   access to GMP's various formatting functions.  */
> +#include <stdio.h>
> +#include <stdarg.h>
> +#include <gmp.h>
> +#include "gdbsupport/traits.h"
> +
> +/* Same as gmp_asprintf, but returning a convenient wrapper type.  */
> +
> +gdb::unique_xmalloc_ptr<char> gmp_string_asprintf (const char *fmt, ...);

I don't know how gmp_string_asprintf will be used, but would it make
sense to make it return an std::string?  Does gmp_sprintf support
passing NULL as BUF, so that you could replicate what is done in
string_printf?

> +
> +/* A class to make it easier to use GMP's mpz_t values within GDB.  */
> +
> +struct gdb_mpz
> +{
> +  mpz_t val;

I don't know what's coming in the following patches, but would it work
to make the field private and only use it through methods?  Having it
totally encapsulated would make me more confident that the callers don't
do anything they are not supposed to with it.

There would need to be methods for arithmetic operations that we use
(e.g. mpz_add), but we don't have to add methods for all existing
functions in gmp, just the ones we use.  And I presume we don't use that
many.

> +
> +  /* Constructors.  */
> +  gdb_mpz () { mpz_init (val); }
> +
> +  explicit gdb_mpz (const mpz_t &from_val)
> +  {
> +    mpz_init (val);
> +    mpz_set (val, from_val);
> +  }
> +
> +  gdb_mpz (const gdb_mpz &from)
> +  {
> +    mpz_init (val);
> +    mpz_set (val, from.val);
> +  }
> +
> +  /* Initialize using the given integral value.
> +
> +     The main advantage of this method is that it handles both signed
> +     and unsigned types, with no size restriction.  */
> +  template<typename T, typename = gdb::Requires<std::is_integral<T>>>
> +  explicit gdb_mpz (T src)
> +  {
> +    mpz_init (val);
> +    set (src);
> +  }
> +
> +  explicit gdb_mpz (gdb_mpz &&from)
> +  {
> +    mpz_init (val);
> +    mpz_swap (val, from.val);
> +  }
> +
> +
> +  gdb_mpz &operator= (const gdb_mpz &from)
> +  {
> +    mpz_set (val, from.val);
> +    return *this;
> +  }
> +
> +  gdb_mpz &operator== (gdb_mpz &&other)
> +  {
> +    mpz_swap (val, other.val);
> +    return *this;
> +  }

Is this meant to be "operator="?

> +
> +  template<typename T, typename = gdb::Requires<std::is_integral<T>>>
> +  gdb_mpz &operator= (T src)
> +  {
> +    set (src);
> +    return *this;
> +  }
> +
> +  /* Convert VAL to an integer of the given type.
> +
> +     The return type can signed or unsigned, with no size restriction.  */
> +  template<typename T> T as_integer () const;
> +
> +  /* Set VAL by importing the number stored in the byte buffer (BUF),
> +     given its size (LEN) and BYTE_ORDER.
> +
> +     UNSIGNED_P indicates whether the number has an unsigned type.  */
> +  void read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
> +	     bool unsigned_p);
> +
> +  /* Write VAL into BUF as a LEN-bytes number with the given BYTE_ORDER.
> +
> +     UNSIGNED_P indicates whether the number has an unsigned type.  */
> +  void write (gdb_byte *buf, int len, enum bfd_endian byte_order,
> +	      bool unsigned_p) const;

These two would be good candidates for gdb::array_view.

> +
> +  /* Return a string containing VAL.  */
> +  gdb::unique_xmalloc_ptr<char> str () const
> +  { return gmp_string_asprintf ("%Zd", val); }
> +
> +  /* The destructor.  */
> +  ~gdb_mpz () { mpz_clear (val); }
> +
> +private:
> +
> +  /* Helper template for constructor and operator=.  */
> +  template<typename T> void set (T src);
> +};
> +
> +/* A class to make it easier to use GMP's mpq_t values within GDB.  */
> +
> +struct gdb_mpq
> +{
> +  mpq_t val;
> +
> +  /* Constructors.  */
> +  gdb_mpq () { mpq_init (val); }
> +
> +  explicit gdb_mpq (const mpq_t &from_val)
> +  {
> +    mpq_init (val);
> +    mpq_set (val, from_val);
> +  }
> +
> +  gdb_mpq (const gdb_mpq &from)
> +  {
> +    mpq_init (val);
> +    mpq_set (val, from.val);
> +  }
> +
> +  explicit gdb_mpq (gdb_mpq &&from)
> +  {
> +    mpq_init (val);
> +    mpq_swap (val, from.val);
> +  }
> +
> +  /* Copy assignment operator.  */
> +  gdb_mpq &operator= (const gdb_mpq &from)
> +  {
> +    mpq_set (val, from.val);
> +    return *this;
> +  }
> +
> +  gdb_mpq &operator= (gdb_mpq &&from)
> +  {
> +    mpq_swap (val, from.val);
> +    return *this;
> +  }
> +
> +  /* Return a string representing VAL as "<numerator> / <denominator>".  */
> +  gdb::unique_xmalloc_ptr<char> str () const
> +  { return gmp_string_asprintf ("%Qd", val); }
> +
> +  /* Return VAL rounded to the nearest integer.  */
> +  gdb_mpz get_rounded () const;
> +
> +  /* Set VAL from the contents of the given buffer (BUF), which
> +     contains the unscaled value of a fixed point type object
> +     with the given size (LEN) and byte order (BYTE_ORDER).
> +
> +     UNSIGNED_P indicates whether the number has an unsigned type.
> +     SCALING_FACTOR is the scaling factor to apply after having
> +     read the unscaled value from our buffer.  */
> +  void read_fixed_point (const gdb_byte *buf, int len,
> +			 enum bfd_endian byte_order, bool unsigned_p,
> +			 const gdb_mpq &scaling_factor);
> +
> +  /* Write VAL into BUF as a LEN-bytes fixed point value following
> +     the given BYTE_ORDER.
> +
> +     UNSIGNED_P indicates whether the number has an unsigned type.
> +     SCALING_FACTOR is the scaling factor to apply before writing
> +     the unscaled value to our buffer.  */
> +  void write_fixed_point (gdb_byte *buf, int len,
> +			  enum bfd_endian byte_order, bool unsigned_p,
> +			  const gdb_mpq &scaling_factor) const;
> +
> +  /* The destructor.  */
> +  ~gdb_mpq () { mpq_clear (val); }
> +};
> +
> +/* A class to make it easier to use GMP's mpz_t values within GDB.

mpz_t -> mpf_t

> +extern void _initialize_gmp_utils_selftests ();

You can drop "extern".

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects
  2020-11-08  6:30 ` [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects Joel Brobecker
@ 2020-11-10 21:06   ` Simon Marchi
  2020-11-14 10:48     ` Joel Brobecker
                       ` (2 more replies)
  0 siblings, 3 replies; 140+ messages in thread
From: Simon Marchi @ 2020-11-10 21:06 UTC (permalink / raw)
  To: Joel Brobecker, GDB patches

[Sorry Joel, I failed to reply-all, so I am sending it again including
 gdb-patches]

I did not do an in-depth review of the functionality, because I don't
have that much time right now (and coming from AdaCore I trust that it's
quite well tested), so the comments are mostly coding-style related.

> This commit introduces a new kind of type, meant to describe
> fixed-point types, using a new code added specifically for
> this purpose (TYPE_CODE_FIXED_POINT).
>
> It then adds handling of fixed-point base types in the DWARF reader.
>
> And finally, as a first step, this commit adds support for printing
> the value of fixed-point type objects.
>
> Note that this commit has a known issue: Trying to print the value
> of a fixed-point object with a format letter (e.g. "print /x NAME")
> causes the wrong value to be printed because the scaling factor
> is not applied. Since the fix for this issue is isolated, and
> this is not a regression, the fix will be made in a pach of its own.
> This is meant to simplify review and archeology.
>
> Also, other functionalities related to fixed-point type handling
> (ptype, arithmetics, etc), will be added piecemeal as well, for
> the same reasons (faciliate reviews and archeology). Related to this,
> the testcase gdb.ada/fixed_cmp.exp is adjusted to compile the test
> program with -fgnat-encodings=all, so as to force the use of GNAT
> encodings, rather than rely on the compiler's default to use them.
> The intent is to enhance this testcase to also test the pure DWARF
> approach using -fgnat-encodings=minimal as soon as the corresponding
> suport gets added in. Thus, the modification to the testcase is made
> in a way that it prepares this testcase to be tested in both modes.

Since it's an easy change to do, I'd suggest to change NULL for nullptr
in all the new code.  Also, declare variable on first use when possible.

> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> index dbf0a3e..1f5152d 100644
> --- a/gdb/dwarf2/read.c
> +++ b/gdb/dwarf2/read.c
> @@ -18130,6 +18130,157 @@ read_typedef (struct die_info *die, struct dwarf2_cu *cu)
>    return this_type;
>  }
>
> +/* Assuming DIE is a rational DW_TAG_constant, read the DIE's
> +   numerator and denominator into NUMERATOR and DENOMINATOR (resp).
> +
> +   If the numerator and/or numerator attribute is missing,
> +   a complaint is filed, and NUMERATOR and DENOMINATOR are left
> +   untouched.  */
> +
> +static void
> +get_dwarf2_rational_constant (struct die_info *die, struct dwarf2_cu *cu,
> +			      LONGEST *numerator, LONGEST *denominator)
> +{
> +  struct attribute *num_attr, *denom_attr;
> +
> +  num_attr = dwarf2_attr (die, DW_AT_GNU_numerator, cu);
> +  if (num_attr == NULL)
> +    complaint (_("DW_AT_GNU_numerator missing in %s DIE at %s"),
> +	       dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
> +
> +  denom_attr = dwarf2_attr (die, DW_AT_GNU_denominator, cu);
> +  if (denom_attr == NULL)
> +    complaint (_("DW_AT_GNU_denominator missing in %s DIE at %s"),
> +	       dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
> +
> +  if (num_attr == NULL || denom_attr == NULL)
> +    return;
> +
> +  *numerator = num_attr->constant_value (1);
> +  *denominator = denom_attr->constant_value (1);
> +}
> +
> +/* Same as get_dwarf2_rational_constant, but extracting an unsigned
> +   rational constant, rather than a signed one.
> +
> +   If the rational constant is has a negative value, a complaint

"is has"

> +   is filed, and NUMERATOR and DENOMINATOR are left untouched.  */
> +
> +static void
> +get_dwarf2_unsigned_rational_constant (struct die_info *die,
> +				       struct dwarf2_cu *cu,
> +				       ULONGEST *numerator,
> +				       ULONGEST *denominator)
> +{
> +  LONGEST num = 1, denom = 1;
> +
> +  get_dwarf2_rational_constant (die, cu, &num, &denom);
> +  if (num < 0 && denom < 0)
> +    {
> +      num = -num;
> +      denom = -denom;
> +    }
> +  else if (num < 0)
> +    {
> +      complaint (_("unexpected negative value for DW_AT_GNU_numerator"
> +		   " in DIE at %s"),
> +		 sect_offset_str (die->sect_off));
> +      return;
> +    }
> +  else if (denom < 0)
> +    {
> +      complaint (_("unexpected negative value for DW_AT_GNU_denominator"
> +		   " in DIE at %s"),
> +		 sect_offset_str (die->sect_off));
> +      return;
> +    }
> +
> +  *numerator = num;
> +  *denominator = denom;
> +}
> +
> +/* Assiuming DIE corresponds to a fixed point type, finish the creation

"Assiuming"

> +   of the corresponding TYPE by setting its TYPE_FIXED_POINT_INFO.
> +   CU is the DIE's CU.  */
> +
> +static void
> +finish_fixed_point_type (struct type *type, struct die_info *die,
> +			 struct dwarf2_cu *cu)

Unless there's a good reason not to (coming up in the following
patches), I would make this function create the "struct type", instead
of having the caller create it and pass it.  In other words, this
signature:

struct type *create_fixed_point_type (die_info *die, dwarf2_cu *cu)

That just makes it more obvious that it's a simple "die" to "type"
transform.

> +{
> +  struct attribute *attr;
> +  /* Numerator and denominator of our fixed-point type's scaling factor.
> +     The default is a scaling factor of 1, which we use as a fallback
> +     when we are not able to decode it (problem with the debugging info,
> +     unsupported forms, bug in GDB, etc...).  Using that as the default
> +     allows us to at least print the unscaled value, which might still
> +     be useful to a user.  */
> +  ULONGEST scale_num = 1;
> +  ULONGEST scale_denom = 1;
> +
> +  gdb_assert (type->code () == TYPE_CODE_FIXED_POINT
> +	      && TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_FIXED_POINT);
> +
> +  attr = dwarf2_attr (die, DW_AT_binary_scale, cu);
> +  if (!attr)
> +    attr = dwarf2_attr (die, DW_AT_decimal_scale, cu);
> +  if (!attr)
> +    attr = dwarf2_attr (die, DW_AT_small, cu);
> +
> +  if (attr == NULL)
> +    {
> +      /* Scaling factor not found.  Assume a scaling factor of 1,
> +	 and hope for the best.  At least the user will be able to see
> +	 the encoded value.  */
> +      complaint (_("no scale found for fixed-point type (DIE at %s)"),
> +		 sect_offset_str (die->sect_off));
> +    }
> +  else if (attr->name == DW_AT_binary_scale)
> +    {
> +      LONGEST scale_exp = attr->constant_value (0);
> +      ULONGEST *num_or_denom = scale_exp > 0 ? &scale_num : &scale_denom;
> +
> +      *num_or_denom = 1 << abs (scale_exp);
> +    }
> +  else if (attr->name == DW_AT_decimal_scale)
> +    {
> +      LONGEST scale_exp = attr->constant_value (0);
> +      ULONGEST *num_or_denom = scale_exp > 0 ? &scale_num : &scale_denom;
> +
> +      *num_or_denom = uinteger_pow (10, abs (scale_exp));
> +    }
> +  else if (attr->name == DW_AT_small)
> +    {
> +      struct die_info *scale_die;
> +      struct dwarf2_cu *scale_cu = cu;
> +
> +      scale_die = follow_die_ref (die, attr, &scale_cu);
> +      if (scale_die->tag == DW_TAG_constant)
> +	get_dwarf2_unsigned_rational_constant (scale_die, scale_cu,
> +					       &scale_num, &scale_denom);
> +      else
> +	complaint (_("%s DIE not supported as target of DW_AT_small attribute"
> +		     " (DIE at %s)"),
> +		   dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
> +    }
> +  else
> +    {
> +      complaint (("unsupported scale attribute %s for fixed-point type"
> +		   " (DIE at %s)"),

Missing _()?  Also, the second line has one space too much.

> @@ -1821,6 +1845,9 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
>    (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits == NULL ? 0 \
>      : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index)))
>
> +#define TYPE_FIXED_POINT_INFO(thistype) \
> +  (TYPE_MAIN_TYPE(thistype)->type_specific.fixed_point_info)

Do you think you can make this macro a method on struct type in the
style of the ones that were added recently?  It will be one less macro
to convert later :).  That method should contain an assert that the type
code is indeed TYPE_CODE_FIXED_POINT.  I think it could return a
`fixed_point_info &`, since there's no way it can fail and need to
return nullptr (now I see that type::bounds should probably return a
`range_bounds &` instead of a `range_bounds *`).

> +
>  #define FIELD_NAME(thisfld) ((thisfld).name)
>  #define FIELD_LOC_KIND(thisfld) ((thisfld).loc_kind)
>  #define FIELD_BITPOS_LVAL(thisfld) ((thisfld).loc.bitpos)
> @@ -2192,6 +2219,8 @@ extern struct type *init_decfloat_type (struct objfile *, int, const char *);
>  extern struct type *init_complex_type (const char *, struct type *);
>  extern struct type *init_pointer_type (struct objfile *, int, const char *,
>  				       struct type *);
> +extern struct type *init_fixed_point_type (struct objfile *, int, int,
> +					   const char *);
>
>  /* Helper functions to construct architecture-owned types.  */
>  extern struct type *arch_type (struct gdbarch *, enum type_code, int,
> @@ -2529,6 +2558,26 @@ extern int type_not_allocated (const struct type *type);
>
>  extern int type_not_associated (const struct type *type);
>
> +/* Return True if TYPE is a TYPE_CODE_FIXED_POINT or if TYPE is
> +   range whose base type is a TYPE_CODE_FIXED_POINT.  */
> +extern int is_fixed_point_type (struct type *type);

int -> bool

> +
> +/* Assuming that TYPE is a fixed point type, return its base type.
> +
> +   In other words, this returns the type after having peeled all
> +   intermediate type layers (such as TYPE_CODE_RANGE, for instance).
> +   The TYPE_CODE of the type returned is guaranteed to be
> +   a TYPE_CODE_FIXED_POINT.  */
> +extern struct type *fixed_point_type_base_type (struct type *type);

I think it would make sense to make this a `struct type` method.

> +
> +/* Given TYPE, which is a fixed point type, return its scaling factor.  */
> +extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);

I think this would belong in fixed_point_type_info, so you'd access it
using:

  type->fixed_point_info ().scaling_factor ()

> diff --git a/gdb/testsuite/gdb.ada/fixed_cmp.exp b/gdb/testsuite/gdb.ada/fixed_cmp.exp
> index 38e41c4..10e2c9a 100644
> --- a/gdb/testsuite/gdb.ada/fixed_cmp.exp
> +++ b/gdb/testsuite/gdb.ada/fixed_cmp.exp
> @@ -19,25 +19,29 @@ if { [skip_ada_tests] } { return -1 }
>
>  standard_ada_testfile fixed
>
> -if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug ]] != "" } {
> -  return -1
> -}
> +foreach_with_prefix scenario {all} {

I suggest naming this variable gnat-encodings, just because the
resulting test name will be a bit clearer.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 6/9] fix printing of DWARF fixed-point type objects with format modifier
  2020-11-08  6:30 ` [PATCH 6/9] fix printing of DWARF fixed-point type objects with format modifier Joel Brobecker
@ 2020-11-10 22:50   ` Simon Marchi
  0 siblings, 0 replies; 140+ messages in thread
From: Simon Marchi @ 2020-11-10 22:50 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

On 2020-11-08 1:30 a.m., Joel Brobecker wrote:
> Consider a fixed-point type such the scaling factor is 1/16,
> as the following Ada code snippet would create:
>
>       type FP1_Type is delta 0.1 range -1.0 .. +1.0;
>       FP1_Var : FP1_Type := 0.25;
>
> Printing the value of this variable with a format modifier yields
> the wrong value. E.g.:
>
>     (gdb) p /x fp1_var
>     $6 = 0x4
>
> Since the real value is 0.25, we therefore expected...
>
>     (gdb) p /x fp1_var
>     $6 = 0x0

I find this behavior a bit strange and I wonder when this is useful.
Intuitively, I would think that /x would give me the underlying
representation, in hex, I think it is more likely to be useful.

But I see that this is how floating points work:

(gdb) ptype f
type = float
(gdb) p f
$1 = 1.23000002
(gdb) p/x f
$2 = 0x1

... so it makes sense to have the same behavior for fixed points.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 7/9] Add ptype support for DWARF-based fixed-point types
  2020-11-08  6:30 ` [PATCH 7/9] Add ptype support for DWARF-based fixed-point types Joel Brobecker
@ 2020-11-10 23:00   ` Simon Marchi
  2020-11-15  6:57     ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-10 23:00 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

On 2020-11-08 1:30 a.m., Joel Brobecker wrote:
> diff --git a/gdb/testsuite/gdb.ada/fixed_points.exp b/gdb/testsuite/gdb.ada/fixed_points.exp
> index 655ee95..6455d35 100644
> --- a/gdb/testsuite/gdb.ada/fixed_points.exp
> +++ b/gdb/testsuite/gdb.ada/fixed_points.exp
> @@ -55,8 +55,47 @@ gdb_test "ptype Overprecise_Object" \
>  gdb_test "print fp1_var" \
>           " = 0.25"
>
> +set test "ptype fp1_var"
> +gdb_test_multiple "$test" $test {
> +    -re "type = <1-byte fixed point \\(small = 0\\.0625\\)>\r\n$gdb_prompt $" {
> +        pass $test
> +    }
> +    -re "type = delta 0\\.1 <'small = 0\\.0625>\r\n$gdb_prompt $" {
> +        # The (legacy) output we obtain when the compiler described
> +        # our fixed point types using the GNAT encodings rather than
> +        # standard DWARF.  OK as well.
> +        pass $test
> +    }
> +}

Instead of setting a "test" variable, you can use $gdb_test_name inside
gdb_test_multiple.

> diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
> index 27c549c..2e72bff 100644
> --- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
> +++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
> @@ -142,3 +142,47 @@ gdb_test "print pck.fp1_range_var" \
>
>  gdb_test "print /x pck.fp1_range_var" \
>           " = 0x1"
> +
> +# Set the language to LANG and do a ptype test on pck__fp1_var,
> +# pck__fp2_var and pck__fp3_var, verifying that the output matches
> +# FP1_RE, FP2_RE, FP2_RE (resp.).
> +
> +proc do_ptype_test {lang fp1_re fp2_re fp3_re fp1_range_re} {
> +    with_test_prefix "$lang" {

Suggest using

  with_test_prefix "lang=$lang"

> +        gdb_test_no_output "set language $lang" \
> +            "set language to $lang for ptype test"
> +
> +        gdb_test "ptype pck__fp1_var" $fp1_re
> +
> +        gdb_test "ptype pck__fp2_var" $fp2_re
> +
> +        gdb_test "ptype pck__fp3_var" $fp3_re
> +
> +        if { $lang == "modula-2" || $lang == "pascal" } {
> +            setup_xfail "*-*-*" "not supported by language"
> +        }

Can you give more details about this?  What prevents these languages
from printing <range type>?  I'm confused, because as far as I can tell
C doesn't support range types more than these two languages, and it's
able to print <range type>.

> diff --git a/gdb/typeprint.h b/gdb/typeprint.h
> index 8936b9a..339c746 100644
> --- a/gdb/typeprint.h
> +++ b/gdb/typeprint.h
> @@ -151,6 +151,8 @@ class typedef_hash_table
>
>  void print_type_scalar (struct type * type, LONGEST, struct ui_file *);
>
> +void print_type_fixed_point (struct type *type, struct ui_file *stream);

For new code, IWBN to follow the standard of putting the doc in the
header file, even though the other functions in that file don't follow
it.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 8/9] Add support for fixed-point type arithmetic
  2020-11-08  6:30 ` [PATCH 8/9] Add support for fixed-point type arithmetic Joel Brobecker
@ 2020-11-10 23:18   ` Simon Marchi
  0 siblings, 0 replies; 140+ messages in thread
From: Simon Marchi @ 2020-11-10 23:18 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

On 2020-11-08 1:30 a.m., Joel Brobecker wrote:
> diff --git a/gdb/valarith.c b/gdb/valarith.c
> index f6caf3d..65a6f13 100644
> --- a/gdb/valarith.c
> +++ b/gdb/valarith.c
> @@ -881,6 +881,84 @@ value_args_as_target_float (struct value *arg1, struct value *arg2,
>  	     type2->name ());
>  }
>
> +/* Assuming at last one of ARG1 or ARG2 is a fixed point value,
> +   perform the binary operation OP on these two operands, and return
> +   the resulting value (also as a fixed point).  */
> +
> +static struct value *
> +fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
> +{
> +  struct type *type1 = check_typedef (value_type (arg1));
> +  struct type *type2 = check_typedef (value_type (arg2));
> +
> +  struct value *val;
> +
> +  gdb_assert (is_fixed_point_type (type1) || is_fixed_point_type (type2));
> +  if (!is_fixed_point_type (type1))
> +    {
> +      arg1 = value_cast (type2, arg1);
> +      type1 = type2;
> +    }
> +  if (!is_fixed_point_type (type2))
> +    {
> +      arg2 = value_cast (type1, arg2);
> +      type2 = type1;
> +    }
> +
> +  gdb_mpq v1, v2, res;
> +  v1.read_fixed_point (value_contents (arg1), TYPE_LENGTH (type1),
> +		       type_byte_order (type1), type1->is_unsigned (),
> +		       fixed_point_scaling_factor (type1));
> +  v2.read_fixed_point (value_contents (arg2), TYPE_LENGTH (type2),
> +		       type_byte_order (type2), type2->is_unsigned (),
> +		       fixed_point_scaling_factor (type2));
> +
> +#define INIT_VAL_WITH_FIXED_POINT_VAL(RESULT) \
> +  do { \
> +      val = allocate_value (type1); \
> +      (RESULT).write_fixed_point			\
> +        (value_contents_raw (val), TYPE_LENGTH (type1), \
> +	 type_byte_order (type1), type1->is_unsigned (), \
> +	 fixed_point_scaling_factor (type1)); \
> +     } while (0)

Can you use a lambda function instead of a macro?  It's easier to
debug and edit.  Something like

  auto fixed_point_to_value = [type1] (const gdb_mpq &fp)
    {
      value *val_ = allocate_value (type1);

      fp.write_fixed_point (value_contents_raw (val_),
			    TYPE_LENGTH (type1),
			    type_byte_order (type1),
			    type1->is_unsigned (),
			    fixed_point_scaling_factor (type1));

      return val_;
    };

and

  val = fixed_point_to_value (res);

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: RFA: Add support for DWARF-based fixed point types
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
                   ` (8 preceding siblings ...)
  2020-11-08  6:30 ` [PATCH 9/9] Add support for fixed-point type comparison operators Joel Brobecker
@ 2020-11-10 23:21 ` Simon Marchi
  2020-11-11  4:53   ` Joel Brobecker
  2020-11-15  8:35 ` pushed: " Joel Brobecker
  2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
  11 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-10 23:21 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

On 2020-11-08 1:30 a.m., Joel Brobecker wrote:
> Hello,
>
> This patch series adds support for fixed point types described
> using a pure DWARF approach. While the main trigger was the desire
> to deprecate the GNAT encodings used in the case of Ada fixed point
> types, the implementation is done in a way that support is generic.
> Other languages which have support for such kinds of types should
> have little work to do to support them as well.
>
> The implementation is based on top of GMP: We use GMP to store and
> operate on rational values, with the added bonus that there is no
> size limit on either the numerator nor denominator. As discussed
> previously, the dependency on GMP is made mandatory
> (https://sourceware.org/pipermail/gdb-patches/2018-March/147373.html).
>
> One part that this patch series does not include is function calls
> and returns. Since those changes are all arch-specific, I will
> submit them in a separate series of its own, to avoid those other
> patches getting lost in this patch series.
>
> Each patch of this series has been tested on x86_64-linux using
> our testsuite. In addition, these changes have been tested using
> AdaCore's testing, on numerous architectures and OSes.
>
> Looking forward to everyone's feedback!

Hi Joel,

I gave some comments that are more on the coding style side of things,
since I am that that familiar with fixed point types.  In general it
seemed to make sense.  I'm fine with you merging this series, addressing
the comments as you see fit.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: RFA: Add support for DWARF-based fixed point types
  2020-11-10 23:21 ` RFA: Add support for DWARF-based fixed point types Simon Marchi
@ 2020-11-11  4:53   ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-11  4:53 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

Hi Simon,

> I gave some comments that are more on the coding style side of things,
> since I am that that familiar with fixed point types.  In general it
> seemed to make sense.  I'm fine with you merging this series, addressing
> the comments as you see fit.

Thanks a lot for the review!

I read through the comments, and from what I could see, I agree with
them all. I'll try to have a new version of the series over the weekend.

Thanks again!
-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects
  2020-11-10 20:15   ` Simon Marchi
@ 2020-11-13  8:12     ` Joel Brobecker
  2020-11-13 15:04       ` Tom Tromey
  0 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-13  8:12 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches, Tom Tromey

[-- Attachment #1: Type: text/plain, Size: 4222 bytes --]

Hi Simon,

[copying Tom as well, as he helped me a lot with the C++ part
when designing this API]

> Here are some comments.  Most of them are really just suggestions,
> what you have looks good to me.  The suggestions can easily be
> implemented later, so you don't have to re-do your patch series.

Thanks for your thorough review.

I took a bit of time today to look at your comments, and work on them.
I'll fold the trivial changes in v2 of the patch. For the more impactful
changes, I'll make them separate patches at the end of the patch series.
Hopefully that'll simplify the review process both for the existing
patch as well as the proposed changes.

> > +/* Same as gmp_asprintf, but returning a convenient wrapper type.  */
> > +
> > +gdb::unique_xmalloc_ptr<char> gmp_string_asprintf (const char *fmt, ...);
> 
> I don't know how gmp_string_asprintf will be used, but would it make
> sense to make it return an std::string?  Does gmp_sprintf support
> passing NULL as BUF, so that you could replicate what is done in
> string_printf?

I can't remember the exact details behind the choice of using
a unique_xmalloc_ptr, but I think it was to avoid having an extra
malloc/free when going from the memory allocated by gmp_vasprintf
to the data returned to caller.

I don't think this function is expected to be called that often,
so it sounds worth the trouble making the API more C++-y.
I've attached a copy of the patch that does that as "0001-[...]".

> > +/* A class to make it easier to use GMP's mpz_t values within GDB.  */
> > +
> > +struct gdb_mpz
> > +{
> > +  mpz_t val;
> 
> I don't know what's coming in the following patches, but would it work
> to make the field private and only use it through methods?  Having it
> totally encapsulated would make me more confident that the callers don't
> do anything they are not supposed to with it.
> 
> There would need to be methods for arithmetic operations that we use
> (e.g. mpz_add), but we don't have to add methods for all existing
> functions in gmp, just the ones we use.  And I presume we don't use that
> many.

I'm not sure about that. The main purpose of these classes is to automate
the lifetime of the data allocated when creating the underlying GMP objects.
Beyond that, there are a few help routines that are connected as methods
because it makes sense to do so now that we have the classes, but could
have otherwise been just regular functions.

I am not opposed to the idea of making the GMP objects private,
but I don't really see enough benefits...

> > +  gdb_mpz &operator== (gdb_mpz &&other)
> > +  {
> > +    mpz_swap (val, other.val);
> > +    return *this;
> > +  }
> 
> Is this meant to be "operator="?

Nice catch! I think so, and I'll fix if Tom confirms as well.

> > +  /* Set VAL by importing the number stored in the byte buffer (BUF),
> > +     given its size (LEN) and BYTE_ORDER.
> > +
> > +     UNSIGNED_P indicates whether the number has an unsigned type.  */
> > +  void read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
> > +	     bool unsigned_p);
> > +
> > +  /* Write VAL into BUF as a LEN-bytes number with the given BYTE_ORDER.
> > +
> > +     UNSIGNED_P indicates whether the number has an unsigned type.  */
> > +  void write (gdb_byte *buf, int len, enum bfd_endian byte_order,
> > +	      bool unsigned_p) const;
> 
> These two would be good candidates for gdb::array_view.

If we change these, I think it would make sense to change the
read_fixed_point/write_fixed_point duo as well.

I'm on the fence about this suggestion. Attached is the patch
implementing it. On the plus side, the API is more idiomatic-C++.
One the down side, it very so slightly increases the complexity
of both the implementation and the current callers. It's because
the rest of the infrastructure is still structured in a way that
what we have access to are pointers and sizes. Perhaps one could
say that, even though the point of call is currently a bit more
work, it does help convey the idea that the "len" is the len of
the buffer.

I don't have a strong opinion either way, so I'm happy to follow
what people think. The patch will be included in v2 of the patch
series, and I'm happy to keep or drop.

-- 
Joel

[-- Attachment #2: 0001-change-gmp_string_asprintf-to-return-an-std-string.patch --]
[-- Type: text/x-diff, Size: 4582 bytes --]

From 6f2bf2c0dc375788b739921f74e1b6da73bf78ec Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Fri, 13 Nov 2020 02:49:06 -0500
Subject: [PATCH 1/2] change gmp_string_asprintf to return an std::string

This was suggested by Simon during a code review of this package upstream.
The upside is that this makes the function's API more natural and C++.
The downside is an extra malloc, which might be the reason why we went
for using a unique_xmalloc_ptr in the first place. Since this function
is not expected to be called frequently, the API improvement might be
worth the performance impact.

gdb/ChangeLog:

        * gmp-utils.h (gmp_string_asprintf): Change return type to
        std::string. Update all callers.
        * gmp-utils.c (gmp_string_asprintf): Likewise.

Change-Id: I49c21053c595583d2110ba2a730e3eeb8e38155d
TN: NB04-020
---
 gdb/gdbtypes.c  |  2 +-
 gdb/gmp-utils.c |  6 ++++--
 gdb/gmp-utils.h | 10 ++++------
 gdb/typeprint.c |  5 ++---
 gdb/valprint.c  |  4 ++--
 5 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index a3a6f07..58c4bc4 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -4922,7 +4922,7 @@ static void
 print_fixed_point_type_info (struct type *type, int spaces)
 {
   printfi_filtered (spaces + 2, "scaling factor: %s\n",
-		    fixed_point_scaling_factor (type).str ().get ());
+		    fixed_point_scaling_factor (type).str ().c_str ());
 }
 
 static struct obstack dont_print_type_obstack;
diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index db92e57..b70aaa3 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -19,7 +19,7 @@
 
 /* See gmp-utils.h.  */
 
-gdb::unique_xmalloc_ptr<char>
+std::string
 gmp_string_asprintf (const char *fmt, ...)
 {
   va_list vp;
@@ -29,7 +29,9 @@ gmp_string_asprintf (const char *fmt, ...)
   gmp_vasprintf (&buf, fmt, vp);
   va_end (vp);
 
-  return gdb::unique_xmalloc_ptr<char> (buf);
+  std::string result(buf);
+  xfree (buf);
+  return result;
 }
 
 /* See gmp-utils.h.  */
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index 1214b64..7eed29a 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -29,9 +29,9 @@
 #include <gmp.h>
 #include "gdbsupport/traits.h"
 
-/* Same as gmp_asprintf, but returning a convenient wrapper type.  */
+/* Same as gmp_asprintf, but returning an std::string.  */
 
-gdb::unique_xmalloc_ptr<char> gmp_string_asprintf (const char *fmt, ...);
+std::string gmp_string_asprintf (const char *fmt, ...);
 
 /* A class to make it easier to use GMP's mpz_t values within GDB.  */
 
@@ -110,8 +110,7 @@ struct gdb_mpz
 	      bool unsigned_p) const;
 
   /* Return a string containing VAL.  */
-  gdb::unique_xmalloc_ptr<char> str () const
-  { return gmp_string_asprintf ("%Zd", val); }
+  std::string str () const { return gmp_string_asprintf ("%Zd", val); }
 
   /* The destructor.  */
   ~gdb_mpz () { mpz_clear (val); }
@@ -163,8 +162,7 @@ struct gdb_mpq
   }
 
   /* Return a string representing VAL as "<numerator> / <denominator>".  */
-  gdb::unique_xmalloc_ptr<char> str () const
-  { return gmp_string_asprintf ("%Qd", val); }
+  std::string str () const { return gmp_string_asprintf ("%Qd", val); }
 
   /* Return VAL rounded to the nearest integer.  */
   gdb_mpz get_rounded () const;
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 6a07b33..6eedb5d 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -668,11 +668,10 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream)
 void
 print_type_fixed_point (struct type *type, struct ui_file *stream)
 {
-  gdb::unique_xmalloc_ptr<char> small_img
-    = fixed_point_scaling_factor (type).str ();
+  std::string small_img = fixed_point_scaling_factor (type).str ();
 
   fprintf_filtered (stream, "%s-byte fixed point (small = %s)",
-		    pulongest (TYPE_LENGTH (type)), small_img.get ());
+		    pulongest (TYPE_LENGTH (type)), small_img.c_str ());
 }
 
 /* Dump details of a type specified either directly or indirectly.
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 38ae0bd..abef002 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -814,8 +814,8 @@ generic_val_print_fixed_point (struct value *val, struct ui_file *stream,
 			  fixed_point_scaling_factor (type));
 
       const char *fmt = TYPE_LENGTH (type) < 4 ? "%.11Fg" : "%.17Fg";
-      gdb::unique_xmalloc_ptr<char> str = gmp_string_asprintf (fmt, f.val);
-      fprintf_filtered (stream, "%s", str.get ());
+      std::string str = gmp_string_asprintf (fmt, f.val);
+      fprintf_filtered (stream, "%s", str.c_str ());
     }
 }
 
-- 
2.1.4


[-- Attachment #3: 0002-gmp-utils-Convert-the-read-write-methods-to-using-gd.patch --]
[-- Type: text/x-diff, Size: 14455 bytes --]

From 3260f64e727e699ce98a02a0a3fe9859c41ab059 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Fri, 13 Nov 2020 02:17:15 -0500
Subject: [PATCH 2/2] gmp-utils: Convert the read/write methods to using
 gdb::array_view

This commit changes the interfaces of some of the methods declared
in gmp-utils to take a gdb::array_view of gdb_byte instead of a
(gdb_byte *, size) couple.

This makes these methods' API probably more C++-idiomatic.
With the way things are structured, this change introduces a minor
extra complication at the point of call of these methods, since
the data available there is not in the form of an array_view,
and thus the array_view needs to be constructed on the spot.

        * gmp-utils.h (gdb_mpz::read): Change buf and len parameters
        into one single gdb::array_view parameter.
        (gdb_mpz::write): Likewise.
        (gdb_mpq::read_fixed_point, gdb_mpq::write_fixed_point): Likewise.
        * gmp-utils.c (gdb_mpz::read): Change buf and len parameters
        into one single gdb::array_view parameter.
        Adjust implementation accordingly.
        (gdb_mpz::write): Likewise.
        (gdb_mpq::read_fixed_point, gdb_mpq::write_fixed_point): Likewise.
        * unittests/gmp-utils-selftests.c: Adapt following changes above.
        * valarith.c, valops.c, valprint.c, value.c: Likewise.

Change-Id: Ia6e9f077def06b92e089684164066fc81fff5e29
---
 gdb/gmp-utils.c                     | 25 +++++++++++++------------
 gdb/gmp-utils.h                     | 32 ++++++++++++++++++--------------
 gdb/unittests/gmp-utils-selftests.c | 12 ++++++++----
 gdb/valarith.c                      |  9 ++++++---
 gdb/valops.c                        | 11 +++++++----
 gdb/valprint.c                      |  3 ++-
 gdb/value.c                         |  3 ++-
 7 files changed, 56 insertions(+), 39 deletions(-)

diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index b70aaa3..6d80f13 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -37,12 +37,12 @@ gmp_string_asprintf (const char *fmt, ...)
 /* See gmp-utils.h.  */
 
 void
-gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+gdb_mpz::read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
 	       bool unsigned_p)
 {
-  mpz_import (val, 1 /* count */, -1 /* order */, len /* size */,
+  mpz_import (val, 1 /* count */, -1 /* order */, buf.size () /* size */,
 	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
-	      0 /* nails */, buf /* op */);
+	      0 /* nails */, buf.data () /* op */);
 
   if (!unsigned_p)
     {
@@ -51,7 +51,7 @@ gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
 	 was in fact negative, we need to adjust VAL accordingly.  */
       gdb_mpz max;
 
-      mpz_ui_pow_ui (max.val, 2, len * TARGET_CHAR_BIT - 1);
+      mpz_ui_pow_ui (max.val, 2, buf.size () * TARGET_CHAR_BIT - 1);
       if (mpz_cmp (val, max.val) >= 0)
 	mpz_submul_ui (val, max.val, 2);
     }
@@ -60,7 +60,7 @@ gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
 /* See gmp-utils.h.  */
 
 void
-gdb_mpz::write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
 		bool unsigned_p) const
 {
   gdb_mpz exported_val (val);
@@ -72,14 +72,15 @@ gdb_mpz::write (gdb_byte *buf, int len, enum bfd_endian byte_order,
 	 would be the same as our negative value.  */
       gdb_mpz neg_offset;
 
-      mpz_ui_pow_ui (neg_offset.val, 2, len * TARGET_CHAR_BIT);
+      mpz_ui_pow_ui (neg_offset.val, 2, buf.size () * TARGET_CHAR_BIT);
       mpz_add (exported_val.val, exported_val.val, neg_offset.val);
     }
 
   /* Start by clearing the buffer, as mpz_export only writes as many
      bytes as it needs (including none, if the value to export is zero.  */
-  memset (buf, 0, len);
-  mpz_export (buf, NULL /* count */, -1 /* order */, len /* size */,
+  memset (buf.data (), 0, buf.size ());
+  mpz_export (buf.data (), NULL /* count */, -1 /* order */,
+	      buf.size () /* size */,
 	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
 	      0 /* nails */, exported_val.val);
 }
@@ -120,12 +121,12 @@ gdb_mpq::get_rounded () const
 /* See gmp-utils.h.  */
 
 void
-gdb_mpq::read_fixed_point (const gdb_byte *buf, int len,
+gdb_mpq::read_fixed_point (gdb::array_view<const gdb_byte> buf,
 			   enum bfd_endian byte_order, bool unsigned_p,
 			   const gdb_mpq &scaling_factor)
 {
   gdb_mpz vz;
-  vz.read (buf, len, byte_order, unsigned_p);
+  vz.read (buf, byte_order, unsigned_p);
 
   mpq_set_z (val, vz.val);
   mpq_mul (val, val, scaling_factor.val);
@@ -134,7 +135,7 @@ gdb_mpq::read_fixed_point (const gdb_byte *buf, int len,
 /* See gmp-utils.h.  */
 
 void
-gdb_mpq::write_fixed_point (gdb_byte *buf, int len,
+gdb_mpq::write_fixed_point (gdb::array_view<gdb_byte> buf,
 			    enum bfd_endian byte_order, bool unsigned_p,
 			    const gdb_mpq &scaling_factor) const
 {
@@ -143,7 +144,7 @@ gdb_mpq::write_fixed_point (gdb_byte *buf, int len,
   mpq_div (unscaled.val, unscaled.val, scaling_factor.val);
 
   gdb_mpz unscaled_z = unscaled.get_rounded ();
-  unscaled_z.write (buf, len, byte_order, unsigned_p);
+  unscaled_z.write (buf, byte_order, unsigned_p);
 }
 
 /* A wrapper around xrealloc that we can then register with GMP
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index 7eed29a..ac6bb0d 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -96,17 +96,19 @@ struct gdb_mpz
      The return type can signed or unsigned, with no size restriction.  */
   template<typename T> T as_integer () const;
 
-  /* Set VAL by importing the number stored in the byte buffer (BUF),
-     given its size (LEN) and BYTE_ORDER.
+  /* Set VAL by importing the number stored in the byte array (BUF),
+     using the given BYTE_ORDER.  The size of the data to read is
+     the byte array's size.
 
      UNSIGNED_P indicates whether the number has an unsigned type.  */
-  void read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+  void read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
 	     bool unsigned_p);
 
-  /* Write VAL into BUF as a LEN-bytes number with the given BYTE_ORDER.
+  /* Write VAL into BUF as a number whose byte size is the size of BUF,
+     using the given BYTE_ORDER.
 
      UNSIGNED_P indicates whether the number has an unsigned type.  */
-  void write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+  void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
 	      bool unsigned_p) const;
 
   /* Return a string containing VAL.  */
@@ -167,24 +169,26 @@ struct gdb_mpq
   /* Return VAL rounded to the nearest integer.  */
   gdb_mpz get_rounded () const;
 
-  /* Set VAL from the contents of the given buffer (BUF), which
-     contains the unscaled value of a fixed point type object
-     with the given size (LEN) and byte order (BYTE_ORDER).
+  /* Set VAL from the contents of the given byte array (BUF), which
+     contains the unscaled value of a fixed point type object.
+     The byte size of the data is the size of BUF.
+
+     BYTE_ORDER provides the byte_order to use when reading the data.
 
      UNSIGNED_P indicates whether the number has an unsigned type.
      SCALING_FACTOR is the scaling factor to apply after having
      read the unscaled value from our buffer.  */
-  void read_fixed_point (const gdb_byte *buf, int len,
+  void read_fixed_point (gdb::array_view<const gdb_byte> buf,
 			 enum bfd_endian byte_order, bool unsigned_p,
 			 const gdb_mpq &scaling_factor);
 
-  /* Write VAL into BUF as a LEN-bytes fixed point value following
-     the given BYTE_ORDER.
+  /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
+     The size of BUF is used as the length to write the value into.
 
      UNSIGNED_P indicates whether the number has an unsigned type.
      SCALING_FACTOR is the scaling factor to apply before writing
      the unscaled value to our buffer.  */
-  void write_fixed_point (gdb_byte *buf, int len,
+  void write_fixed_point (gdb::array_view<gdb_byte> buf,
 			  enum bfd_endian byte_order, bool unsigned_p,
 			  const gdb_mpq &scaling_factor) const;
 
@@ -213,13 +217,13 @@ struct gdb_mpf
      UNSIGNED_P indicates whether the number has an unsigned type.
      SCALING_FACTOR is the scaling factor to apply after having
      read the unscaled value from our buffer.  */
-  void read_fixed_point (const gdb_byte *buf, int len,
+  void read_fixed_point (gdb::array_view<const gdb_byte> buf,
 			 enum bfd_endian byte_order, bool unsigned_p,
 			 const gdb_mpq &scaling_factor)
   {
     gdb_mpq tmp_q;
 
-    tmp_q.read_fixed_point (buf, len, byte_order, unsigned_p, scaling_factor);
+    tmp_q.read_fixed_point (buf, byte_order, unsigned_p, scaling_factor);
     mpf_set_q (val, tmp_q.val);
   }
 
diff --git a/gdb/unittests/gmp-utils-selftests.c b/gdb/unittests/gmp-utils-selftests.c
index b5738eb..ccd7f01 100644
--- a/gdb/unittests/gmp-utils-selftests.c
+++ b/gdb/unittests/gmp-utils-selftests.c
@@ -109,7 +109,8 @@ store_and_read_back (T val, int buf_len, enum bfd_endian byte_order,
   mpz_set (actual.val, expected.val);
   mpz_sub_ui (actual.val, actual.val, 500);
 
-  actual.read (buf, buf_len, byte_order, !std::is_signed<T>::value);
+  actual.read (gdb::array_view<const gdb_byte> (buf, buf_len),
+	       byte_order, !std::is_signed<T>::value);
 }
 
 /* Test the gdb_mpz::read method over a reasonable range of values.
@@ -234,7 +235,8 @@ write_and_extract (T val, int buf_len, enum bfd_endian byte_order)
   SELF_CHECK (v.as_integer<T> () == val);
 
   gdb_byte *buf = (gdb_byte *) alloca (buf_len);
-  v.write (buf, buf_len, byte_order, !std::is_signed<T>::value);
+  v.write (gdb::array_view<gdb_byte> (buf, buf_len),
+	   byte_order, !std::is_signed<T>::value);
 
   return extract_integer<T> (buf, buf_len, byte_order);
 }
@@ -333,7 +335,8 @@ read_fp_test (int unscaled, const gdb_mpq &scaling_factor,
   gdb_byte buf[len];
   store_signed_integer (buf, len, byte_order, unscaled);
 
-  actual.read_fixed_point (buf, len, byte_order, 0, scaling_factor);
+  actual.read_fixed_point (gdb::array_view<const gdb_byte> (buf, len),
+			   byte_order, 0, scaling_factor);
 
   mpq_set_si (expected.val, unscaled, 1);
   mpq_mul (expected.val, expected.val, scaling_factor.val);
@@ -402,7 +405,8 @@ write_fp_test (int numerator, unsigned int denominator,
   gdb_mpq v;
   mpq_set_ui (v.val, numerator, denominator);
   mpq_canonicalize (v.val);
-  v.write_fixed_point (buf, len, byte_order, 0, scaling_factor);
+  v.write_fixed_point (gdb::array_view<gdb_byte> (buf, len),
+		       byte_order, 0, scaling_factor);
 
   return extract_unsigned_integer (buf, len, byte_order);
 }
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 0e38aed..7d406b1 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -939,10 +939,12 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
     }
 
   gdb_mpq v1, v2, res;
-  v1.read_fixed_point (value_contents (arg1), TYPE_LENGTH (type1),
+  v1.read_fixed_point (gdb::array_view <const gdb_byte> (value_contents (arg1),
+							 TYPE_LENGTH (type1)),
 		       type_byte_order (type1), type1->is_unsigned (),
 		       fixed_point_scaling_factor (type1));
-  v2.read_fixed_point (value_contents (arg2), TYPE_LENGTH (type2),
+  v2.read_fixed_point (gdb::array_view <const gdb_byte> (value_contents (arg2),
+							 TYPE_LENGTH (type2)),
 		       type_byte_order (type2), type2->is_unsigned (),
 		       fixed_point_scaling_factor (type2));
 
@@ -950,7 +952,8 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   do { \
       val = allocate_value (type1); \
       (RESULT).write_fixed_point			\
-        (value_contents_raw (val), TYPE_LENGTH (type1), \
+        (gdb::array_view <gdb_byte> (value_contents_raw (val), \
+				     TYPE_LENGTH (type1)), \
 	 type_byte_order (type1), type1->is_unsigned (), \
 	 fixed_point_scaling_factor (type1)); \
      } while (0)
diff --git a/gdb/valops.c b/gdb/valops.c
index d63f233..b0b1209 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -357,7 +357,8 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
     {
       gdb_mpz vz;
 
-      vz.read (value_contents (from_val), TYPE_LENGTH (from_type),
+      vz.read (gdb::array_view<const gdb_byte> (value_contents (from_val),
+						TYPE_LENGTH (from_type)),
 	       type_byte_order (from_type), from_type->is_unsigned ());
       mpq_set_z (vq.val, vz.val);
 
@@ -378,8 +379,9 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
   /* Finally, create the result value, and pack the unscaled value
      in it.  */
   struct value *result = allocate_value (to_type);
-  unscaled.write (value_contents_raw (result),
-		  TYPE_LENGTH (to_type), type_byte_order (to_type),
+  unscaled.write (gdb::array_view<gdb_byte> (value_contents_raw (result),
+					     TYPE_LENGTH (to_type)),
+		  type_byte_order (to_type),
 		  to_type->is_unsigned ());
 
   return result;
@@ -523,7 +525,8 @@ value_cast (struct type *type, struct value *arg2)
 	  gdb_mpq fp_val;
 
 	  fp_val.read_fixed_point
-	    (value_contents (arg2), TYPE_LENGTH (type2),
+	    (gdb::array_view<const gdb_byte> (value_contents (arg2),
+					      TYPE_LENGTH (type2)),
 	     type_byte_order (type2), type2->is_unsigned (),
 	     fixed_point_scaling_factor (type2));
 
diff --git a/gdb/valprint.c b/gdb/valprint.c
index abef002..21a4bf4 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -809,7 +809,8 @@ generic_val_print_fixed_point (struct value *val, struct ui_file *stream,
       const gdb_byte *valaddr = value_contents_for_printing (val);
       gdb_mpf f;
 
-      f.read_fixed_point (valaddr, TYPE_LENGTH (type),
+      f.read_fixed_point (gdb::array_view<const gdb_byte> (valaddr,
+							   TYPE_LENGTH (type)),
 			  type_byte_order (type), type->is_unsigned (),
 			  fixed_point_scaling_factor (type));
 
diff --git a/gdb/value.c b/gdb/value.c
index 3b207cd..bff4afc 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2812,7 +2812,8 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
     case TYPE_CODE_FIXED_POINT:
       {
 	gdb_mpq vq;
-	vq.read_fixed_point (valaddr, len, byte_order, nosign,
+	vq.read_fixed_point (gdb::array_view<const gdb_byte> (valaddr, len),
+			     byte_order, nosign,
 			     fixed_point_scaling_factor (type));
 
 	gdb_mpz vz;
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects
  2020-11-13  8:12     ` Joel Brobecker
@ 2020-11-13 15:04       ` Tom Tromey
  2020-11-13 15:06         ` Simon Marchi
  2020-11-16 16:18         ` Tom Tromey
  0 siblings, 2 replies; 140+ messages in thread
From: Tom Tromey @ 2020-11-13 15:04 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Simon Marchi, gdb-patches, Tom Tromey

>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:

>> There would need to be methods for arithmetic operations that we use
>> (e.g. mpz_add), but we don't have to add methods for all existing
>> functions in gmp, just the ones we use.  And I presume we don't use that
>> many.

Joel> I'm not sure about that. The main purpose of these classes is to automate
Joel> the lifetime of the data allocated when creating the underlying GMP objects.
Joel> Beyond that, there are a few help routines that are connected as methods
Joel> because it makes sense to do so now that we have the classes, but could
Joel> have otherwise been just regular functions.

I tend to think we should just leave it for now.  My main reason is that
the patches already exist & are tested in this form; and there are
follow-up patches to post as well.  And, it's taken quite a long while
to find the necessary time to prep these for submission.

Also perhaps instead of updating these we should reconsider using the
c++ classes that come with gmp.  See gmpxx.h or
(info "(gmp) C++ Class Interface")
(I'm don't recall why these weren't used, maybe it's the caveat in the
manual.  However I think we can probably deal with that ok.)

Anyway, I'm happy to do either of these as follow-ups after landing.
Unlike prepping the patches, this kind of work can readily be done in
spare moments.

Let me know if this plan is alright with you.

>> Is this meant to be "operator="?

Joel> Nice catch! I think so, and I'll fix if Tom confirms as well.

Yeah, oops.

Tom

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects
  2020-11-13 15:04       ` Tom Tromey
@ 2020-11-13 15:06         ` Simon Marchi
  2020-11-16 16:18         ` Tom Tromey
  1 sibling, 0 replies; 140+ messages in thread
From: Simon Marchi @ 2020-11-13 15:06 UTC (permalink / raw)
  To: Tom Tromey, Joel Brobecker; +Cc: gdb-patches

On 2020-11-13 10:04 a.m., Tom Tromey wrote:
> Let me know if this plan is alright with you.

This is fine with me.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects
  2020-11-10 21:06   ` Simon Marchi
@ 2020-11-14 10:48     ` Joel Brobecker
  2020-11-14 13:20       ` Simon Marchi
  2020-11-14 11:30     ` Joel Brobecker
  2020-11-15  6:33     ` Joel Brobecker
  2 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-14 10:48 UTC (permalink / raw)
  To: Simon Marchi; +Cc: GDB patches

[-- Attachment #1: Type: text/plain, Size: 1941 bytes --]

Hi Simon,

> > +   of the corresponding TYPE by setting its TYPE_FIXED_POINT_INFO.
> > +   CU is the DIE's CU.  */
> > +
> > +static void
> > +finish_fixed_point_type (struct type *type, struct die_info *die,
> > +			 struct dwarf2_cu *cu)
> 
> Unless there's a good reason not to (coming up in the following
> patches), I would make this function create the "struct type", instead
> of having the caller create it and pass it.  In other words, this
> signature:
> 
> struct type *create_fixed_point_type (die_info *die, dwarf2_cu *cu)
> 
> That just makes it more obvious that it's a simple "die" to "type"
> transform.

While implementing this suggestion, I'm realizing that doing so
requires either:

(1) Recomputing the following information for the CU: encoding,
    bitsize if any, and type name, which means:

        | attr = dwarf2_attr (die, DW_AT_encoding, cu);
        | if (attr != nullptr && attr->form_is_constant ())
        |   encoding = attr->constant_value (0);
        | attr = dwarf2_attr (die, DW_AT_byte_size, cu);
        | if (attr != nullptr)
        |   bits = attr->constant_value (0) * TARGET_CHAR_BIT;
        | name = dwarf2_name (die, cu);
        | if (!name)
        |   complaint (_("DW_AT_name missing from DW_TAG_base_type"));

    Or:

(2) Passing that information as arguments to the function.

I find option (1) really sad because of the code duplication.
And I find option (2) somewhat unsatisfactory, because we then
run the risk of passing inconsistent information.

This might explain partly why the init + finish approach isn't
new in this unit...

I'm attaching the patch which shows how option (1) looks like.
For me, the current approach strikes a better balance between
API cleanliness and implementation considerations. But I don't
have a strong opinion against implementing what you suggest,
including through option (2) (or other options I missed).

Let me know what you think.

-- 
Joel

[-- Attachment #2: 0001-make-finish_fixed_point_type-create-the-type-renamin.patch --]
[-- Type: text/x-diff, Size: 2750 bytes --]

From 2e76b9ca55aa93189d22d649c8698ab8d572ed7a Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Sat, 14 Nov 2020 05:43:33 -0500
Subject: [PATCH] make finish_fixed_point_type create the type (renaming it
 accordingly)

Change-Id: Ic1b81f5e8328617627675a609ede8320edd749c0
---
 gdb/dwarf2/read.c | 34 ++++++++++++++++++++++++----------
 1 file changed, 24 insertions(+), 10 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 4a447d4..6ba24b3 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -18221,14 +18221,17 @@ get_dwarf2_unsigned_rational_constant (struct die_info *die,
    of the corresponding TYPE by setting its TYPE_FIXED_POINT_INFO.
    CU is the DIE's CU.  */
 
-static void
-finish_fixed_point_type (struct type *type, struct die_info *die,
-			 struct dwarf2_cu *cu)
+static struct type *
+read_fixed_point_type (struct die_info *die, struct dwarf2_cu *cu)
 {
   struct attribute *attr;
+  int encoding = 0;
 
-  gdb_assert (type->code () == TYPE_CODE_FIXED_POINT
-	      && TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_FIXED_POINT);
+  attr = dwarf2_attr (die, DW_AT_encoding, cu);
+  if (attr != nullptr && attr->form_is_constant ())
+    encoding = attr->constant_value (0);
+  gdb_assert (encoding == DW_ATE_signed_fixed
+	      || encoding == DW_ATE_unsigned_fixed);
 
   attr = dwarf2_attr (die, DW_AT_binary_scale, cu);
   if (!attr)
@@ -18289,10 +18292,25 @@ finish_fixed_point_type (struct type *type, struct die_info *die,
 		 sect_offset_str (die->sect_off));
     }
 
+  int bits = 0;
+
+  attr = dwarf2_attr (die, DW_AT_byte_size, cu);
+  if (attr != nullptr)
+    bits = attr->constant_value (0) * TARGET_CHAR_BIT;
+  const char *name = dwarf2_name (die, cu);
+  if (!name)
+    complaint (_("DW_AT_name missing from DW_TAG_base_type"));
+
+  struct type *type = init_fixed_point_type
+    (cu->per_objfile->objfile, bits, encoding == DW_ATE_unsigned_fixed,
+     name);
+
   gdb_mpq &scaling_factor = TYPE_FIXED_POINT_INFO (type)->scaling_factor;
   mpz_set (mpq_numref (scaling_factor.val), scale_num.val);
   mpz_set (mpq_denref (scaling_factor.val), scale_denom.val);
   mpq_canonicalize (scaling_factor.val);
+
+  return type;
 }
 
 /* Allocate a floating-point type of size BITS and name NAME.  Pass NAME_HINT
@@ -18574,12 +18592,8 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
 	}
 	break;
       case DW_ATE_signed_fixed:
-	type = init_fixed_point_type (objfile, bits, 0, name);
-	finish_fixed_point_type (type, die, cu);
-	break;
       case DW_ATE_unsigned_fixed:
-	type = init_fixed_point_type (objfile, bits, 1, name);
-	finish_fixed_point_type (type, die, cu);
+	type = read_fixed_point_type (die, cu);
 	break;
 
       default:
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects
  2020-11-10 21:06   ` Simon Marchi
  2020-11-14 10:48     ` Joel Brobecker
@ 2020-11-14 11:30     ` Joel Brobecker
  2020-11-14 16:14       ` Simon Marchi
  2020-11-15  6:33     ` Joel Brobecker
  2 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-14 11:30 UTC (permalink / raw)
  To: Simon Marchi; +Cc: GDB patches

[-- Attachment #1: Type: text/plain, Size: 1087 bytes --]

Hi again, Simon,

> > @@ -1821,6 +1845,9 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
> >    (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits == NULL ? 0 \
> >      : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index)))
> >
> > +#define TYPE_FIXED_POINT_INFO(thistype) \
> > +  (TYPE_MAIN_TYPE(thistype)->type_specific.fixed_point_info)
> 
> Do you think you can make this macro a method on struct type in the
> style of the ones that were added recently?  It will be one less macro
> to convert later :).  That method should contain an assert that the type
> code is indeed TYPE_CODE_FIXED_POINT.  I think it could return a
> `fixed_point_info &`, since there's no way it can fail and need to
> return nullptr (now I see that type::bounds should probably return a
> `range_bounds &` instead of a `range_bounds *`).

Can you tell me if the attached patch corresponds to what you had
in mind? As the revlog suggests, it's missing a bit of doc around it,
but I wanted to make sure I did this correctly before adding the forms.

Thank you,
-- 
Joel

[-- Attachment #2: 0001-WIP-convert-TYPE_FIXED_POINT_INFO-to-methods-of-stru.patch --]
[-- Type: text/x-diff, Size: 5574 bytes --]

From ad39478edc5d344414ab1ebd5f1eccc13de5a0ce Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Sat, 14 Nov 2020 06:27:25 -0500
Subject: [PATCH] WIP: convert TYPE_FIXED_POINT_INFO to methods of struct type

FIXME: Add proper revision log.

Change-Id: I4259542cc084775648accd135a70829b8ac09615
FIXME: Document the new methods.
---
 gdb/dwarf2/read.c |  4 ++--
 gdb/gdbtypes.c    | 16 ++++++++--------
 gdb/gdbtypes.h    | 23 +++++++++++++++++------
 3 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 4a447d4..248f59b 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -18218,7 +18218,7 @@ get_dwarf2_unsigned_rational_constant (struct die_info *die,
 }
 
 /* Assuming DIE corresponds to a fixed point type, finish the creation
-   of the corresponding TYPE by setting its TYPE_FIXED_POINT_INFO.
+   of the corresponding TYPE by setting its type-specific data.
    CU is the DIE's CU.  */
 
 static void
@@ -18289,7 +18289,7 @@ finish_fixed_point_type (struct type *type, struct die_info *die,
 		 sect_offset_str (die->sect_off));
     }
 
-  gdb_mpq &scaling_factor = TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+  gdb_mpq &scaling_factor = type->fixed_point_info ().scaling_factor;
   mpz_set (mpq_numref (scaling_factor.val), scale_num.val);
   mpz_set (mpq_denref (scaling_factor.val), scale_denom.val);
   mpq_canonicalize (scaling_factor.val);
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 2f92887..7d6e22d 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -5498,8 +5498,8 @@ copy_type_recursive (struct objfile *objfile,
       break;
     case TYPE_SPECIFIC_FIXED_POINT:
       INIT_FIXED_POINT_SPECIFIC (new_type);
-      TYPE_FIXED_POINT_INFO (new_type)->scaling_factor
-	= TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+      new_type->fixed_point_info ().scaling_factor
+	= type->fixed_point_info ().scaling_factor;
       break;
     case TYPE_SPECIFIC_INT:
       TYPE_SPECIFIC_FIELD (new_type) = TYPE_SPECIFIC_INT;
@@ -5821,11 +5821,11 @@ static const struct objfile_key<fixed_point_type_storage>
 
 /* See gdbtypes.h.  */
 
-fixed_point_type_info *
+void
 allocate_fixed_point_type_info (struct type *type)
 {
   std::unique_ptr<fixed_point_type_info> up (new fixed_point_type_info);
-  fixed_point_type_info *result;
+  fixed_point_type_info *info;
 
   if (TYPE_OBJFILE_OWNED (type))
     {
@@ -5833,17 +5833,17 @@ allocate_fixed_point_type_info (struct type *type)
 	= fixed_point_objfile_key.get (TYPE_OBJFILE (type));
       if (storage == nullptr)
 	storage = fixed_point_objfile_key.emplace (TYPE_OBJFILE (type));
-      result = up.get ();
+      info = up.get ();
       storage->push_back (std::move (up));
     }
   else
     {
       /* We just leak the memory, because that's what we do generally
 	 for non-objfile-attached types.  */
-      result = up.release ();
+      info = up.release ();
     }
 
-  return result;
+  type->set_fixed_point_info (info);
 }
 
 /* See gdbtypes.h.  */
@@ -5878,7 +5878,7 @@ fixed_point_scaling_factor (struct type *type)
 {
   type = fixed_point_type_base_type (type);
 
-  return TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+  return type->fixed_point_info ().scaling_factor;
 }
 
 \f
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 9cf847b..375a516 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1216,6 +1216,21 @@ struct type
     this->main_type->m_flag_endianity_not_default = endianity_is_not_default;
   }
 
+  struct fixed_point_type_info &fixed_point_info () const
+  {
+    gdb_assert (this->code () == TYPE_CODE_FIXED_POINT
+		&& this->main_type->type_specific.fixed_point_info != nullptr);
+
+    return *this->main_type->type_specific.fixed_point_info;
+  }
+
+  void set_fixed_point_info (struct fixed_point_type_info *info) const
+  {
+    gdb_assert (this->code () == TYPE_CODE_FIXED_POINT);
+
+    this->main_type->type_specific.fixed_point_info = info;
+  }
+
   /* * Return the dynamic property of the requested KIND from this type's
      list of dynamic properties.  */
   dynamic_prop *dyn_prop (dynamic_prop_node_kind kind) const;
@@ -1769,7 +1784,7 @@ extern void allocate_gnat_aux_type (struct type *);
    handled.  */
 #define INIT_FIXED_POINT_SPECIFIC(type) \
   (TYPE_SPECIFIC_FIELD (type) = TYPE_SPECIFIC_FIXED_POINT, \
-   TYPE_FIXED_POINT_INFO (type) = allocate_fixed_point_type_info (type))
+   allocate_fixed_point_type_info (type))
 
 #define TYPE_MAIN_TYPE(thistype) (thistype)->main_type
 #define TYPE_TARGET_TYPE(thistype) TYPE_MAIN_TYPE(thistype)->target_type
@@ -1867,9 +1882,6 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
   (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits == NULL ? 0 \
     : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index)))
 
-#define TYPE_FIXED_POINT_INFO(thistype) \
-  (TYPE_MAIN_TYPE(thistype)->type_specific.fixed_point_info)
-
 #define FIELD_NAME(thisfld) ((thisfld).name)
 #define FIELD_LOC_KIND(thisfld) ((thisfld).loc_kind)
 #define FIELD_BITPOS_LVAL(thisfld) ((thisfld).loc.bitpos)
@@ -2597,8 +2609,7 @@ extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);
 
 /* Allocate a fixed-point type info for TYPE.  This should only be
    called by INIT_FIXED_POINT_SPECIFIC.  */
-extern fixed_point_type_info *allocate_fixed_point_type_info
-  (struct type *type);
+extern void allocate_fixed_point_type_info (struct type *type);
 
 /* * When the type includes explicit byte ordering, return that.
    Otherwise, the byte ordering from gdbarch_byte_order for 
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects
  2020-11-14 10:48     ` Joel Brobecker
@ 2020-11-14 13:20       ` Simon Marchi
  0 siblings, 0 replies; 140+ messages in thread
From: Simon Marchi @ 2020-11-14 13:20 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: GDB patches

On 2020-11-14 5:48 a.m., Joel Brobecker wrote:
> Hi Simon,
> 
>>> +   of the corresponding TYPE by setting its TYPE_FIXED_POINT_INFO.
>>> +   CU is the DIE's CU.  */
>>> +
>>> +static void
>>> +finish_fixed_point_type (struct type *type, struct die_info *die,
>>> +			 struct dwarf2_cu *cu)
>>
>> Unless there's a good reason not to (coming up in the following
>> patches), I would make this function create the "struct type", instead
>> of having the caller create it and pass it.  In other words, this
>> signature:
>>
>> struct type *create_fixed_point_type (die_info *die, dwarf2_cu *cu)
>>
>> That just makes it more obvious that it's a simple "die" to "type"
>> transform.
> 
> While implementing this suggestion, I'm realizing that doing so
> requires either:
> 
> (1) Recomputing the following information for the CU: encoding,
>     bitsize if any, and type name, which means:
> 
>         | attr = dwarf2_attr (die, DW_AT_encoding, cu);
>         | if (attr != nullptr && attr->form_is_constant ())
>         |   encoding = attr->constant_value (0);
>         | attr = dwarf2_attr (die, DW_AT_byte_size, cu);
>         | if (attr != nullptr)
>         |   bits = attr->constant_value (0) * TARGET_CHAR_BIT;
>         | name = dwarf2_name (die, cu);
>         | if (!name)
>         |   complaint (_("DW_AT_name missing from DW_TAG_base_type"));
> 
>     Or:
> 
> (2) Passing that information as arguments to the function.
> 
> I find option (1) really sad because of the code duplication.
> And I find option (2) somewhat unsatisfactory, because we then
> run the risk of passing inconsistent information.
> 
> This might explain partly why the init + finish approach isn't
> new in this unit...
> 
> I'm attaching the patch which shows how option (1) looks like.
> For me, the current approach strikes a better balance between
> API cleanliness and implementation considerations. But I don't
> have a strong opinion against implementing what you suggest,
> including through option (2) (or other options I missed).
> 
> Let me know what you think.
> 
> -- 
> Joel
> 

Ok I see, well that convinces me the original code is fine.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects
  2020-11-14 11:30     ` Joel Brobecker
@ 2020-11-14 16:14       ` Simon Marchi
  2020-11-15  5:30         ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-14 16:14 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: GDB patches


On 2020-11-14 6:30 a.m., Joel Brobecker wrote:
> Can you tell me if the attached patch corresponds to what you had
> in mind? As the revlog suggests, it's missing a bit of doc around it,
> but I wanted to make sure I did this correctly before adding the forms.

Yes, that looks fine, thanks.  I would split the following assert in two:

    gdb_assert (this->code () == TYPE_CODE_FIXED_POINT
		&& this->main_type->type_specific.fixed_point_info != nullptr);

because if it fails, it makes it easier at first glance to know which condition was false.

Otherwise, that is fine with me.  I think the whole type-specific stuff
management will have to be redesigned at some point anyway, so that we
can use non-POD types in there.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects
  2020-11-14 16:14       ` Simon Marchi
@ 2020-11-15  5:30         ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  5:30 UTC (permalink / raw)
  To: Simon Marchi; +Cc: GDB patches

> On 2020-11-14 6:30 a.m., Joel Brobecker wrote:
> > Can you tell me if the attached patch corresponds to what you had
> > in mind? As the revlog suggests, it's missing a bit of doc around it,
> > but I wanted to make sure I did this correctly before adding the forms.
> 
> Yes, that looks fine, thanks.

Thanks for the pre-review, Simon, and confirming I was on the right
track.

> I would split the following assert in two:
> 
>     gdb_assert (this->code () == TYPE_CODE_FIXED_POINT
> 		&& this->main_type->type_specific.fixed_point_info != nullptr);
> 
> because if it fails, it makes it easier at first glance to know which
> condition was false.

Indeed. That's a good idea.

> Otherwise, that is fine with me.  I think the whole type-specific stuff
> management will have to be redesigned at some point anyway, so that we
> can use non-POD types in there.

Agreed.

One even bigger dream of mine was to have our struct type become
a hierarchy of classes, rather than just one. Then the type-specific
stuff gets taken care of via class extension...

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects
  2020-11-10 21:06   ` Simon Marchi
  2020-11-14 10:48     ` Joel Brobecker
  2020-11-14 11:30     ` Joel Brobecker
@ 2020-11-15  6:33     ` Joel Brobecker
  2020-11-16  0:13       ` Simon Marchi
  2 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  6:33 UTC (permalink / raw)
  To: Simon Marchi; +Cc: GDB patches

[-- Attachment #1: Type: text/plain, Size: 795 bytes --]

Hi Simon,

> > +/* Given TYPE, which is a fixed point type, return its scaling factor.  */
> > +extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);
> 
> I think this would belong in fixed_point_type_info, so you'd access it
> using:
> 
>   type->fixed_point_info ().scaling_factor ()

In pratice, this wouldn't work. The main reason-d'etre for this function
is that fixed point types can be both a TYPE_CODE_FIXED_POINT as well
as a TYPE_CODE_RANGE of a TYPE_CODE_FIXED_POINT. What the function
above does is first call fixed_point_type_base_type in order to get
to the type which actually has the fixed_point_info, and then from
there accesses the scaling factor.

What we can do is make that a method of struct type instead...
This is what the attached patch does.

-- 
Joel

[-- Attachment #2: 0001-Make-function-fixed_point_scaling_factor-a-method-of.patch --]
[-- Type: text/x-diff, Size: 6948 bytes --]

From 15721d0ee30f77ce8c3abb0c9469c015a37856cd Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Sun, 15 Nov 2020 01:21:37 -0500
Subject: [PATCH] Make function fixed_point_scaling_factor a method of struct
 type

This logically connects this function to the object it inspects.

gdb/ChangeLog:

        * gdbtypes.h (struct type) <fixed_point_scaling_factor>: New method,
        replacing fixed_point_scaling_factor.  All callers updated
        throughout this project.
        (fixed_point_scaling_factor): Delete declaration.
        * gdbtypes.c (type::fixed_point_scaling_factor): Replaces
        fixed_point_scaling_factor.  Adjust implementation accordingly.
---
 gdb/gdbtypes.c  | 6 +++---
 gdb/gdbtypes.h  | 8 +++++---
 gdb/typeprint.c | 2 +-
 gdb/valarith.c  | 6 +++---
 gdb/valops.c    | 6 +++---
 gdb/valprint.c  | 2 +-
 gdb/value.c     | 2 +-
 7 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index eb176c9..79c8121 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -4922,7 +4922,7 @@ static void
 print_fixed_point_type_info (struct type *type, int spaces)
 {
   printfi_filtered (spaces + 2, "scaling factor: %s\n",
-		    fixed_point_scaling_factor (type).str ().c_str ());
+		    type->fixed_point_scaling_factor ().str ().c_str ());
 }
 
 static struct obstack dont_print_type_obstack;
@@ -5876,9 +5876,9 @@ type::fixed_point_type_base_type ()
 /* See gdbtypes.h.  */
 
 const gdb_mpq &
-fixed_point_scaling_factor (struct type *type)
+type::fixed_point_scaling_factor ()
 {
-  type = type->fixed_point_type_base_type ();
+  struct type *type = this->fixed_point_type_base_type ();
 
   return type->fixed_point_info ().scaling_factor;
 }
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 19f95f4..dc37f63 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1224,6 +1224,11 @@ struct type
 
   struct type *fixed_point_type_base_type ();
 
+  /* * Assuming that THIS is a TYPE_CODE_FIXED_POINT, return its scaling
+     factor.  */
+
+  const gdb_mpq &fixed_point_scaling_factor ();
+
   /* * Return the dynamic property of the requested KIND from this type's
      list of dynamic properties.  */
   dynamic_prop *dyn_prop (dynamic_prop_node_kind kind) const;
@@ -2589,9 +2594,6 @@ extern int type_not_associated (const struct type *type);
    a range type whose base type is a TYPE_CODE_FIXED_POINT.  */
 extern bool is_fixed_point_type (struct type *type);
 
-/* Given TYPE, which is a fixed point type, return its scaling factor.  */
-extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);
-
 /* Allocate a fixed-point type info for TYPE.  This should only be
    called by INIT_FIXED_POINT_SPECIFIC.  */
 extern void allocate_fixed_point_type_info (struct type *type);
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 6eedb5d..e85b736 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -668,7 +668,7 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream)
 void
 print_type_fixed_point (struct type *type, struct ui_file *stream)
 {
-  std::string small_img = fixed_point_scaling_factor (type).str ();
+  std::string small_img = type->fixed_point_scaling_factor ().str ();
 
   fprintf_filtered (stream, "%s-byte fixed point (small = %s)",
 		    pulongest (TYPE_LENGTH (type)), small_img.c_str ());
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 8c47249..1c6ef2c 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -911,11 +911,11 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   v1.read_fixed_point (gdb::array_view <const gdb_byte> (value_contents (arg1),
 							 TYPE_LENGTH (type1)),
 		       type_byte_order (type1), type1->is_unsigned (),
-		       fixed_point_scaling_factor (type1));
+		       type1->fixed_point_scaling_factor ());
   v2.read_fixed_point (gdb::array_view <const gdb_byte> (value_contents (arg2),
 							 TYPE_LENGTH (type2)),
 		       type_byte_order (type2), type2->is_unsigned (),
-		       fixed_point_scaling_factor (type2));
+		       type2->fixed_point_scaling_factor ());
 
 #define INIT_VAL_WITH_FIXED_POINT_VAL(RESULT) \
   do { \
@@ -924,7 +924,7 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
         (gdb::array_view <gdb_byte> (value_contents_raw (val), \
 				     TYPE_LENGTH (type1)), \
 	 type_byte_order (type1), type1->is_unsigned (), \
-	 fixed_point_scaling_factor (type1)); \
+	 type1->fixed_point_scaling_factor ()); \
      } while (0)
 
   switch (op)
diff --git a/gdb/valops.c b/gdb/valops.c
index b4c6d88..bfddf62 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -363,7 +363,7 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
       mpq_set_z (vq.val, vz.val);
 
       if (is_fixed_point_type (from_type))
-	mpq_mul (vq.val, vq.val, fixed_point_scaling_factor (from_type).val);
+	mpq_mul (vq.val, vq.val, from_type->fixed_point_scaling_factor ().val);
     }
 
   else
@@ -373,7 +373,7 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
   /* Divide that value by the scaling factor to obtain the unscaled
      value, first in rational form, and then in integer form.  */
 
-  mpq_div (vq.val, vq.val, fixed_point_scaling_factor (to_type).val);
+  mpq_div (vq.val, vq.val, to_type->fixed_point_scaling_factor ().val);
   gdb_mpz unscaled = vq.get_rounded ();
 
   /* Finally, create the result value, and pack the unscaled value
@@ -528,7 +528,7 @@ value_cast (struct type *type, struct value *arg2)
 	    (gdb::array_view<const gdb_byte> (value_contents (arg2),
 					      TYPE_LENGTH (type2)),
 	     type_byte_order (type2), type2->is_unsigned (),
-	     fixed_point_scaling_factor (type2));
+	     type2->fixed_point_scaling_factor ());
 
 	  struct value *v = allocate_value (to_type);
 	  target_float_from_host_double (value_contents_raw (v),
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 66f8de9..0d66ed4 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -812,7 +812,7 @@ generic_val_print_fixed_point (struct value *val, struct ui_file *stream,
       f.read_fixed_point (gdb::array_view<const gdb_byte> (valaddr,
 							   TYPE_LENGTH (type)),
 			  type_byte_order (type), type->is_unsigned (),
-			  fixed_point_scaling_factor (type));
+			  type->fixed_point_scaling_factor ());
 
       const char *fmt = TYPE_LENGTH (type) < 4 ? "%.11Fg" : "%.17Fg";
       std::string str = gmp_string_asprintf (fmt, f.val);
diff --git a/gdb/value.c b/gdb/value.c
index f3f5169..0b3d463 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2814,7 +2814,7 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
 	gdb_mpq vq;
 	vq.read_fixed_point (gdb::array_view<const gdb_byte> (valaddr, len),
 			     byte_order, nosign,
-			     fixed_point_scaling_factor (type));
+			     type->fixed_point_scaling_factor ());
 
 	gdb_mpz vz;
 	mpz_tdiv_q (vz.val, mpq_numref (vq.val), mpq_denref (vq.val));
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 7/9] Add ptype support for DWARF-based fixed-point types
  2020-11-10 23:00   ` Simon Marchi
@ 2020-11-15  6:57     ` Joel Brobecker
  2020-11-15  7:09       ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  6:57 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

Hi Simon,

> > +        gdb_test_no_output "set language $lang" \
> > +            "set language to $lang for ptype test"
> > +
> > +        gdb_test "ptype pck__fp1_var" $fp1_re
> > +
> > +        gdb_test "ptype pck__fp2_var" $fp2_re
> > +
> > +        gdb_test "ptype pck__fp3_var" $fp3_re
> > +
> > +        if { $lang == "modula-2" || $lang == "pascal" } {
> > +            setup_xfail "*-*-*" "not supported by language"
> > +        }
> 
> Can you give more details about this?  What prevents these languages
> from printing <range type>?  I'm confused, because as far as I can tell
> C doesn't support range types more than these two languages, and it's
> able to print <range type>.

Both trigger the following error:

    (gdb) ptype pck__fp1_range_var
    type = [Invalid type code in symbol table.

It didn't seem to be worth the effort of going any further than that,
because I didn't didn't think either language would have fixed point
types.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 7/9] Add ptype support for DWARF-based fixed-point types
  2020-11-15  6:57     ` Joel Brobecker
@ 2020-11-15  7:09       ` Joel Brobecker
  2020-11-16  0:16         ` Simon Marchi
  0 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  7:09 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

> > > +        gdb_test_no_output "set language $lang" \
> > > +            "set language to $lang for ptype test"
> > > +
> > > +        gdb_test "ptype pck__fp1_var" $fp1_re
> > > +
> > > +        gdb_test "ptype pck__fp2_var" $fp2_re
> > > +
> > > +        gdb_test "ptype pck__fp3_var" $fp3_re
> > > +
> > > +        if { $lang == "modula-2" || $lang == "pascal" } {
> > > +            setup_xfail "*-*-*" "not supported by language"
> > > +        }
> > 
> > Can you give more details about this?  What prevents these languages
> > from printing <range type>?  I'm confused, because as far as I can tell
> > C doesn't support range types more than these two languages, and it's
> > able to print <range type>.
> 
> Both trigger the following error:
> 
>     (gdb) ptype pck__fp1_range_var
>     type = [Invalid type code in symbol table.
> 
> It didn't seem to be worth the effort of going any further than that,
> because I didn't didn't think either language would have fixed point
> types.

I should probably expand a bit: I tried to make the implementation
of this feature as generic as possible, so that all current and
future languages that provide support for these kinds of types can
benefit from it with as little work as possible. For some reason,
this doesn't work for M2 and Pascal, and the decision I made at
the time was to ignore these issues on the basis that these are errors
a real user is unlikely to hit.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* pushed: Add support for DWARF-based fixed point types
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
                   ` (9 preceding siblings ...)
  2020-11-10 23:21 ` RFA: Add support for DWARF-based fixed point types Simon Marchi
@ 2020-11-15  8:35 ` Joel Brobecker
  2020-11-15  8:35   ` [pushed/v2 1/9] gdb/configure: Add --with-libgmp-prefix option Joel Brobecker
                     ` (11 more replies)
  2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
  11 siblings, 12 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

Hi everyone,

I just finished pusing the following patch series to branch master.

  -  gdb/configure: Add --with-libgmp-prefix option
  -  gdb: Make GMP a required dependency for building GDB
  -  gmp-utils: New API to simply use of GMP's
  -  Move uinteger_pow gdb/valarith.c to gdb/utils.c and
  -  Add support for printing value of DWARF-based
  -  fix printing of DWARF fixed-point type objects with
  -  Add ptype support for DWARF-based fixed-point types
  -  Add support for fixed-point type arithmetic
  -  Add support for fixed-point type comparison operators

The differences between what I pushed and what was sent for review
is that I took care of all the suggestions that Simon made which
were small and straightforward.

I already replied to the various suggestions that made less sense
to me.

For the remaining suggestions, I decided to handle them as followup
changes, which I have already implemented and will send for review
momentarily.

A big Thank You again to Simon for having taken the time to review
the aptch series!

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* [pushed/v2 1/9] gdb/configure: Add --with-libgmp-prefix option
  2020-11-15  8:35 ` pushed: " Joel Brobecker
@ 2020-11-15  8:35   ` Joel Brobecker
  2020-11-15 15:52     ` Bernd Edlinger
  2020-11-15  8:35   ` [pushed/v2 2/9] gdb: Make GMP a required dependency for building GDB Joel Brobecker
                     ` (10 subsequent siblings)
  11 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This patch allows a user to tell gdb's configure script where
his GMP library is installed.

gdb/ChangeLog:

        * configure.ac: Add support for --with-libgmp-prefix.
        * Makefile.in (LIBGMP): New variable.
        (CLIBS): Include $(LIBGMP).
        * configure, config.in: Regenerate
---
 gdb/ChangeLog    |   7 +
 gdb/Makefile.in  |   5 +-
 gdb/config.in    |   3 +
 gdb/configure    | 488 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/configure.ac |   5 +
 5 files changed, 507 insertions(+), 1 deletion(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a70c5fe..ee1dea3 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,10 @@
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
+	* configure.ac: Add support for --with-libgmp-prefix.
+	* Makefile.in (LIBGMP): New variable.
+	(CLIBS): Include $(LIBGMP).
+	* configure, config.in: Regenerate
+
 2020-11-14  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	PR cli/26879
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c46935e..c461964 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -203,6 +203,9 @@ LIBXXHASH = @LIBXXHASH@
 # Where is libipt?  This will be empty if libipt was not available.
 LIBIPT = @LIBIPT@
 
+# Where is libgmp?
+LIBGMP = @LIBGMP@
+
 # Where is libmpfr?  This will be empty if libmpfr was not available.
 LIBMPFR = @LIBMPFR@
 
@@ -632,7 +635,7 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) \
 	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
 	$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
 	$(WIN32LIBS) $(LIBGNU) $(LIBGNU_EXTRA_LIBS) $(LIBICONV) \
-	$(LIBMPFR) $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
+	$(LIBMPFR) $(LIBGMP) $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
 	$(DEBUGINFOD_LIBS)
 CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(CTF_DEPS) \
 	$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) \
diff --git a/gdb/config.in b/gdb/config.in
index 3e741c6..14a77c6 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -229,6 +229,9 @@
 /* Define if you have the expat library. */
 #undef HAVE_LIBEXPAT
 
+/* Define if you have the gmp library. */
+#undef HAVE_LIBGMP
+
 /* Define to 1 if you have the `libiconvlist' function. */
 #undef HAVE_LIBICONVLIST
 
diff --git a/gdb/configure b/gdb/configure
index 4a03cd9..2bf0856 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -732,6 +732,9 @@ python_prog_path
 LTLIBMPFR
 LIBMPFR
 HAVE_LIBMPFR
+LTLIBGMP
+LIBGMP
+HAVE_LIBGMP
 LTLIBEXPAT
 LIBEXPAT
 HAVE_LIBEXPAT
@@ -896,6 +899,8 @@ with_jit_reader_dir
 with_expat
 with_libexpat_prefix
 with_libexpat_type
+with_libgmp_prefix
+with_libgmp_type
 with_mpfr
 with_libmpfr_prefix
 with_libmpfr_type
@@ -1639,6 +1644,9 @@ Optional Packages:
   --with-libexpat-prefix[=DIR]  search for libexpat in DIR/include and DIR/lib
   --without-libexpat-prefix     don't search for libexpat in includedir and libdir
   --with-libexpat-type=TYPE     type of library to search for (auto/static/shared)
+  --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
+  --without-libgmp-prefix     don't search for libgmp in includedir and libdir
+  --with-libgmp-type=TYPE     type of library to search for (auto/static/shared)
   --with-mpfr             include MPFR support (auto/yes/no)
   --with-libmpfr-prefix[=DIR]  search for libmpfr in DIR/include and DIR/lib
   --without-libmpfr-prefix     don't search for libmpfr in includedir and libdir
@@ -9982,6 +9990,486 @@ done
   fi
 fi
 
+# Verify that we have a usable GMP library.
+
+
+
+
+
+
+
+
+    use_additional=yes
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+
+# Check whether --with-libgmp-prefix was given.
+if test "${with_libgmp_prefix+set}" = set; then :
+  withval=$with_libgmp_prefix;
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/lib"
+      fi
+    fi
+
+fi
+
+
+# Check whether --with-libgmp-type was given.
+if test "${with_libgmp_type+set}" = set; then :
+  withval=$with_libgmp_type;  with_libgmp_type=$withval
+else
+   with_libgmp_type=auto
+fi
+
+  lib_type=`eval echo \$with_libgmp_type`
+
+      LIBGMP=
+  LTLIBGMP=
+  INCGMP=
+  rpathdirs=
+  ltrpathdirs=
+  names_already_handled=
+  names_next_round='gmp '
+  while test -n "$names_next_round"; do
+    names_this_round="$names_next_round"
+    names_next_round=
+    for name in $names_this_round; do
+      already_handled=
+      for n in $names_already_handled; do
+        if test "$n" = "$name"; then
+          already_handled=yes
+          break
+        fi
+      done
+      if test -z "$already_handled"; then
+        names_already_handled="$names_already_handled $name"
+                        uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+        eval value=\"\$HAVE_LIB$uppername\"
+        if test -n "$value"; then
+          if test "$value" = yes; then
+            eval value=\"\$LIB$uppername\"
+            test -z "$value" || LIBGMP="${LIBGMP}${LIBGMP:+ }$value"
+            eval value=\"\$LTLIB$uppername\"
+            test -z "$value" || LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }$value"
+          else
+                                    :
+          fi
+        else
+                              found_dir=
+          found_la=
+          found_so=
+          found_a=
+          if test $use_additional = yes; then
+            if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext" && test x$lib_type != xstatic; then
+              found_dir="$additional_libdir"
+              found_so="$additional_libdir/lib$name.$shlibext"
+              if test -f "$additional_libdir/lib$name.la"; then
+                found_la="$additional_libdir/lib$name.la"
+              fi
+            elif test x$lib_type != xshared; then
+              if test -f "$additional_libdir/lib$name.$libext"; then
+                found_dir="$additional_libdir"
+                found_a="$additional_libdir/lib$name.$libext"
+                if test -f "$additional_libdir/lib$name.la"; then
+                  found_la="$additional_libdir/lib$name.la"
+                fi
+              fi
+            fi
+          fi
+          if test "X$found_dir" = "X"; then
+            for x in $LDFLAGS $LTLIBGMP; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+              case "$x" in
+                -L*)
+                  dir=`echo "X$x" | sed -e 's/^X-L//'`
+                  if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext" && test x$lib_type != xstatic; then
+                    found_dir="$dir"
+                    found_so="$dir/lib$name.$shlibext"
+                    if test -f "$dir/lib$name.la"; then
+                      found_la="$dir/lib$name.la"
+                    fi
+                  elif test x$lib_type != xshared; then
+                    if test -f "$dir/lib$name.$libext"; then
+                      found_dir="$dir"
+                      found_a="$dir/lib$name.$libext"
+                      if test -f "$dir/lib$name.la"; then
+                        found_la="$dir/lib$name.la"
+                      fi
+                    fi
+                  fi
+                  ;;
+              esac
+              if test "X$found_dir" != "X"; then
+                break
+              fi
+            done
+          fi
+          if test "X$found_dir" != "X"; then
+                        LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-L$found_dir -l$name"
+            if test "X$found_so" != "X"; then
+                                                        if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+                                LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
+              else
+                                                                                haveit=
+                for x in $ltrpathdirs; do
+                  if test "X$x" = "X$found_dir"; then
+                    haveit=yes
+                    break
+                  fi
+                done
+                if test -z "$haveit"; then
+                  ltrpathdirs="$ltrpathdirs $found_dir"
+                fi
+                                if test "$hardcode_direct" = yes; then
+                                                      LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
+                else
+                  if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+                                                            LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
+                                                            haveit=
+                    for x in $rpathdirs; do
+                      if test "X$x" = "X$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      rpathdirs="$rpathdirs $found_dir"
+                    fi
+                  else
+                                                                                haveit=
+                    for x in $LDFLAGS $LIBGMP; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                      if test "X$x" = "X-L$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      LIBGMP="${LIBGMP}${LIBGMP:+ }-L$found_dir"
+                    fi
+                    if test "$hardcode_minus_L" != no; then
+                                                                                        LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
+                    else
+                                                                                                                                                                                LIBGMP="${LIBGMP}${LIBGMP:+ }-l$name"
+                    fi
+                  fi
+                fi
+              fi
+            else
+              if test "X$found_a" != "X"; then
+                                LIBGMP="${LIBGMP}${LIBGMP:+ }$found_a"
+              else
+                                                LIBGMP="${LIBGMP}${LIBGMP:+ }-L$found_dir -l$name"
+              fi
+            fi
+                        additional_includedir=
+            case "$found_dir" in
+              */lib | */lib/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+                additional_includedir="$basedir/include"
+                ;;
+            esac
+            if test "X$additional_includedir" != "X"; then
+                                                                                                                if test "X$additional_includedir" != "X/usr/include"; then
+                haveit=
+                if test "X$additional_includedir" = "X/usr/local/include"; then
+                  if test -n "$GCC"; then
+                    case $host_os in
+                      linux*) haveit=yes;;
+                    esac
+                  fi
+                fi
+                if test -z "$haveit"; then
+                  for x in $CPPFLAGS $INCGMP; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                    if test "X$x" = "X-I$additional_includedir"; then
+                      haveit=yes
+                      break
+                    fi
+                  done
+                  if test -z "$haveit"; then
+                    if test -d "$additional_includedir"; then
+                                            INCGMP="${INCGMP}${INCGMP:+ }-I$additional_includedir"
+                    fi
+                  fi
+                fi
+              fi
+            fi
+                        if test -n "$found_la"; then
+                                                        save_libdir="$libdir"
+              case "$found_la" in
+                */* | *\\*) . "$found_la" ;;
+                *) . "./$found_la" ;;
+              esac
+              libdir="$save_libdir"
+                            for dep in $dependency_libs; do
+                case "$dep" in
+                  -L*)
+                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+                                                                                                                                                                if test "X$additional_libdir" != "X/usr/lib"; then
+                      haveit=
+                      if test "X$additional_libdir" = "X/usr/local/lib"; then
+                        if test -n "$GCC"; then
+                          case $host_os in
+                            linux*) haveit=yes;;
+                          esac
+                        fi
+                      fi
+                      if test -z "$haveit"; then
+                        haveit=
+                        for x in $LDFLAGS $LIBGMP; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                                                        LIBGMP="${LIBGMP}${LIBGMP:+ }-L$additional_libdir"
+                          fi
+                        fi
+                        haveit=
+                        for x in $LDFLAGS $LTLIBGMP; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                                                        LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-L$additional_libdir"
+                          fi
+                        fi
+                      fi
+                    fi
+                    ;;
+                  -R*)
+                    dir=`echo "X$dep" | sed -e 's/^X-R//'`
+                    if test "$enable_rpath" != no; then
+                                                                  haveit=
+                      for x in $rpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        rpathdirs="$rpathdirs $dir"
+                      fi
+                                                                  haveit=
+                      for x in $ltrpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        ltrpathdirs="$ltrpathdirs $dir"
+                      fi
+                    fi
+                    ;;
+                  -l*)
+                                        names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+                    ;;
+                  *.la)
+                                                                                names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+                    ;;
+                  *)
+                                        LIBGMP="${LIBGMP}${LIBGMP:+ }$dep"
+                    LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }$dep"
+                    ;;
+                esac
+              done
+            fi
+          else
+                                                            if test "x$lib_type" = "xauto" || test "x$lib_type" = "xshared"; then
+              LIBGMP="${LIBGMP}${LIBGMP:+ }-l$name"
+              LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-l$name"
+            else
+              LIBGMP="${LIBGMP}${LIBGMP:+ }-l:lib$name.$libext"
+              LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-l:lib$name.$libext"
+            fi
+          fi
+        fi
+      fi
+    done
+  done
+  if test "X$rpathdirs" != "X"; then
+    if test -n "$hardcode_libdir_separator"; then
+                        alldirs=
+      for found_dir in $rpathdirs; do
+        alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+      done
+            acl_save_libdir="$libdir"
+      libdir="$alldirs"
+      eval flag=\"$hardcode_libdir_flag_spec\"
+      libdir="$acl_save_libdir"
+      LIBGMP="${LIBGMP}${LIBGMP:+ }$flag"
+    else
+            for found_dir in $rpathdirs; do
+        acl_save_libdir="$libdir"
+        libdir="$found_dir"
+        eval flag=\"$hardcode_libdir_flag_spec\"
+        libdir="$acl_save_libdir"
+        LIBGMP="${LIBGMP}${LIBGMP:+ }$flag"
+      done
+    fi
+  fi
+  if test "X$ltrpathdirs" != "X"; then
+            for found_dir in $ltrpathdirs; do
+      LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-R$found_dir"
+    done
+  fi
+
+
+        ac_save_CPPFLAGS="$CPPFLAGS"
+
+  for element in $INCGMP; do
+    haveit=
+    for x in $CPPFLAGS; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+      if test "X$x" = "X$element"; then
+        haveit=yes
+        break
+      fi
+    done
+    if test -z "$haveit"; then
+      CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+    fi
+  done
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libgmp" >&5
+$as_echo_n "checking for libgmp... " >&6; }
+if ${ac_cv_libgmp+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    ac_save_LIBS="$LIBS"
+    LIBS="$LIBS $LIBGMP"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <gmp.h>
+int
+main ()
+{
+mpz_t n;
+                       mpz_init (n);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_libgmp=yes
+else
+  ac_cv_libgmp=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LIBS="$ac_save_LIBS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libgmp" >&5
+$as_echo "$ac_cv_libgmp" >&6; }
+  if test "$ac_cv_libgmp" = yes; then
+    HAVE_LIBGMP=yes
+
+$as_echo "#define HAVE_LIBGMP 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libgmp" >&5
+$as_echo_n "checking how to link with libgmp... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBGMP" >&5
+$as_echo "$LIBGMP" >&6; }
+  else
+    HAVE_LIBGMP=no
+            CPPFLAGS="$ac_save_CPPFLAGS"
+    LIBGMP=
+    LTLIBGMP=
+  fi
+
+
+
+
+
+
+
 
 # Check whether --with-mpfr was given.
 if test "${with_mpfr+set}" = set; then :
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 1b9548e..0264a4f 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -683,6 +683,11 @@ else
   fi
 fi
 
+# Verify that we have a usable GMP library.
+AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
+                      [mpz_t n;
+                       mpz_init (n);])
+
 AC_ARG_WITH(mpfr,
   AS_HELP_STRING([--with-mpfr], [include MPFR support (auto/yes/no)]),
   [], [with_mpfr=auto])
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [pushed/v2 2/9] gdb: Make GMP a required dependency for building GDB
  2020-11-15  8:35 ` pushed: " Joel Brobecker
  2020-11-15  8:35   ` [pushed/v2 1/9] gdb/configure: Add --with-libgmp-prefix option Joel Brobecker
@ 2020-11-15  8:35   ` Joel Brobecker
  2020-11-15  8:35   ` [pushed/v2 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects Joel Brobecker
                     ` (9 subsequent siblings)
  11 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This commit modifies gdb's configure script to trigger an error
if we cannot find a usable libgmp.

For the record, making this a requirement was discussed in March 2018:
https://sourceware.org/pipermail/gdb-patches/2018-March/147373.html

gdb/ChangeLog:

        * configure.ac: Generate an error if a usable GMP library
        could not be found.
        * configure: Regenerate.
---
 gdb/ChangeLog    | 6 ++++++
 gdb/configure    | 3 +++
 gdb/configure.ac | 3 +++
 3 files changed, 12 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ee1dea3..8de390a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,11 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* configure.ac: Generate an error if a usable GMP library
+	could not be found.
+	* configure: Regenerate.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* configure.ac: Add support for --with-libgmp-prefix.
 	* Makefile.in (LIBGMP): New variable.
 	(CLIBS): Include $(LIBGMP).
diff --git a/gdb/configure b/gdb/configure
index 2bf0856..a3e73b4 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -10469,6 +10469,9 @@ $as_echo "$LIBGMP" >&6; }
 
 
 
+if test "$HAVE_LIBGMP" != yes; then
+  as_fn_error $? "GMP is missing or unusable" "$LINENO" 5
+fi
 
 
 # Check whether --with-mpfr was given.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 0264a4f..32f25d9 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -687,6 +687,9 @@ fi
 AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
                       [mpz_t n;
                        mpz_init (n);])
+if test "$HAVE_LIBGMP" != yes; then
+  AC_MSG_ERROR([GMP is missing or unusable])
+fi
 
 AC_ARG_WITH(mpfr,
   AS_HELP_STRING([--with-mpfr], [include MPFR support (auto/yes/no)]),
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [pushed/v2 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects
  2020-11-15  8:35 ` pushed: " Joel Brobecker
  2020-11-15  8:35   ` [pushed/v2 1/9] gdb/configure: Add --with-libgmp-prefix option Joel Brobecker
  2020-11-15  8:35   ` [pushed/v2 2/9] gdb: Make GMP a required dependency for building GDB Joel Brobecker
@ 2020-11-15  8:35   ` Joel Brobecker
  2020-11-15  8:35   ` [pushed/v2 4/9] Move uinteger_pow gdb/valarith.c to gdb/utils.c and make it public Joel Brobecker
                     ` (8 subsequent siblings)
  11 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This API was motivated by a number of reasons:
  - GMP's API does not handle "long long" and "unsigned long long",
    so using LONGEST and ULONGEST is not straightforward;
  - Automate the need to initialize GMP objects before use, and
    clear them when no longer used.

However, this API grew also to help with similar matter such
as formatting to a string, and also reading/writing fixed-point
values from byte buffers.

Dedicated unit testing is also added.

gdb/ChangeLog:

        * gmp-utils.h,  gmp-utils.h: New file.
        * unittests/gmp-utils-selftests.c: New file.
        * Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
        unittests/gmp-utils-selftests.c.
        (COMMON_SFILES) Add gmp-utils.c.
        (HFILES_NO_SRCDIR): Add gmp-utils.h.
---
 gdb/ChangeLog                       |   9 +
 gdb/Makefile.in                     |   3 +
 gdb/gmp-utils.c                     | 172 ++++++++++++++
 gdb/gmp-utils.h                     | 282 ++++++++++++++++++++++
 gdb/unittests/gmp-utils-selftests.c | 460 ++++++++++++++++++++++++++++++++++++
 5 files changed, 926 insertions(+)
 create mode 100644 gdb/gmp-utils.c
 create mode 100644 gdb/gmp-utils.h
 create mode 100644 gdb/unittests/gmp-utils-selftests.c

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 8de390a..a029109 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,14 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* gmp-utils.h,  gmp-utils.h: New file.
+	* unittests/gmp-utils-selftests.c: New file.
+	* Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
+	unittests/gmp-utils-selftests.c.
+	(COMMON_SFILES) Add gmp-utils.c.
+	(HFILES_NO_SRCDIR): Add gmp-utils.h.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* configure.ac: Generate an error if a usable GMP library
 	could not be found.
 	* configure: Regenerate.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c461964..9b48f73 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -446,6 +446,7 @@ SELFTESTS_SRCS = \
 	unittests/filtered_iterator-selftests.c \
 	unittests/format_pieces-selftests.c \
 	unittests/function-view-selftests.c \
+	unittests/gmp-utils-selftests.c \
 	unittests/lookup_name_info-selftests.c \
 	unittests/memory-map-selftests.c \
 	unittests/memrange-selftests.c \
@@ -1059,6 +1060,7 @@ COMMON_SFILES = \
 	gdb_regex.c \
 	gdbarch.c \
 	gdbtypes.c \
+	gmp-utils.c \
 	gnu-v2-abi.c \
 	gnu-v3-abi.c \
 	go-lang.c \
@@ -1304,6 +1306,7 @@ HFILES_NO_SRCDIR = \
 	gdbthread.h \
 	gdbtypes.h \
 	glibc-tdep.h \
+	gmp-utils.h \
 	gnu-nat.h \
 	go-lang.h \
 	gregset.h \
diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
new file mode 100644
index 0000000..db92e57
--- /dev/null
+++ b/gdb/gmp-utils.c
@@ -0,0 +1,172 @@
+/* Copyright (C) 2019-2020 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 "gmp-utils.h"
+
+/* See gmp-utils.h.  */
+
+gdb::unique_xmalloc_ptr<char>
+gmp_string_asprintf (const char *fmt, ...)
+{
+  va_list vp;
+  char *buf;
+
+  va_start (vp, fmt);
+  gmp_vasprintf (&buf, fmt, vp);
+  va_end (vp);
+
+  return gdb::unique_xmalloc_ptr<char> (buf);
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+	       bool unsigned_p)
+{
+  mpz_import (val, 1 /* count */, -1 /* order */, len /* size */,
+	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
+	      0 /* nails */, buf /* op */);
+
+  if (!unsigned_p)
+    {
+      /* The value was imported as if it was a positive value,
+	 as mpz_import does not handle signs. If the original value
+	 was in fact negative, we need to adjust VAL accordingly.  */
+      gdb_mpz max;
+
+      mpz_ui_pow_ui (max.val, 2, len * TARGET_CHAR_BIT - 1);
+      if (mpz_cmp (val, max.val) >= 0)
+	mpz_submul_ui (val, max.val, 2);
+    }
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpz::write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+		bool unsigned_p) const
+{
+  gdb_mpz exported_val (val);
+
+  if (mpz_cmp_ui (val, 0) < 0)
+    {
+      /* mpz_export does not handle signed values, so create a positive
+	 value whose bit representation as an unsigned of the same length
+	 would be the same as our negative value.  */
+      gdb_mpz neg_offset;
+
+      mpz_ui_pow_ui (neg_offset.val, 2, len * TARGET_CHAR_BIT);
+      mpz_add (exported_val.val, exported_val.val, neg_offset.val);
+    }
+
+  /* Start by clearing the buffer, as mpz_export only writes as many
+     bytes as it needs (including none, if the value to export is zero.  */
+  memset (buf, 0, len);
+  mpz_export (buf, NULL /* count */, -1 /* order */, len /* size */,
+	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
+	      0 /* nails */, exported_val.val);
+}
+
+/* See gmp-utils.h.  */
+
+gdb_mpz
+gdb_mpq::get_rounded () const
+{
+  /* Work with a positive number so as to make the "floor" rounding
+     always round towards zero.  */
+
+  gdb_mpq abs_val (val);
+  mpq_abs (abs_val.val, abs_val.val);
+
+  /* Convert our rational number into a quotient and remainder,
+     with "floor" rounding, which in our case means rounding
+     towards zero.  */
+
+  gdb_mpz quotient, remainder;
+  mpz_fdiv_qr (quotient.val, remainder.val,
+	       mpq_numref (abs_val.val), mpq_denref (abs_val.val));
+
+  /* Multiply the remainder by 2, and see if it is greater or equal
+     to abs_val's denominator.  If yes, round to the next integer.  */
+
+  mpz_mul_ui (remainder.val, remainder.val, 2);
+  if (mpz_cmp (remainder.val, mpq_denref (abs_val.val)) >= 0)
+    mpz_add_ui (quotient.val, quotient.val, 1);
+
+  /* Re-apply the sign if needed.  */
+  if (mpq_sgn (val) < 0)
+    mpz_neg (quotient.val, quotient.val);
+
+  return quotient;
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpq::read_fixed_point (const gdb_byte *buf, int len,
+			   enum bfd_endian byte_order, bool unsigned_p,
+			   const gdb_mpq &scaling_factor)
+{
+  gdb_mpz vz;
+  vz.read (buf, len, byte_order, unsigned_p);
+
+  mpq_set_z (val, vz.val);
+  mpq_mul (val, val, scaling_factor.val);
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpq::write_fixed_point (gdb_byte *buf, int len,
+			    enum bfd_endian byte_order, bool unsigned_p,
+			    const gdb_mpq &scaling_factor) const
+{
+  gdb_mpq unscaled (val);
+
+  mpq_div (unscaled.val, unscaled.val, scaling_factor.val);
+
+  gdb_mpz unscaled_z = unscaled.get_rounded ();
+  unscaled_z.write (buf, len, byte_order, unsigned_p);
+}
+
+/* A wrapper around xrealloc that we can then register with GMP
+   as the "realloc" function.  */
+
+static void *
+xrealloc_for_gmp (void *ptr, size_t old_size, size_t new_size)
+{
+  return xrealloc (ptr, new_size);
+}
+
+/* A wrapper around xfree that we can then register with GMP
+   as the "free" function.  */
+
+static void
+xfree_for_gmp (void *ptr, size_t size)
+{
+  xfree (ptr);
+}
+
+void _initialize_gmp_utils ();
+
+void
+_initialize_gmp_utils ()
+{
+  /* Tell GMP to use GDB's memory management routines.  */
+  mp_set_memory_functions (xmalloc, xrealloc_for_gmp, xfree_for_gmp);
+}
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
new file mode 100644
index 0000000..1214b64
--- /dev/null
+++ b/gdb/gmp-utils.h
@@ -0,0 +1,282 @@
+/* Miscellaneous routines making it easier to use GMP within GDB's framework.
+
+   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GMP_UTILS_H
+#define GMP_UTILS_H
+
+#include "defs.h"
+
+/* Include <stdio.h> and <stdarg.h> ahead of <gmp.h>, so as to get
+   access to GMP's various formatting functions.  */
+#include <stdio.h>
+#include <stdarg.h>
+#include <gmp.h>
+#include "gdbsupport/traits.h"
+
+/* Same as gmp_asprintf, but returning a convenient wrapper type.  */
+
+gdb::unique_xmalloc_ptr<char> gmp_string_asprintf (const char *fmt, ...);
+
+/* A class to make it easier to use GMP's mpz_t values within GDB.  */
+
+struct gdb_mpz
+{
+  mpz_t val;
+
+  /* Constructors.  */
+  gdb_mpz () { mpz_init (val); }
+
+  explicit gdb_mpz (const mpz_t &from_val)
+  {
+    mpz_init (val);
+    mpz_set (val, from_val);
+  }
+
+  gdb_mpz (const gdb_mpz &from)
+  {
+    mpz_init (val);
+    mpz_set (val, from.val);
+  }
+
+  /* Initialize using the given integral value.
+
+     The main advantage of this method is that it handles both signed
+     and unsigned types, with no size restriction.  */
+  template<typename T, typename = gdb::Requires<std::is_integral<T>>>
+  explicit gdb_mpz (T src)
+  {
+    mpz_init (val);
+    set (src);
+  }
+
+  explicit gdb_mpz (gdb_mpz &&from)
+  {
+    mpz_init (val);
+    mpz_swap (val, from.val);
+  }
+
+  
+  gdb_mpz &operator= (const gdb_mpz &from)
+  {
+    mpz_set (val, from.val);
+    return *this;
+  }
+
+  gdb_mpz &operator= (gdb_mpz &&other)
+  {
+    mpz_swap (val, other.val);
+    return *this;
+  }
+
+  template<typename T, typename = gdb::Requires<std::is_integral<T>>>
+  gdb_mpz &operator= (T src)
+  {
+    set (src);
+    return *this;
+  }
+
+  /* Convert VAL to an integer of the given type.
+
+     The return type can signed or unsigned, with no size restriction.  */
+  template<typename T> T as_integer () const;
+
+  /* Set VAL by importing the number stored in the byte buffer (BUF),
+     given its size (LEN) and BYTE_ORDER.
+
+     UNSIGNED_P indicates whether the number has an unsigned type.  */
+  void read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+	     bool unsigned_p);
+
+  /* Write VAL into BUF as a LEN-bytes number with the given BYTE_ORDER.
+
+     UNSIGNED_P indicates whether the number has an unsigned type.  */
+  void write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+	      bool unsigned_p) const;
+
+  /* Return a string containing VAL.  */
+  gdb::unique_xmalloc_ptr<char> str () const
+  { return gmp_string_asprintf ("%Zd", val); }
+
+  /* The destructor.  */
+  ~gdb_mpz () { mpz_clear (val); }
+
+private:
+
+  /* Helper template for constructor and operator=.  */
+  template<typename T> void set (T src);
+};
+
+/* A class to make it easier to use GMP's mpq_t values within GDB.  */
+
+struct gdb_mpq
+{
+  mpq_t val;
+
+  /* Constructors.  */
+  gdb_mpq () { mpq_init (val); }
+
+  explicit gdb_mpq (const mpq_t &from_val)
+  {
+    mpq_init (val);
+    mpq_set (val, from_val);
+  }
+
+  gdb_mpq (const gdb_mpq &from)
+  {
+    mpq_init (val);
+    mpq_set (val, from.val);
+  }
+
+  explicit gdb_mpq (gdb_mpq &&from)
+  {
+    mpq_init (val);
+    mpq_swap (val, from.val);
+  }
+
+  /* Copy assignment operator.  */
+  gdb_mpq &operator= (const gdb_mpq &from)
+  {
+    mpq_set (val, from.val);
+    return *this;
+  }
+
+  gdb_mpq &operator= (gdb_mpq &&from)
+  {
+    mpq_swap (val, from.val);
+    return *this;
+  }
+
+  /* Return a string representing VAL as "<numerator> / <denominator>".  */
+  gdb::unique_xmalloc_ptr<char> str () const
+  { return gmp_string_asprintf ("%Qd", val); }
+
+  /* Return VAL rounded to the nearest integer.  */
+  gdb_mpz get_rounded () const;
+
+  /* Set VAL from the contents of the given buffer (BUF), which
+     contains the unscaled value of a fixed point type object
+     with the given size (LEN) and byte order (BYTE_ORDER).
+
+     UNSIGNED_P indicates whether the number has an unsigned type.
+     SCALING_FACTOR is the scaling factor to apply after having
+     read the unscaled value from our buffer.  */
+  void read_fixed_point (const gdb_byte *buf, int len,
+			 enum bfd_endian byte_order, bool unsigned_p,
+			 const gdb_mpq &scaling_factor);
+
+  /* Write VAL into BUF as a LEN-bytes fixed point value following
+     the given BYTE_ORDER.
+
+     UNSIGNED_P indicates whether the number has an unsigned type.
+     SCALING_FACTOR is the scaling factor to apply before writing
+     the unscaled value to our buffer.  */
+  void write_fixed_point (gdb_byte *buf, int len,
+			  enum bfd_endian byte_order, bool unsigned_p,
+			  const gdb_mpq &scaling_factor) const;
+
+  /* The destructor.  */
+  ~gdb_mpq () { mpq_clear (val); }
+};
+
+/* A class to make it easier to use GMP's mpf_t values within GDB.
+
+   Should MPFR become a required dependency, we should probably
+   drop this class in favor of using MPFR.  */
+
+struct gdb_mpf
+{
+  mpf_t val;
+
+  /* Constructors.  */
+  gdb_mpf () { mpf_init (val); }
+
+  DISABLE_COPY_AND_ASSIGN (gdb_mpf);
+
+  /* Set VAL from the contents of the given buffer (BUF), which
+     contains the unscaled value of a fixed point type object
+     with the given size (LEN) and byte order (BYTE_ORDER).
+
+     UNSIGNED_P indicates whether the number has an unsigned type.
+     SCALING_FACTOR is the scaling factor to apply after having
+     read the unscaled value from our buffer.  */
+  void read_fixed_point (const gdb_byte *buf, int len,
+			 enum bfd_endian byte_order, bool unsigned_p,
+			 const gdb_mpq &scaling_factor)
+  {
+    gdb_mpq tmp_q;
+
+    tmp_q.read_fixed_point (buf, len, byte_order, unsigned_p, scaling_factor);
+    mpf_set_q (val, tmp_q.val);
+  }
+
+  /* The destructor.  */
+  ~gdb_mpf () { mpf_clear (val); }
+};
+
+/* See declaration above.  */
+
+template<typename T>
+void
+gdb_mpz::set (T src)
+{
+  mpz_import (val, 1 /* count */, -1 /* order */,
+	      sizeof (T) /* size */, 0 /* endian (0 = native) */,
+	      0 /* nails */, &src /* op */);
+  if (std::is_signed<T>::value && src < 0)
+    {
+      /* mpz_import does not handle the sign, so our value was imported
+	 as an unsigned. Adjust that imported value so as to make it
+	 the correct negative value.  */
+      gdb_mpz neg_offset;
+
+      mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
+      mpz_sub (val, val, neg_offset.val);
+    }
+}
+
+/* See declaration above.  */
+
+template<typename T>
+T
+gdb_mpz::as_integer () const
+{
+  /* Initialize RESULT, because mpz_export only write the minimum
+     number of bytes, including none if our value is zero!  */
+  T result = 0;
+
+  gdb_mpz exported_val (val);
+  if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
+    {
+      /* We want to use mpz_export to set the return value, but
+	 this function does not handle the sign. So give exported_val
+	 a value which is at the same time positive, and has the same
+	 bit representation as our negative value.  */
+      gdb_mpz neg_offset;
+
+      mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
+      mpz_add (exported_val.val, exported_val.val, neg_offset.val);
+    }
+
+  mpz_export (&result, NULL /* count */, -1 /* order */,
+	      sizeof (T) /* size */, 0 /* endian (0 = native) */,
+	      0 /* nails */, exported_val.val);
+  return result;
+}
+
+#endif
diff --git a/gdb/unittests/gmp-utils-selftests.c b/gdb/unittests/gmp-utils-selftests.c
new file mode 100644
index 0000000..e8c3c5c
--- /dev/null
+++ b/gdb/unittests/gmp-utils-selftests.c
@@ -0,0 +1,460 @@
+/* Self tests of the gmp-utils API.
+
+   Copyright (C) 2019-2020 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 "gmp-utils.h"
+#include "gdbsupport/selftest.h"
+
+#include <math.h>
+
+namespace selftests {
+
+/* Perform a series of general tests of gdb_mpz's as_integer method.
+
+   This function tries to be reasonably exhaustive, by testing the edges,
+   as well as a resonable set of values including negative ones, zero,
+   and positive values.  */
+
+static void
+gdb_mpz_as_integer ()
+{
+  /* Test a range of values, both as LONGEST and ULONGEST.  */
+  gdb_mpz v;
+  LONGEST l_expected;
+  ULONGEST ul_expected;
+
+  /* Start with the smallest LONGEST  */
+  l_expected = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
+
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
+  mpz_neg (v.val, v.val);
+
+  SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
+
+  /* Try with a small range of integers including negative, zero,
+     and positive values.  */
+  for (int i = -256; i <= 256; i++)
+    {
+      l_expected = (LONGEST) i;
+      mpz_set_si (v.val, i);
+      SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
+
+      if (i >= 0)
+	{
+	  ul_expected = (ULONGEST) i;
+	  mpz_set_ui (v.val, i);
+	  SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
+	}
+    }
+
+  /* Try with LONGEST_MAX.  */
+  l_expected = LONGEST_MAX;
+  ul_expected = (ULONGEST) l_expected;
+
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
+  mpz_sub_ui (v.val, v.val, 1);
+
+  SELF_CHECK (v.as_integer<LONGEST> () == l_expected);
+  SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
+
+  /* Try with ULONGEST_MAX.  */
+  ul_expected = ULONGEST_MAX;
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8);
+  mpz_sub_ui (v.val, v.val, 1);
+
+  SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
+}
+
+/* A helper function to store the given integer value into a buffer,
+   before reading it back into a gdb_mpz.  Sets ACTUAL to the value
+   read back, while at the same time setting EXPECTED as the value
+   we would expect to be read back.
+
+   Note that this function does not perform the comparison between
+   EXPECTED and ACTUAL.  The caller will do it inside a SELF_CHECK
+   call, allowing the line information shown when the test fails
+   to provide a bit more information about the kind of values
+   that were used when the check failed.  This makes the writing
+   of the tests a little more verbose, but the debugging in case
+   of problems should hopefuly be easier.  */
+
+template<typename T>
+void
+store_and_read_back (T val, int buf_len, enum bfd_endian byte_order,
+		     gdb_mpz &expected, gdb_mpz &actual)
+{
+  gdb_byte *buf;
+
+  expected = val;
+
+  buf = (gdb_byte *) alloca (buf_len);
+  store_integer (buf, buf_len, byte_order, val);
+
+  /* Pre-initialize ACTUAL to something that's not the expected value.  */
+  mpz_set (actual.val, expected.val);
+  mpz_sub_ui (actual.val, actual.val, 500);
+
+  actual.read (buf, buf_len, byte_order, !std::is_signed<T>::value);
+}
+
+/* Test the gdb_mpz::read method over a reasonable range of values.
+
+   The testing is done by picking an arbitrary buffer length, after
+   which we test every possible value that this buffer allows, both
+   with signed numbers as well as unsigned ones.  */
+
+static void
+gdb_mpz_read_all_from_small ()
+{
+  /* Start with a type whose size is small enough that we can afford
+     to check the complete range.  */
+
+  int buf_len = 1;
+  LONGEST l_min = -pow (2, buf_len * 8 - 1);
+  LONGEST l_max = pow (2, buf_len * 8 - 1) - 1;
+
+  for (LONGEST l = l_min; l <= l_max; l++)
+    {
+      gdb_mpz expected, actual;
+
+      store_and_read_back (l, buf_len, BFD_ENDIAN_BIG, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+      store_and_read_back (l, buf_len, BFD_ENDIAN_LITTLE, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+    }
+
+  /* Do the same as above, but with an unsigned type.  */
+  ULONGEST ul_min = 0;
+  ULONGEST ul_max = pow (2, buf_len * 8) - 1;
+
+  for (ULONGEST ul = ul_min; ul <= ul_max; ul++)
+    {
+      gdb_mpz expected, actual;
+
+      store_and_read_back (ul, buf_len, BFD_ENDIAN_BIG, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+      store_and_read_back (ul, buf_len, BFD_ENDIAN_LITTLE, expected, actual);
+      SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+    }
+}
+
+/* Test the gdb_mpz::read the extremes of LONGEST and ULONGEST.  */
+
+static void
+gdb_mpz_read_min_max ()
+{
+  gdb_mpz expected, actual;
+
+  /* Start with the smallest LONGEST.  */
+
+  LONGEST l_min = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
+
+  store_and_read_back (l_min, sizeof (LONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (l_min, sizeof (LONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  /* Same with LONGEST_MAX.  */
+
+  LONGEST l_max = LONGEST_MAX;
+
+  store_and_read_back (l_max, sizeof (LONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (l_max, sizeof (LONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  /* Same with the smallest ULONGEST.  */
+
+  ULONGEST ul_min = 0;
+
+  store_and_read_back (ul_min, sizeof (ULONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (ul_min, sizeof (ULONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  /* Same with ULONGEST_MAX.  */
+
+  ULONGEST ul_max = ULONGEST_MAX;
+
+  store_and_read_back (ul_max, sizeof (ULONGEST), BFD_ENDIAN_BIG,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+
+  store_and_read_back (ul_max, sizeof (ULONGEST), BFD_ENDIAN_LITTLE,
+		       expected, actual);
+  SELF_CHECK (mpz_cmp (actual.val, expected.val) == 0);
+}
+
+/* A helper function which creates a gdb_mpz object from the given
+   integer VAL, and then writes it using its gdb_mpz::write method.
+
+   The written value is then extracted from the buffer and returned,
+   for comparison with the original.
+
+   Note that this function does not perform the comparison between
+   VAL and the returned value.  The caller will do it inside a SELF_CHECK
+   call, allowing the line information shown when the test fails
+   to provide a bit more information about the kind of values
+   that were used when the check failed.  This makes the writing
+   of the tests a little more verbose, but the debugging in case
+   of problems should hopefuly be easier.  */
+
+template<typename T>
+T
+write_and_extract (T val, int buf_len, enum bfd_endian byte_order)
+{
+  gdb_mpz v (val);
+
+  SELF_CHECK (v.as_integer<T> () == val);
+
+  gdb_byte *buf = (gdb_byte *) alloca (buf_len);
+  v.write (buf, buf_len, byte_order, !std::is_signed<T>::value);
+
+  return extract_integer<T> (buf, buf_len, byte_order);
+}
+
+/* Test the gdb_mpz::write method over a reasonable range of values.
+
+   The testing is done by picking an arbitrary buffer length, after
+   which we test every possible value that this buffer allows.  */
+
+static void
+gdb_mpz_write_all_from_small ()
+{
+  int buf_len = 1;
+  LONGEST l_min = -pow (2, buf_len * 8 - 1);
+  LONGEST l_max = pow (2, buf_len * 8 - 1) - 1;
+
+  for (LONGEST l = l_min; l <= l_max; l++)
+    {
+      SELF_CHECK (write_and_extract (l, buf_len, BFD_ENDIAN_BIG) == l);
+      SELF_CHECK (write_and_extract (l, buf_len, BFD_ENDIAN_LITTLE) == l);
+    }
+
+    /* Do the same as above, but with an unsigned type.  */
+  ULONGEST ul_min = 0;
+  ULONGEST ul_max = pow (2, buf_len * 8) - 1;
+
+  for (ULONGEST ul = ul_min; ul <= ul_max; ul++)
+    {
+      SELF_CHECK (write_and_extract (ul, buf_len, BFD_ENDIAN_BIG) == ul);
+      SELF_CHECK (write_and_extract (ul, buf_len, BFD_ENDIAN_LITTLE) == ul);
+    }
+}
+
+/* Test the gdb_mpz::write the extremes of LONGEST and ULONGEST.  */
+
+static void
+gdb_mpz_write_min_max ()
+{
+  /* Start with the smallest LONGEST.  */
+
+  LONGEST l_min = (LONGEST) 1 << (sizeof (LONGEST) * 8 - 1);
+  SELF_CHECK (write_and_extract (l_min, sizeof (LONGEST), BFD_ENDIAN_BIG)
+	      == l_min);
+  SELF_CHECK (write_and_extract (l_min, sizeof (LONGEST), BFD_ENDIAN_LITTLE)
+	      == l_min);
+
+  /* Same with LONGEST_MAX.  */
+
+  LONGEST l_max = LONGEST_MAX;
+  SELF_CHECK (write_and_extract (l_max, sizeof (LONGEST), BFD_ENDIAN_BIG)
+	      == l_max);
+  SELF_CHECK (write_and_extract (l_max, sizeof (LONGEST), BFD_ENDIAN_LITTLE)
+	      == l_max);
+
+  /* Same with the smallest ULONGEST.  */
+
+  ULONGEST ul_min = (ULONGEST) 1 << (sizeof (ULONGEST) * 8 - 1);
+  SELF_CHECK (write_and_extract (ul_min, sizeof (ULONGEST), BFD_ENDIAN_BIG)
+	      == ul_min);
+  SELF_CHECK (write_and_extract (ul_min, sizeof (ULONGEST), BFD_ENDIAN_LITTLE)
+	      == ul_min);
+
+  /* Same with ULONGEST_MAX.  */
+
+  ULONGEST ul_max = ULONGEST_MAX;
+  SELF_CHECK (write_and_extract (ul_max, sizeof (ULONGEST), BFD_ENDIAN_BIG)
+	      == ul_max);
+  SELF_CHECK (write_and_extract (ul_max, sizeof (ULONGEST), BFD_ENDIAN_LITTLE)
+	      == ul_max);
+}
+
+/* A helper function which stores the signed number, the unscaled value
+   of a fixed point object, into a buffer, and then uses gdb_mpq's
+   read_fixed_point to read it as a fixed_point value, with
+   the given parameters.
+
+   EXPECTED is set to the value we expected to get after the call
+   to read_fixed_point.  ACTUAL is the value we actually do get.
+
+   Note that this function does not perform the comparison between
+   EXPECTED and ACTUAL.  The caller will do it inside a SELF_CHECK
+   call, allowing the line information shown when the test fails
+   to provide a bit more information about the kind of values
+   that were used when the check failed.  This makes the writing
+   of the tests a little more verbose, but the debugging in case
+   of problems should hopefuly be easier.  */
+
+static void
+read_fp_test (int unscaled, const gdb_mpq &scaling_factor,
+	      enum bfd_endian byte_order,
+	      gdb_mpq &expected, gdb_mpq &actual)
+{
+  /* For this kind of testing, we'll use a buffer the same size as
+     our unscaled parameter.  */
+  const int len = sizeof (unscaled);
+  gdb_byte buf[len];
+  store_signed_integer (buf, len, byte_order, unscaled);
+
+  actual.read_fixed_point (buf, len, byte_order, 0, scaling_factor);
+
+  mpq_set_si (expected.val, unscaled, 1);
+  mpq_mul (expected.val, expected.val, scaling_factor.val);
+}
+
+/* Perform various tests of the gdb_mpq::read_fixed_point method.  */
+
+static void
+gdb_mpq_read_fixed_point ()
+{
+  gdb_mpq expected, actual;
+  gdb_mpq scaling_factor;
+
+  /* Pick an arbitrary scaling_factor; this operation is trivial enough
+     thanks to GMP that the value we use isn't really important.  */
+  mpq_set_ui (scaling_factor.val, 3, 5);
+
+  /* Try a few values, both negative and positive... */
+
+  read_fp_test (-256, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (-256, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (-1, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (-1, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (0, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (0, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (1, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (1, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+
+  read_fp_test (1025, scaling_factor, BFD_ENDIAN_BIG, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+  read_fp_test (1025, scaling_factor, BFD_ENDIAN_LITTLE, expected, actual);
+  SELF_CHECK (mpq_cmp (actual.val, expected.val) == 0);
+}
+
+/* A helper function which builds a gdb_mpq object from the given
+   NUMERATOR and DENOMINATOR, and then calls gdb_mpq's write_fixed_point
+   method to write it to a buffer.
+
+   The value written into the buffer is then read back as is,
+   and returned.  */
+
+static LONGEST
+write_fp_test (int numerator, unsigned int denominator,
+	       const gdb_mpq &scaling_factor,
+	       enum bfd_endian byte_order)
+{
+  /* For this testing, we'll use a buffer the size of LONGEST.
+     This is really an arbitrary decision, as long as the buffer
+     is long enough to hold the unscaled values that we'll be
+     writing.  */
+  const int len = sizeof (LONGEST);
+  gdb_byte buf[len];
+  memset (buf, 0, len);
+
+  gdb_mpq v;
+  mpq_set_ui (v.val, numerator, denominator);
+  mpq_canonicalize (v.val);
+  v.write_fixed_point (buf, len, byte_order, 0, scaling_factor);
+
+  return extract_unsigned_integer (buf, len, byte_order);
+}
+
+/* Perform various tests of the gdb_mpq::write_fixed_point method.  */
+
+static void
+gdb_mpq_write_fixed_point ()
+{
+  /* Pick an arbitrary factor; this operations is sufficiently trivial
+     with the use of GMP that the value of this factor is not really
+     all that important.  */
+  gdb_mpq scaling_factor;
+  mpq_set_ui (scaling_factor.val, 1, 3);
+
+  gdb_mpq vq;
+
+  /* Try a few multiples of the scaling factor, both negative,
+     and positive... */
+
+  SELF_CHECK (write_fp_test (-8, 1, scaling_factor, BFD_ENDIAN_BIG) == -24);
+  SELF_CHECK (write_fp_test (-8, 1, scaling_factor, BFD_ENDIAN_LITTLE) == -24);
+
+  SELF_CHECK (write_fp_test (-2, 3, scaling_factor, BFD_ENDIAN_BIG) == -2);
+  SELF_CHECK (write_fp_test (-2, 3, scaling_factor, BFD_ENDIAN_LITTLE) == -2);
+
+  SELF_CHECK (write_fp_test (0, 3, scaling_factor, BFD_ENDIAN_BIG) == 0);
+  SELF_CHECK (write_fp_test (0, 3, scaling_factor, BFD_ENDIAN_LITTLE) == 0);
+
+  SELF_CHECK (write_fp_test (5, 3, scaling_factor, BFD_ENDIAN_BIG) == 5);
+  SELF_CHECK (write_fp_test (5, 3, scaling_factor, BFD_ENDIAN_LITTLE) == 5);
+}
+
+}
+
+void _initialize_gmp_utils_selftests ();
+
+void
+_initialize_gmp_utils_selftests ()
+{
+  selftests::register_test ("gdb_mpz_as_integer",
+			    selftests::gdb_mpz_as_integer);
+  selftests::register_test ("gdb_mpz_read_all_from_small",
+			    selftests::gdb_mpz_read_all_from_small);
+  selftests::register_test ("gdb_mpz_read_min_max",
+			    selftests::gdb_mpz_read_min_max);
+  selftests::register_test ("gdb_mpz_write_all_from_small",
+			    selftests::gdb_mpz_write_all_from_small);
+  selftests::register_test ("gdb_mpz_write_min_max",
+			    selftests::gdb_mpz_write_min_max);
+  selftests::register_test ("gdb_mpq_read_fixed_point",
+			    selftests::gdb_mpq_read_fixed_point);
+  selftests::register_test ("gdb_mpq_write_fixed_point",
+			    selftests::gdb_mpq_write_fixed_point);
+}
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [pushed/v2 4/9] Move uinteger_pow gdb/valarith.c to gdb/utils.c and make it public
  2020-11-15  8:35 ` pushed: " Joel Brobecker
                     ` (2 preceding siblings ...)
  2020-11-15  8:35   ` [pushed/v2 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects Joel Brobecker
@ 2020-11-15  8:35   ` Joel Brobecker
  2020-11-15  8:35   ` [pushed/v2 5/9] Add support for printing value of DWARF-based fixed-point type objects Joel Brobecker
                     ` (7 subsequent siblings)
  11 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This is a generic function which I would like to use in a followup
patch adding support for fixed-point types. So this commit moves it
out of valarith.c into util.c, and makes it non-static.

gdb/ChangeLog:

        * utils.h (uinteger_pow): Add declaration.
        * utils.c (uinteger_pow): Moved here (without changes)...
        * valarith.c (uinteger_pow): ... from here.
---
 gdb/ChangeLog  |  6 ++++++
 gdb/utils.c    | 30 ++++++++++++++++++++++++++++++
 gdb/utils.h    |  7 +++++++
 gdb/valarith.c | 31 -------------------------------
 4 files changed, 43 insertions(+), 31 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a029109..5aacbf0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,11 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* utils.h (uinteger_pow): Add declaration.
+	* utils.c (uinteger_pow): Moved here (without changes)...
+	* valarith.c (uinteger_pow): ... from here.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* gmp-utils.h,  gmp-utils.h: New file.
 	* unittests/gmp-utils-selftests.c: New file.
 	* Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
diff --git a/gdb/utils.c b/gdb/utils.c
index ab931c3..3226656 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -709,6 +709,36 @@ myread (int desc, char *addr, int len)
   return orglen;
 }
 
+/* See utils.h.  */
+
+ULONGEST
+uinteger_pow (ULONGEST v1, LONGEST v2)
+{
+  if (v2 < 0)
+    {
+      if (v1 == 0)
+	error (_("Attempt to raise 0 to negative power."));
+      else
+	return 0;
+    }
+  else
+    {
+      /* The Russian Peasant's Algorithm.  */
+      ULONGEST v;
+
+      v = 1;
+      for (;;)
+	{
+	  if (v2 & 1L)
+	    v *= v1;
+	  v2 >>= 1;
+	  if (v2 == 0)
+	    return v;
+	  v1 *= v1;
+	}
+    }
+}
+
 void
 print_spaces (int n, struct ui_file *file)
 {
diff --git a/gdb/utils.h b/gdb/utils.h
index 6948908..a8c65ed 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -593,6 +593,13 @@ extern pid_t wait_to_die_with_timeout (pid_t pid, int *status, int timeout);
 
 extern int myread (int, char *, int);
 
+/* Integer exponentiation: Return V1**V2, where both arguments
+   are integers.
+
+   Requires V1 != 0 if V2 < 0.
+   Returns 1 for 0 ** 0.  */
+extern ULONGEST uinteger_pow (ULONGEST v1, LONGEST v2);
+
 /* Resource limits used by getrlimit and setrlimit.  */
 
 enum resource_limit_kind
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 21b597a..f6caf3d 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -819,37 +819,6 @@ integer_pow (LONGEST v1, LONGEST v2)
     }
 }
 
-/* Integer exponentiation: V1**V2, where both arguments are
-   integers.  Requires V1 != 0 if V2 < 0.  Returns 1 for 0 ** 0.  */
-
-static ULONGEST
-uinteger_pow (ULONGEST v1, LONGEST v2)
-{
-  if (v2 < 0)
-    {
-      if (v1 == 0)
-	error (_("Attempt to raise 0 to negative power."));
-      else
-	return 0;
-    }
-  else 
-    {
-      /* The Russian Peasant's Algorithm.  */
-      ULONGEST v;
-      
-      v = 1;
-      for (;;)
-	{
-	  if (v2 & 1L) 
-	    v *= v1;
-	  v2 >>= 1;
-	  if (v2 == 0)
-	    return v;
-	  v1 *= v1;
-	}
-    }
-}
-
 /* Obtain argument values for binary operation, converting from
    other types if one of them is not floating point.  */
 static void
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [pushed/v2 5/9] Add support for printing value of DWARF-based fixed-point type objects
  2020-11-15  8:35 ` pushed: " Joel Brobecker
                     ` (3 preceding siblings ...)
  2020-11-15  8:35   ` [pushed/v2 4/9] Move uinteger_pow gdb/valarith.c to gdb/utils.c and make it public Joel Brobecker
@ 2020-11-15  8:35   ` Joel Brobecker
  2020-11-15  8:35   ` [pushed/v2 6/9] fix printing of DWARF fixed-point type objects with format modifier Joel Brobecker
                     ` (6 subsequent siblings)
  11 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This commit introduces a new kind of type, meant to describe
fixed-point types, using a new code added specifically for
this purpose (TYPE_CODE_FIXED_POINT).

It then adds handling of fixed-point base types in the DWARF reader.

And finally, as a first step, this commit adds support for printing
the value of fixed-point type objects.

Note that this commit has a known issue: Trying to print the value
of a fixed-point object with a format letter (e.g. "print /x NAME")
causes the wrong value to be printed because the scaling factor
is not applied. Since the fix for this issue is isolated, and
this is not a regression, the fix will be made in a pach of its own.
This is meant to simplify review and archeology.

Also, other functionalities related to fixed-point type handling
(ptype, arithmetics, etc), will be added piecemeal as well, for
the same reasons (faciliate reviews and archeology). Related to this,
the testcase gdb.ada/fixed_cmp.exp is adjusted to compile the test
program with -fgnat-encodings=all, so as to force the use of GNAT
encodings, rather than rely on the compiler's default to use them.
The intent is to enhance this testcase to also test the pure DWARF
approach using -fgnat-encodings=minimal as soon as the corresponding
suport gets added in. Thus, the modification to the testcase is made
in a way that it prepares this testcase to be tested in both modes.

gdb/ChangeLog:

        * ada-valprint.c (ada_value_print_1): Add fixed-point type handling.
        * dwarf2/read.c (get_dwarf2_rational_constant)
        (get_dwarf2_unsigned_rational_constant, finish_fixed_point_type)
        (has_zero_over_zero_small_attribute): New functions.
        read_base_type, set_die_type): Add fixed-point type handling.
        * gdb-gdb.py.in: Add fixed-point type handling.
        * gdbtypes.c: #include "gmp-utils.h".
        (create_range_type, set_type_code): Add fixed-point type handling.
        (init_fixed_point_type): New function.
        (is_integral_type, is_scalar_type): Add fixed-point type handling.
        (print_fixed_point_type_info): New function.
        (recursive_dump_type, copy_type_recursive): Add fixed-point type
        handling.
        (fixed_point_type_storage): New typedef.
        (fixed_point_objfile_key): New static global.
        (allocate_fixed_point_type_info, is_fixed_point_type): New functions.
        (fixed_point_type_base_type, fixed_point_scaling_factor): New
        functions.
        * gdbtypes.h: #include "gmp-utils.h".
        (enum type_code) <TYPE_SPECIFIC_FIXED_POINT>: New enum.
        (union type_specific) <fixed_point_info>: New field.
        (struct fixed_point_type_info): New struct.
        (INIT_FIXED_POINT_SPECIFIC, TYPE_FIXED_POINT_INFO): New macros.
        (init_fixed_point_type, is_fixed_point_type)
        (fixed_point_type_base_type, fixed_point_scaling_factor)
        (allocate_fixed_point_type_info): Add declarations.
        * valprint.c (generic_val_print_fixed_point): New function.
        (generic_value_print): Add fixed-point type handling.
        * value.c (value_as_address, unpack_long): Add fixed-point type
        handling.

gdb/testsuite/ChangeLog:

        * gdb.ada/fixed_cmp.exp: Force compilation to use -fgnat-encodings=all.
        * gdb.ada/fixed_points.exp: Add fixed-point variables printing tests.
        * gdb.ada/fixed_points/pck.ads, gdb.ada/fixed_points/pck.adb:
        New files.
        * gdb.ada/fixed_points/fixed_points.adb: Add use of package Pck.

        * gdb.dwarf2/dw2-fixed-point.c, gdb.dwarf2/dw2-fixed-point.exp:
        New files.
---
 gdb/ChangeLog                                      |  33 ++++
 gdb/ada-valprint.c                                 |   3 +
 gdb/dwarf2/read.c                                  | 211 +++++++++++++++++++++
 gdb/gdb-gdb.py.in                                  |   5 +
 gdb/gdbtypes.c                                     | 133 ++++++++++++-
 gdb/gdbtypes.h                                     |  53 +++++-
 gdb/testsuite/ChangeLog                            |  11 ++
 gdb/testsuite/gdb.ada/fixed_cmp.exp                |  34 ++--
 gdb/testsuite/gdb.ada/fixed_points.exp             |  11 ++
 .../gdb.ada/fixed_points/fixed_points.adb          |   4 +
 gdb/testsuite/gdb.ada/fixed_points/pck.adb         |  22 +++
 gdb/testsuite/gdb.ada/fixed_points/pck.ads         |  30 +++
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c         |  49 +++++
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp       | 132 +++++++++++++
 gdb/valprint.c                                     |  33 ++++
 gdb/value.c                                        |  14 ++
 16 files changed, 760 insertions(+), 18 deletions(-)
 create mode 100644 gdb/testsuite/gdb.ada/fixed_points/pck.adb
 create mode 100644 gdb/testsuite/gdb.ada/fixed_points/pck.ads
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 5aacbf0..16905ac 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,38 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* ada-valprint.c (ada_value_print_1): Add fixed-point type handling.
+	* dwarf2/read.c (get_dwarf2_rational_constant)
+	(get_dwarf2_unsigned_rational_constant, finish_fixed_point_type)
+	(has_zero_over_zero_small_attribute): New functions.
+	read_base_type, set_die_type): Add fixed-point type handling.
+	* gdb-gdb.py.in: Add fixed-point type handling.
+	* gdbtypes.c: #include "gmp-utils.h".
+	(create_range_type, set_type_code): Add fixed-point type handling.
+	(init_fixed_point_type): New function.
+	(is_integral_type, is_scalar_type): Add fixed-point type handling.
+	(print_fixed_point_type_info): New function.
+	(recursive_dump_type, copy_type_recursive): Add fixed-point type
+	handling.
+	(fixed_point_type_storage): New typedef.
+	(fixed_point_objfile_key): New static global.
+	(allocate_fixed_point_type_info, is_fixed_point_type): New functions.
+	(fixed_point_type_base_type, fixed_point_scaling_factor): New
+	functions.
+	* gdbtypes.h: #include "gmp-utils.h".
+	(enum type_code) <TYPE_SPECIFIC_FIXED_POINT>: New enum.
+	(union type_specific) <fixed_point_info>: New field.
+	(struct fixed_point_type_info): New struct.
+	(INIT_FIXED_POINT_SPECIFIC, TYPE_FIXED_POINT_INFO): New macros.
+	(init_fixed_point_type, is_fixed_point_type)
+	(fixed_point_type_base_type, fixed_point_scaling_factor)
+	(allocate_fixed_point_type_info): Add declarations.
+	* valprint.c (generic_val_print_fixed_point): New function.
+	(generic_value_print): Add fixed-point type handling.
+	* value.c (value_as_address, unpack_long): Add fixed-point type
+	handling.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* utils.h (uinteger_pow): Add declaration.
 	* utils.c (uinteger_pow): Moved here (without changes)...
 	* valarith.c (uinteger_pow): ... from here.
diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c
index d7704f0..482069a 100644
--- a/gdb/ada-valprint.c
+++ b/gdb/ada-valprint.c
@@ -1027,6 +1027,9 @@ ada_value_print_1 (struct value *val, struct ui_file *stream, int recurse,
       deprecated_set_value_type (val, type);
     }
 
+  if (is_fixed_point_type (type))
+    type = fixed_point_type_base_type (type);
+
   switch (type->code ())
     {
     default:
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 1b43fc8..3c5982629 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -18092,6 +18092,157 @@ read_typedef (struct die_info *die, struct dwarf2_cu *cu)
   return this_type;
 }
 
+/* Assuming DIE is a rational DW_TAG_constant, read the DIE's
+   numerator and denominator into NUMERATOR and DENOMINATOR (resp).
+
+   If the numerator and/or numerator attribute is missing,
+   a complaint is filed, and NUMERATOR and DENOMINATOR are left
+   untouched.  */
+
+static void
+get_dwarf2_rational_constant (struct die_info *die, struct dwarf2_cu *cu,
+			      LONGEST *numerator, LONGEST *denominator)
+{
+  struct attribute *num_attr, *denom_attr;
+
+  num_attr = dwarf2_attr (die, DW_AT_GNU_numerator, cu);
+  if (num_attr == nullptr)
+    complaint (_("DW_AT_GNU_numerator missing in %s DIE at %s"),
+	       dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
+
+  denom_attr = dwarf2_attr (die, DW_AT_GNU_denominator, cu);
+  if (denom_attr == nullptr)
+    complaint (_("DW_AT_GNU_denominator missing in %s DIE at %s"),
+	       dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
+
+  if (num_attr == nullptr || denom_attr == nullptr)
+    return;
+
+  *numerator = num_attr->constant_value (1);
+  *denominator = denom_attr->constant_value (1);
+}
+
+/* Same as get_dwarf2_rational_constant, but extracting an unsigned
+   rational constant, rather than a signed one.
+
+   If the rational constant has a negative value, a complaint
+   is filed, and NUMERATOR and DENOMINATOR are left untouched.  */
+
+static void
+get_dwarf2_unsigned_rational_constant (struct die_info *die,
+				       struct dwarf2_cu *cu,
+				       ULONGEST *numerator,
+				       ULONGEST *denominator)
+{
+  LONGEST num = 1, denom = 1;
+
+  get_dwarf2_rational_constant (die, cu, &num, &denom);
+  if (num < 0 && denom < 0)
+    {
+      num = -num;
+      denom = -denom;
+    }
+  else if (num < 0)
+    {
+      complaint (_("unexpected negative value for DW_AT_GNU_numerator"
+		   " in DIE at %s"),
+		 sect_offset_str (die->sect_off));
+      return;
+    }
+  else if (denom < 0)
+    {
+      complaint (_("unexpected negative value for DW_AT_GNU_denominator"
+		   " in DIE at %s"),
+		 sect_offset_str (die->sect_off));
+      return;
+    }
+
+  *numerator = num;
+  *denominator = denom;
+}
+
+/* Assuming DIE corresponds to a fixed point type, finish the creation
+   of the corresponding TYPE by setting its TYPE_FIXED_POINT_INFO.
+   CU is the DIE's CU.  */
+
+static void
+finish_fixed_point_type (struct type *type, struct die_info *die,
+			 struct dwarf2_cu *cu)
+{
+  struct attribute *attr;
+  /* Numerator and denominator of our fixed-point type's scaling factor.
+     The default is a scaling factor of 1, which we use as a fallback
+     when we are not able to decode it (problem with the debugging info,
+     unsupported forms, bug in GDB, etc...).  Using that as the default
+     allows us to at least print the unscaled value, which might still
+     be useful to a user.  */
+  ULONGEST scale_num = 1;
+  ULONGEST scale_denom = 1;
+
+  gdb_assert (type->code () == TYPE_CODE_FIXED_POINT
+	      && TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_FIXED_POINT);
+
+  attr = dwarf2_attr (die, DW_AT_binary_scale, cu);
+  if (!attr)
+    attr = dwarf2_attr (die, DW_AT_decimal_scale, cu);
+  if (!attr)
+    attr = dwarf2_attr (die, DW_AT_small, cu);
+
+  if (attr == nullptr)
+    {
+      /* Scaling factor not found.  Assume a scaling factor of 1,
+	 and hope for the best.  At least the user will be able to see
+	 the encoded value.  */
+      complaint (_("no scale found for fixed-point type (DIE at %s)"),
+		 sect_offset_str (die->sect_off));
+    }
+  else if (attr->name == DW_AT_binary_scale)
+    {
+      LONGEST scale_exp = attr->constant_value (0);
+      ULONGEST *num_or_denom = scale_exp > 0 ? &scale_num : &scale_denom;
+
+      *num_or_denom = 1 << abs (scale_exp);
+    }
+  else if (attr->name == DW_AT_decimal_scale)
+    {
+      LONGEST scale_exp = attr->constant_value (0);
+      ULONGEST *num_or_denom = scale_exp > 0 ? &scale_num : &scale_denom;
+
+      *num_or_denom = uinteger_pow (10, abs (scale_exp));
+    }
+  else if (attr->name == DW_AT_small)
+    {
+      struct die_info *scale_die;
+      struct dwarf2_cu *scale_cu = cu;
+
+      scale_die = follow_die_ref (die, attr, &scale_cu);
+      if (scale_die->tag == DW_TAG_constant)
+	get_dwarf2_unsigned_rational_constant (scale_die, scale_cu,
+					       &scale_num, &scale_denom);
+      else
+	complaint (_("%s DIE not supported as target of DW_AT_small attribute"
+		     " (DIE at %s)"),
+		   dwarf_tag_name (die->tag), sect_offset_str (die->sect_off));
+    }
+  else
+    {
+      complaint (_("unsupported scale attribute %s for fixed-point type"
+		   " (DIE at %s)"),
+		 dwarf_attr_name (attr->name),
+		 sect_offset_str (die->sect_off));
+    }
+
+  gdb_mpq &scaling_factor = TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+
+  gdb_mpz tmp_z (scale_num);
+  mpz_set (mpq_numref (scaling_factor.val), tmp_z.val);
+
+  tmp_z = scale_denom;
+  mpz_set (mpq_denref (scaling_factor.val), tmp_z.val);
+
+  mpq_canonicalize (scaling_factor.val);
+}
+
 /* Allocate a floating-point type of size BITS and name NAME.  Pass NAME_HINT
    (which may be different from NAME) to the architecture back-end to allow
    it to guess the correct format if necessary.  */
@@ -18133,6 +18284,32 @@ dwarf2_init_integer_type (struct dwarf2_cu *cu, struct objfile *objfile,
   return type;
 }
 
+/* Return true if DIE has a DW_AT_small attribute whose value is
+   a constant rational, where both the numerator and denominator
+   are equal to zero.
+
+   CU is the DIE's Compilation Unit.  */
+
+static bool
+has_zero_over_zero_small_attribute (struct die_info *die,
+				    struct dwarf2_cu *cu)
+{
+  struct attribute *attr = dwarf2_attr (die, DW_AT_small, cu);
+  if (attr == nullptr)
+    return false;
+
+  struct dwarf2_cu *scale_cu = cu;
+  struct die_info *scale_die
+    = follow_die_ref (die, attr, &scale_cu);
+
+  if (scale_die->tag != DW_TAG_constant)
+    return false;
+
+  LONGEST num = 1, denom = 1;
+  get_dwarf2_rational_constant (scale_die, cu, &num, &denom);
+  return (num == 0 && denom == 0);
+}
+
 /* Initialise and return a floating point type of size BITS suitable for
    use as a component of a complex number.  The NAME_HINT is passed through
    when initialising the floating point type and is the name of the complex
@@ -18243,6 +18420,31 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
 	}
     }
 
+  if ((encoding == DW_ATE_signed_fixed || encoding == DW_ATE_unsigned_fixed)
+      && cu->language == language_ada
+      && has_zero_over_zero_small_attribute (die, cu))
+    {
+      /* brobecker/2018-02-24: This is a fixed point type for which
+	 the scaling factor is represented as fraction whose value
+	 does not make sense (zero divided by zero), so we should
+	 normally never see these.  However, there is a small category
+	 of fixed point types for which GNAT is unable to provide
+	 the scaling factor via the standard DWARF mechanisms, and
+	 for which the info is provided via the GNAT encodings instead.
+	 This is likely what this DIE is about.
+
+	 Ideally, GNAT should be declaring this type the same way
+	 it declares other fixed point types when using the legacy
+	 GNAT encoding, which is to use a simple signed or unsigned
+	 base type.  A report to the GNAT team has been created to
+	 look into it.  In the meantime, pretend this type is a simple
+	 signed or unsigned integral, rather than a fixed point type,
+	 to avoid any confusion later on as to how to process this type.  */
+      encoding = (encoding == DW_ATE_signed_fixed
+		  ? DW_ATE_signed
+		  : DW_ATE_unsigned);
+    }
+
   switch (encoding)
     {
       case DW_ATE_address:
@@ -18319,6 +18521,14 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
 	  return set_die_type (die, type, cu);
 	}
 	break;
+      case DW_ATE_signed_fixed:
+	type = init_fixed_point_type (objfile, bits, 0, name);
+	finish_fixed_point_type (type, die, cu);
+	break;
+      case DW_ATE_unsigned_fixed:
+	type = init_fixed_point_type (objfile, bits, 1, name);
+	finish_fixed_point_type (type, die, cu);
+	break;
 
       default:
 	complaint (_("unsupported DW_AT_encoding: '%s'"),
@@ -24751,6 +24961,7 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
       && type->code () != TYPE_CODE_METHODPTR
       && type->code () != TYPE_CODE_MEMBERPTR
       && type->code () != TYPE_CODE_METHOD
+      && type->code () != TYPE_CODE_FIXED_POINT
       && !HAVE_GNAT_AUX_INFO (type))
     INIT_GNAT_SPECIFIC (type);
 
diff --git a/gdb/gdb-gdb.py.in b/gdb/gdb-gdb.py.in
index 6594ac1..ff68bd7 100644
--- a/gdb/gdb-gdb.py.in
+++ b/gdb/gdb-gdb.py.in
@@ -229,6 +229,11 @@ class StructMainTypePrettyPrinter:
             # tail_call_list is not printed.
         elif type_specific_kind == "TYPE_SPECIFIC_SELF_TYPE":
             img = "self_type = %s" % type_specific['self_type']
+        elif type_specific_kind == "TYPE_SPECIFIC_FIXED_POINT":
+            # The scaling factor is an opaque structure, so we cannot
+            # decode its value from Python (not without insider knowledge).
+            img = ('scaling_factor: <opaque> (call __gmpz_dump with '
+                   ' _mp_num and _mp_den fields if needed)')
         else:
             img = ("type_specific = ??? (unknown type_secific_kind: %s)"
                    % type_specific_kind)
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 686edaf..2f92887 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -40,6 +40,7 @@
 #include "gdbcore.h"
 #include "floatformat.h"
 #include <algorithm>
+#include "gmp-utils.h"
 
 /* Initialize BADNESS constants.  */
 
@@ -950,6 +951,8 @@ create_range_type (struct type *result_type, struct type *index_type,
 
   result_type->set_bounds (bounds);
 
+  if (index_type->code () == TYPE_CODE_FIXED_POINT)
+    result_type->set_is_unsigned (index_type->is_unsigned ());
   /* Note that the signed-ness of a range type can't simply be copied
      from the underlying type.  Consider a case where the underlying
      type is 'int', but the range type can hold 0..65535, and where
@@ -957,7 +960,7 @@ create_range_type (struct type *result_type, struct type *index_type,
      case, if we copy the underlying type's sign, then reading some
      range values will cause an unwanted sign extension.  So, we have
      some heuristics here instead.  */
-  if (low_bound->kind () == PROP_CONST && low_bound->const_val () >= 0)
+  else if (low_bound->kind () == PROP_CONST && low_bound->const_val () >= 0)
     result_type->set_is_unsigned (true);
   /* Ada allows the declaration of range types whose upper bound is
      less than the lower bound, so checking the lower bound is not
@@ -3136,6 +3139,9 @@ set_type_code (struct type *type, enum type_code code)
 	break;
       case TYPE_CODE_FUNC:
 	INIT_FUNC_SPECIFIC (type);
+        break;
+      case TYPE_CODE_FIXED_POINT:
+	INIT_FIXED_POINT_SPECIFIC (type);
 	break;
     }
 }
@@ -3352,6 +3358,24 @@ init_pointer_type (struct objfile *objfile,
   return t;
 }
 
+/* Allocate a TYPE_CODE_FIXED_POINT type structure associated with OBJFILE.
+   BIT is the pointer type size in bits.
+   UNSIGNED_P should be nonzero if the type is unsigned.
+   NAME is the type name.  */
+
+struct type *
+init_fixed_point_type (struct objfile *objfile,
+		       int bit, int unsigned_p, const char *name)
+{
+  struct type *t;
+
+  t = init_type (objfile, TYPE_CODE_FIXED_POINT, bit, name);
+  if (unsigned_p)
+    t->set_is_unsigned (true);
+
+  return t;
+}
+
 /* See gdbtypes.h.  */
 
 unsigned
@@ -3498,6 +3522,7 @@ is_integral_type (struct type *t)
   t = check_typedef (t);
   return
     ((t != NULL)
+     && !is_fixed_point_type (t)
      && ((t->code () == TYPE_CODE_INT)
 	 || (t->code () == TYPE_CODE_ENUM)
 	 || (t->code () == TYPE_CODE_FLAGS)
@@ -3523,6 +3548,9 @@ is_scalar_type (struct type *type)
 {
   type = check_typedef (type);
 
+  if (is_fixed_point_type (type))
+    return 0; /* Implemented as a scalar, but more like a floating point.  */
+
   switch (type->code ())
     {
     case TYPE_CODE_ARRAY:
@@ -4887,6 +4915,16 @@ print_gnat_stuff (struct type *type, int spaces)
     }
 }
 
+/* Print the contents of the TYPE's type_specific union, assuming that
+   its type-specific kind is TYPE_SPECIFIC_FIXED_POINT.  */
+
+static void
+print_fixed_point_type_info (struct type *type, int spaces)
+{
+  printfi_filtered (spaces + 2, "scaling factor: %s\n",
+		    fixed_point_scaling_factor (type).str ().get ());
+}
+
 static struct obstack dont_print_type_obstack;
 
 /* Print the dynamic_prop PROP.  */
@@ -5025,6 +5063,9 @@ recursive_dump_type (struct type *type, int spaces)
     case TYPE_CODE_NAMESPACE:
       printf_filtered ("(TYPE_CODE_NAMESPACE)");
       break;
+    case TYPE_CODE_FIXED_POINT:
+      printf_filtered ("(TYPE_CODE_FIXED_POINT)");
+      break;
     default:
       printf_filtered ("(UNKNOWN TYPE CODE)");
       break;
@@ -5217,6 +5258,12 @@ recursive_dump_type (struct type *type, int spaces)
 	puts_filtered ("\n");
 	break;
 
+      case TYPE_SPECIFIC_FIXED_POINT:
+	printfi_filtered (spaces, "fixed_point_info ");
+	print_fixed_point_type_info (type, spaces);
+	puts_filtered ("\n");
+	break;
+
     case TYPE_SPECIFIC_INT:
       if (type->bit_size_differs_p ())
 	{
@@ -5449,6 +5496,11 @@ copy_type_recursive (struct objfile *objfile,
 			  copy_type_recursive (objfile, TYPE_SELF_TYPE (type),
 					       copied_types));
       break;
+    case TYPE_SPECIFIC_FIXED_POINT:
+      INIT_FIXED_POINT_SPECIFIC (new_type);
+      TYPE_FIXED_POINT_INFO (new_type)->scaling_factor
+	= TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+      break;
     case TYPE_SPECIFIC_INT:
       TYPE_SPECIFIC_FIELD (new_type) = TYPE_SPECIFIC_INT;
       TYPE_MAIN_TYPE (new_type)->type_specific.int_stuff
@@ -5752,6 +5804,85 @@ append_composite_type_field (struct type *t, const char *name,
   append_composite_type_field_aligned (t, name, field, 0);
 }
 
+\f
+
+/* We manage the lifetimes of fixed_point_type_info objects by
+   attaching them to the objfile.  Currently, these objects are
+   modified during construction, and GMP does not provide a way to
+   hash the contents of an mpq_t; so it's a bit of a pain to hash-cons
+   them.  If we did do this, they could be moved to the per-BFD and
+   shared across objfiles.  */
+typedef std::vector<std::unique_ptr<fixed_point_type_info>>
+    fixed_point_type_storage;
+
+/* Key used for managing the storage of fixed-point type info.  */
+static const struct objfile_key<fixed_point_type_storage>
+    fixed_point_objfile_key;
+
+/* See gdbtypes.h.  */
+
+fixed_point_type_info *
+allocate_fixed_point_type_info (struct type *type)
+{
+  std::unique_ptr<fixed_point_type_info> up (new fixed_point_type_info);
+  fixed_point_type_info *result;
+
+  if (TYPE_OBJFILE_OWNED (type))
+    {
+      fixed_point_type_storage *storage
+	= fixed_point_objfile_key.get (TYPE_OBJFILE (type));
+      if (storage == nullptr)
+	storage = fixed_point_objfile_key.emplace (TYPE_OBJFILE (type));
+      result = up.get ();
+      storage->push_back (std::move (up));
+    }
+  else
+    {
+      /* We just leak the memory, because that's what we do generally
+	 for non-objfile-attached types.  */
+      result = up.release ();
+    }
+
+  return result;
+}
+
+/* See gdbtypes.h.  */
+
+bool
+is_fixed_point_type (struct type *type)
+{
+  while (check_typedef (type)->code () == TYPE_CODE_RANGE)
+    type = TYPE_TARGET_TYPE (check_typedef (type));
+  type = check_typedef (type);
+
+  return type->code () == TYPE_CODE_FIXED_POINT;
+}
+
+/* See gdbtypes.h.  */
+
+struct type *
+fixed_point_type_base_type (struct type *type)
+{
+  while (check_typedef (type)->code () == TYPE_CODE_RANGE)
+    type = TYPE_TARGET_TYPE (check_typedef (type));
+  type = check_typedef (type);
+
+  gdb_assert (type->code () == TYPE_CODE_FIXED_POINT);
+  return type;
+}
+
+/* See gdbtypes.h.  */
+
+const gdb_mpq &
+fixed_point_scaling_factor (struct type *type)
+{
+  type = fixed_point_type_base_type (type);
+
+  return TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+}
+
+\f
+
 static struct gdbarch_data *gdbtypes_data;
 
 const struct builtin_type *
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 4d574e2..5f9ac27 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -52,6 +52,7 @@
 #include "gdbsupport/print-utils.h"
 #include "dwarf2.h"
 #include "gdb_obstack.h"
+#include "gmp-utils.h"
 
 /* Forward declarations for prototypes.  */
 struct field;
@@ -189,7 +190,10 @@ enum type_code
     TYPE_CODE_INTERNAL_FUNCTION,
 
     /* * Methods implemented in extension languages.  */
-    TYPE_CODE_XMETHOD
+    TYPE_CODE_XMETHOD,
+
+    /* * Fixed Point type.  */
+    TYPE_CODE_FIXED_POINT,
   };
 
 /* * Some bits for the type's instance_flags word.  See the macros
@@ -600,7 +604,8 @@ enum type_specific_kind
   /* Note: This is used by TYPE_CODE_FUNC and TYPE_CODE_METHOD.  */
   TYPE_SPECIFIC_FUNC,
   TYPE_SPECIFIC_SELF_TYPE,
-  TYPE_SPECIFIC_INT
+  TYPE_SPECIFIC_INT,
+  TYPE_SPECIFIC_FIXED_POINT,
 };
 
 union type_owner
@@ -766,6 +771,10 @@ union type_specific
 
   struct type *self_type;
 
+  /* * For TYPE_CODE_FIXED_POINT types, the info necessary to decode
+     values of that type.  */
+  struct fixed_point_type_info *fixed_point_info;
+
   /* * An integer-like scalar type may be stored in just part of its
      enclosing storage bytes.  This structure describes this
      situation.  */
@@ -1678,6 +1687,14 @@ struct call_site
     struct call_site_parameter parameter[1];
   };
 
+/* The type-specific info for TYPE_CODE_FIXED_POINT types.  */
+
+struct fixed_point_type_info
+{
+  /* The fixed point type's scaling factor.  */
+  gdb_mpq scaling_factor;
+};
+
 /* * The default value of TYPE_CPLUS_SPECIFIC(T) points to this shared
    static structure.  */
 
@@ -1725,6 +1742,13 @@ extern void allocate_gnat_aux_type (struct type *);
      TYPE_ZALLOC (type,							       \
 		  sizeof (*TYPE_MAIN_TYPE (type)->type_specific.func_stuff)))
 
+/* "struct fixed_point_type_info" has a field that has a destructor.
+   See allocate_fixed_point_type_info to understand how this is
+   handled.  */
+#define INIT_FIXED_POINT_SPECIFIC(type) \
+  (TYPE_SPECIFIC_FIELD (type) = TYPE_SPECIFIC_FIXED_POINT, \
+   TYPE_FIXED_POINT_INFO (type) = allocate_fixed_point_type_info (type))
+
 #define TYPE_MAIN_TYPE(thistype) (thistype)->main_type
 #define TYPE_TARGET_TYPE(thistype) TYPE_MAIN_TYPE(thistype)->target_type
 #define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type
@@ -1821,6 +1845,9 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
   (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits == NULL ? 0 \
     : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index)))
 
+#define TYPE_FIXED_POINT_INFO(thistype) \
+  (TYPE_MAIN_TYPE(thistype)->type_specific.fixed_point_info)
+
 #define FIELD_NAME(thisfld) ((thisfld).name)
 #define FIELD_LOC_KIND(thisfld) ((thisfld).loc_kind)
 #define FIELD_BITPOS_LVAL(thisfld) ((thisfld).loc.bitpos)
@@ -2192,6 +2219,8 @@ extern struct type *init_decfloat_type (struct objfile *, int, const char *);
 extern struct type *init_complex_type (const char *, struct type *);
 extern struct type *init_pointer_type (struct objfile *, int, const char *,
 				       struct type *);
+extern struct type *init_fixed_point_type (struct objfile *, int, int,
+					   const char *);
 
 /* Helper functions to construct architecture-owned types.  */
 extern struct type *arch_type (struct gdbarch *, enum type_code, int,
@@ -2529,6 +2558,26 @@ extern int type_not_allocated (const struct type *type);
 
 extern int type_not_associated (const struct type *type);
 
+/* Return True if TYPE is a TYPE_CODE_FIXED_POINT or if TYPE is
+   a range type whose base type is a TYPE_CODE_FIXED_POINT.  */
+extern bool is_fixed_point_type (struct type *type);
+
+/* Assuming that TYPE is a fixed point type, return its base type.
+
+   In other words, this returns the type after having peeled all
+   intermediate type layers (such as TYPE_CODE_RANGE, for instance).
+   The TYPE_CODE of the type returned is guaranteed to be
+   a TYPE_CODE_FIXED_POINT.  */
+extern struct type *fixed_point_type_base_type (struct type *type);
+
+/* Given TYPE, which is a fixed point type, return its scaling factor.  */
+extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);
+
+/* Allocate a fixed-point type info for TYPE.  This should only be
+   called by INIT_FIXED_POINT_SPECIFIC.  */
+extern fixed_point_type_info *allocate_fixed_point_type_info
+  (struct type *type);
+
 /* * When the type includes explicit byte ordering, return that.
    Otherwise, the byte ordering from gdbarch_byte_order for 
    get_type_arch is returned.  */
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index b1a8f8f..0f629bd 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,14 @@
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
+	* gdb.ada/fixed_cmp.exp: Force compilation to use -fgnat-encodings=all.
+	* gdb.ada/fixed_points.exp: Add fixed-point variables printing tests.
+	* gdb.ada/fixed_points/pck.ads, gdb.ada/fixed_points/pck.adb:
+	New files.
+	* gdb.ada/fixed_points/fixed_points.adb: Add use of package Pck.
+
+	* gdb.dwarf2/dw2-fixed-point.c, gdb.dwarf2/dw2-fixed-point.exp:
+	New files.
+
 2020-11-14  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	PR cli/26879
diff --git a/gdb/testsuite/gdb.ada/fixed_cmp.exp b/gdb/testsuite/gdb.ada/fixed_cmp.exp
index 38e41c4..cfdbb1c 100644
--- a/gdb/testsuite/gdb.ada/fixed_cmp.exp
+++ b/gdb/testsuite/gdb.ada/fixed_cmp.exp
@@ -19,25 +19,29 @@ if { [skip_ada_tests] } { return -1 }
 
 standard_ada_testfile fixed
 
-if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug ]] != "" } {
-  return -1
-}
+foreach_with_prefix gnat_encodings {all} {
+    set flags [list debug additional_flags=-fgnat-encodings=$gnat_encodings]
+
+    if {[gdb_compile_ada "${srcfile}" "${binfile}" executable $flags] != "" } {
+      return -1
+    }
 
-clean_restart ${testfile}
+    clean_restart ${testfile}
 
-set bp_location [gdb_get_line_number "STOP" ${testdir}/fixed.adb]
-runto "fixed.adb:$bp_location"
+    set bp_location [gdb_get_line_number "STOP" ${testdir}/fixed.adb]
+    runto "fixed.adb:$bp_location"
 
-gdb_test "print My_Var > 10.0" \
-         "= true"
+    gdb_test "print My_Var > 10.0" \
+             "= true"
 
-gdb_test "print My_Var > 20.0" \
-         "= false"
+    gdb_test "print My_Var > 20.0" \
+             "= false"
 
-# Do the same, but with integer values.
+    # Do the same, but with integer values.
 
-gdb_test "print My_Var > 10" \
-         "= true"
+    gdb_test "print My_Var > 10" \
+             "= true"
 
-gdb_test "print My_Var > 20" \
-         "= false"
+    gdb_test "print My_Var > 20" \
+             "= false"
+}
diff --git a/gdb/testsuite/gdb.ada/fixed_points.exp b/gdb/testsuite/gdb.ada/fixed_points.exp
index f991f56..655ee95 100644
--- a/gdb/testsuite/gdb.ada/fixed_points.exp
+++ b/gdb/testsuite/gdb.ada/fixed_points.exp
@@ -49,3 +49,14 @@ gdb_test "print Overprecise_Object" \
 
 gdb_test "ptype Overprecise_Object" \
          "= delta 0.135791"
+
+# FP*_Var...
+
+gdb_test "print fp1_var" \
+         " = 0.25"
+
+gdb_test "print fp2_var" \
+         " = -0.01"
+
+gdb_test "print fp3_var" \
+         " = 0.1"
diff --git a/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb b/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb
index a2720e3..f0a34ba 100644
--- a/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb
+++ b/gdb/testsuite/gdb.ada/fixed_points/fixed_points.adb
@@ -14,6 +14,7 @@
 --  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 with System;
+with Pck; use Pck;
 
 procedure Fixed_Points is
 
@@ -59,4 +60,7 @@ begin
    Subtype_Object := 1.0/16.0;
    New_Type_Object := 1.0/16.0;
    Overprecise_Object := Overprecise_Fixed_Point'Small * 2;
+   Do_Nothing (FP1_Var'Address);
+   Do_Nothing (FP2_Var'Address);
+   Do_Nothing (FP3_Var'Address);
 end Fixed_Points;
diff --git a/gdb/testsuite/gdb.ada/fixed_points/pck.adb b/gdb/testsuite/gdb.ada/fixed_points/pck.adb
new file mode 100644
index 0000000..16f0384
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/fixed_points/pck.adb
@@ -0,0 +1,22 @@
+--  Copyright 2016-2020 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/>.
+
+package body Pck is
+   procedure Do_Nothing (A : System.Address) is
+   begin
+      null;
+   end Do_Nothing;
+end pck;
+
diff --git a/gdb/testsuite/gdb.ada/fixed_points/pck.ads b/gdb/testsuite/gdb.ada/fixed_points/pck.ads
new file mode 100644
index 0000000..4d900dc
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/fixed_points/pck.ads
@@ -0,0 +1,30 @@
+--  Copyright 2016-2020 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/>.
+
+with System;
+
+package Pck is
+   type FP1_Type is delta 0.1 range -1.0 .. +1.0;
+   FP1_Var : FP1_Type := 0.25;
+
+   type FP2_Type is delta 0.01 digits 14;
+   FP2_Var : FP2_Type := -0.01;
+
+   type FP3_Type is delta 0.1 range 0.0 .. 1.0 with Small => 0.1/3.0;
+   FP3_Var : FP3_Type := 0.1;
+
+   procedure Do_Nothing (A : System.Address);
+end pck;
+
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
new file mode 100644
index 0000000..d9c811c
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
@@ -0,0 +1,49 @@
+/* Copyright 2016-2020 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 <stdint.h>
+
+/* Simulate an Ada variable declared inside package Pck as follow:
+      type FP1_Type is delta 0.1 range -1.0 .. +1.0;
+      FP1_Var : FP1_Type := 0.25;  */
+int8_t pck__fp1_var = 4;
+
+/* Simulate an Ada variable declared inside package Pck as follow:
+      type FP2_Type is delta 0.01 digits 14;
+      FP2_Var : FP2_Type := -0.01;  */
+int32_t pck__fp2_var = -1;
+
+/* Simulate an Ada variable declared inside package Pck as follow:
+      type FP3_Type is delta 0.1 range 0.0 .. 1.0 with Small => 0.1/3.0;
+      FP3_Var : FP3_Type := 0.1;  */
+int8_t pck__fp3_var = 3;
+
+/* Simulate an Ada variable declared inside package Pck as follow:
+      type FP1_Type is delta 0.1 range -1.0 .. +1.0;
+      FP1_Var : FP1_Type := 1.0;  */
+int8_t pck__fp1_range_var = 16;
+
+int
+main (void)
+{
+  pck__fp1_var++;
+  pck__fp2_var++;
+  pck__fp3_var++;
+  pck__fp1_range_var++;
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
new file mode 100644
index 0000000..bf88ffe
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
@@ -0,0 +1,132 @@
+# Copyright 2016-2020 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/>.
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+standard_testfile dw2-fixed-point.c dw2-fixed-point-dw.S
+
+# Make some DWARF for the test.
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    cu {} {
+ 	DW_TAG_compile_unit {
+                {DW_AT_language @DW_LANG_Ada95}
+                {DW_AT_name     pck.ads}
+                {DW_AT_comp_dir /tmp}
+        } {
+            declare_labels fp1_base_type fp2_base_type fp3_small \
+                fp3_base_type fp1_range_type
+
+            fp1_base_type: DW_TAG_base_type {
+                {DW_AT_byte_size     1 DW_FORM_sdata}
+                {DW_AT_encoding      @DW_ATE_signed_fixed}
+                {DW_AT_name          pck__fp1_type}
+                {DW_AT_binary_scale  -4 DW_FORM_sdata}
+            }
+
+            DW_TAG_variable {
+                {DW_AT_name pck__fp1_var}
+                {DW_AT_type :$fp1_base_type}
+                {DW_AT_location {
+                    DW_OP_addr [gdb_target_symbol pck__fp1_var]
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+
+            fp2_base_type: DW_TAG_base_type {
+                {DW_AT_byte_size     1 DW_FORM_sdata}
+                {DW_AT_encoding      @DW_ATE_signed_fixed}
+                {DW_AT_name          pck__fp2_type}
+                {DW_AT_decimal_scale -2 DW_FORM_sdata}
+            }
+
+            DW_TAG_variable {
+                {DW_AT_name pck__fp2_var}
+                {DW_AT_type :$fp2_base_type}
+                {DW_AT_location {
+                    DW_OP_addr [gdb_target_symbol pck__fp2_var]
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+
+            fp3_small: DW_TAG_constant {
+                {DW_AT_GNU_numerator   1 DW_FORM_data1}
+                {DW_AT_GNU_denominator 30 DW_FORM_sdata}
+            }
+
+            fp3_base_type: DW_TAG_base_type {
+                {DW_AT_byte_size     1 DW_FORM_sdata}
+                {DW_AT_encoding      @DW_ATE_signed_fixed}
+                {DW_AT_name          pck__fp3_type}
+                {DW_AT_small         :$fp3_small}
+            }
+
+            DW_TAG_variable {
+                {DW_AT_name pck__fp3_var}
+                {DW_AT_type :$fp3_base_type}
+                {DW_AT_location {
+                    DW_OP_addr [gdb_target_symbol pck__fp3_var]
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+
+            fp1_range_type: DW_TAG_subrange_type {
+                 {DW_AT_lower_bound 0xf0 DW_FORM_data1}
+                 {DW_AT_upper_bound 0x10 DW_FORM_data1}
+                 {DW_AT_name foo__fp1_range_type}
+                 {DW_AT_type :$fp1_base_type}
+             }
+
+             DW_TAG_variable {
+                 {DW_AT_name pck__fp1_range_var}
+                 {DW_AT_type :$fp1_range_type}
+                 {DW_AT_location {
+                     DW_OP_addr [gdb_target_symbol pck__fp1_range_var]
+                 } SPECIAL_expr}
+                 {external 1 flag}
+             }
+	}
+    }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+	  [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+# Do the testing in Ada mode, since this is the language for which
+# this feature has been implemented, and where we know the language
+# has the concept of fixed-point types.
+gdb_test_no_output "set lang ada"
+
+gdb_test "print pck.fp1_var" \
+         " = 0.25"
+
+gdb_test "print pck.fp2_var" \
+         " = -0.01"
+
+gdb_test "print pck.fp3_var" \
+         " = 0.1"
+
+gdb_test "print pck.fp1_range_var" \
+         " = 1"
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 2d9d1fb..38ae0bd 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -794,6 +794,31 @@ generic_val_print_float (struct type *type, struct ui_file *stream,
   print_floating (valaddr, type, stream);
 }
 
+/* generic_val_print helper for TYPE_CODE_FIXED_POINT.  */
+
+static void
+generic_val_print_fixed_point (struct value *val, struct ui_file *stream,
+			       const struct value_print_options *options)
+{
+  if (options->format)
+    value_print_scalar_formatted (val, options, 0, stream);
+  else
+    {
+      struct type *type = value_type (val);
+
+      const gdb_byte *valaddr = value_contents_for_printing (val);
+      gdb_mpf f;
+
+      f.read_fixed_point (valaddr, TYPE_LENGTH (type),
+			  type_byte_order (type), type->is_unsigned (),
+			  fixed_point_scaling_factor (type));
+
+      const char *fmt = TYPE_LENGTH (type) < 4 ? "%.11Fg" : "%.17Fg";
+      gdb::unique_xmalloc_ptr<char> str = gmp_string_asprintf (fmt, f.val);
+      fprintf_filtered (stream, "%s", str.get ());
+    }
+}
+
 /* generic_value_print helper for TYPE_CODE_COMPLEX.  */
 
 static void
@@ -844,6 +869,10 @@ generic_value_print (struct value *val, struct ui_file *stream, int recurse,
   struct type *type = value_type (val);
 
   type = check_typedef (type);
+
+  if (is_fixed_point_type (type))
+    type = fixed_point_type_base_type (type);
+
   switch (type->code ())
     {
     case TYPE_CODE_ARRAY:
@@ -909,6 +938,10 @@ generic_value_print (struct value *val, struct ui_file *stream, int recurse,
 	generic_val_print_float (type, stream, val, options);
       break;
 
+    case TYPE_CODE_FIXED_POINT:
+      generic_val_print_fixed_point (val, stream, options);
+      break;
+
     case TYPE_CODE_VOID:
       fputs_filtered (decorations->void_name, stream);
       break;
diff --git a/gdb/value.c b/gdb/value.c
index c9907fa..a0546af 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2758,6 +2758,9 @@ value_as_address (struct value *val)
 LONGEST
 unpack_long (struct type *type, const gdb_byte *valaddr)
 {
+  if (is_fixed_point_type (type))
+    type = fixed_point_type_base_type (type);
+
   enum bfd_endian byte_order = type_byte_order (type);
   enum type_code code = type->code ();
   int len = TYPE_LENGTH (type);
@@ -2806,6 +2809,17 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
     case TYPE_CODE_DECFLOAT:
       return target_float_to_longest (valaddr, type);
 
+    case TYPE_CODE_FIXED_POINT:
+      {
+	gdb_mpq vq;
+	vq.read_fixed_point (valaddr, len, byte_order, nosign,
+			     fixed_point_scaling_factor (type));
+
+	gdb_mpz vz;
+	mpz_tdiv_q (vz.val, mpq_numref (vq.val), mpq_denref (vq.val));
+	return vz.as_integer<LONGEST> ();
+      }
+
     case TYPE_CODE_PTR:
     case TYPE_CODE_REF:
     case TYPE_CODE_RVALUE_REF:
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [pushed/v2 6/9] fix printing of DWARF fixed-point type objects with format modifier
  2020-11-15  8:35 ` pushed: " Joel Brobecker
                     ` (4 preceding siblings ...)
  2020-11-15  8:35   ` [pushed/v2 5/9] Add support for printing value of DWARF-based fixed-point type objects Joel Brobecker
@ 2020-11-15  8:35   ` Joel Brobecker
  2020-11-15  8:35   ` [pushed/v2 7/9] Add ptype support for DWARF-based fixed-point types Joel Brobecker
                     ` (5 subsequent siblings)
  11 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

Consider a fixed-point type such the scaling factor is 1/16,
as the following Ada code snippet would create:

      type FP1_Type is delta 0.1 range -1.0 .. +1.0;
      FP1_Var : FP1_Type := 0.25;

Printing the value of this variable with a format modifier yields
the wrong value. E.g.:

    (gdb) p /x fp1_var
    $6 = 0x4

Since the real value is 0.25, we therefore expected...

    (gdb) p /x fp1_var
    $6 = 0x0

What happens, in this case, is that the value being printed is
actually the "raw" value of our object, before the scaling factor
gets applied.

This commit fixes the issue by using approach as for float values,
where we convert the value into an integer value, prior to printing,
knowing that the conversion takes the scaling factor into account.

gdb/ChangeLog:

        * printcmd.c (print_scalar_formatted): Add fixed-point type
        handling when options->format is set.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-fixed-point.exp: Add "print /x" tests.
---
 gdb/ChangeLog                                |  5 +++++
 gdb/printcmd.c                               |  3 ++-
 gdb/testsuite/ChangeLog                      |  4 ++++
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp | 12 ++++++++++++
 4 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 16905ac..0d322da 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,10 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* printcmd.c (print_scalar_formatted): Add fixed-point type
+	handling when options->format is set.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* ada-valprint.c (ada_value_print_1): Add fixed-point type handling.
 	* dwarf2/read.c (get_dwarf2_rational_constant)
 	(get_dwarf2_unsigned_rational_constant, finish_fixed_point_type)
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index f7186c2..6651424 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -421,7 +421,8 @@ print_scalar_formatted (const gdb_byte *valaddr, struct type *type,
      range case, we want to avoid this, so we store the unpacked value
      here for possible use later.  */
   gdb::optional<LONGEST> val_long;
-  if ((type->code () == TYPE_CODE_FLT
+  if (((type->code () == TYPE_CODE_FLT
+	|| is_fixed_point_type (type))
        && (options->format == 'o'
 	   || options->format == 'x'
 	   || options->format == 't'
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 0f629bd..9b9ffe5 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* gdb.dwarf2/dw2-fixed-point.exp: Add "print /x" tests.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* gdb.ada/fixed_cmp.exp: Force compilation to use -fgnat-encodings=all.
 	* gdb.ada/fixed_points.exp: Add fixed-point variables printing tests.
 	* gdb.ada/fixed_points/pck.ads, gdb.ada/fixed_points/pck.adb:
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
index bf88ffe..27c549c 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
@@ -122,11 +122,23 @@ gdb_test_no_output "set lang ada"
 gdb_test "print pck.fp1_var" \
          " = 0.25"
 
+gdb_test "print /x pck.fp1_var" \
+         " = 0x0"
+
 gdb_test "print pck.fp2_var" \
          " = -0.01"
 
+gdb_test "print /x pck.fp2_var" \
+         " = 0x0"
+
 gdb_test "print pck.fp3_var" \
          " = 0.1"
 
+gdb_test "print /x pck.fp3_var" \
+         " = 0x0"
+
 gdb_test "print pck.fp1_range_var" \
          " = 1"
+
+gdb_test "print /x pck.fp1_range_var" \
+         " = 0x1"
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [pushed/v2 7/9] Add ptype support for DWARF-based fixed-point types
  2020-11-15  8:35 ` pushed: " Joel Brobecker
                     ` (5 preceding siblings ...)
  2020-11-15  8:35   ` [pushed/v2 6/9] fix printing of DWARF fixed-point type objects with format modifier Joel Brobecker
@ 2020-11-15  8:35   ` Joel Brobecker
  2020-11-15  8:35   ` [pushed/v2 8/9] Add support for fixed-point type arithmetic Joel Brobecker
                     ` (4 subsequent siblings)
  11 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

Note that the ptype information printed for types described
via pure DWARF debug info is slightly less informative as
the one printed when the information is encoded in the type's
name, via the GNAT encoding. As a result, the output in
the case of DWARF-described fixed point types is slightly
different. In pratice, this is no real loss because the information
not available in DWARF has no bearing on how the type is actually
stored in memory.

gdb/ChangeLog:

        * ada-typeprint.c (ada_print_type): Add handing of fixed-point
        range types.
        * c-typeprint.c (c_type_print_varspec_prefix)
        (c_type_print_varspec_suffix, c_type_print_base_1): Add
        TYPE_CODE_FIXED_POINT handling.
        * p-typeprint.c (pascal_type_print_varspec_prefix)
        (pascal_type_print_varspec_suffix): Likewise.
        * typeprint.c (print_type_fixed_point): New function.
        * typeprint.h (print_type_fixed_point): Add declaration.

gdb/testsuite/ChangeLog:

        * gdb.ada/fixed_points.exp: Add ptype tests.
        * gdb.dwarf2/dw2-fixed-point.exp: Likewise.
---
 gdb/ChangeLog                                | 12 ++++++++
 gdb/ada-typeprint.c                          |  6 ++++
 gdb/c-typeprint.c                            |  6 ++++
 gdb/p-typeprint.c                            |  2 ++
 gdb/testsuite/ChangeLog                      |  5 ++++
 gdb/testsuite/gdb.ada/fixed_points.exp       | 36 +++++++++++++++++++++++
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp | 44 ++++++++++++++++++++++++++++
 gdb/typeprint.c                              | 12 ++++++++
 gdb/typeprint.h                              |  5 ++++
 9 files changed, 128 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 0d322da..56e54d3 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,17 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* ada-typeprint.c (ada_print_type): Add handing of fixed-point
+	range types.
+	* c-typeprint.c (c_type_print_varspec_prefix)
+	(c_type_print_varspec_suffix, c_type_print_base_1): Add
+	TYPE_CODE_FIXED_POINT handling.
+	* p-typeprint.c (pascal_type_print_varspec_prefix)
+	(pascal_type_print_varspec_suffix): Likewise.
+	* typeprint.c (print_type_fixed_point): New function.
+	* typeprint.h (print_type_fixed_point): Add declaration.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* printcmd.c (print_scalar_formatted): Add fixed-point type
 	handling when options->format is set.
 
diff --git a/gdb/ada-typeprint.c b/gdb/ada-typeprint.c
index 5388247..8abb65b 100644
--- a/gdb/ada-typeprint.c
+++ b/gdb/ada-typeprint.c
@@ -1046,6 +1046,12 @@ ada_print_type (struct type *type0, const char *varstring,
       case TYPE_CODE_RANGE:
 	if (ada_is_gnat_encoded_fixed_point_type (type))
 	  print_gnat_encoded_fixed_point_type (type, stream);
+	else if (is_fixed_point_type (type))
+	  {
+	    fprintf_filtered (stream, "<");
+	    print_type_fixed_point (type, stream);
+	    fprintf_filtered (stream, ">");
+	  }
 	else if (ada_is_modular_type (type))
 	  fprintf_filtered (stream, "mod %s", 
 			    int_string (ada_modulus (type), 10, 0, 0, 1));
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index e72fdaa..10631ff 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -465,6 +465,7 @@ c_type_print_varspec_prefix (struct type *type,
     case TYPE_CODE_COMPLEX:
     case TYPE_CODE_NAMESPACE:
     case TYPE_CODE_DECFLOAT:
+    case TYPE_CODE_FIXED_POINT:
       /* These types need no prefix.  They are listed here so that
 	 gcc -Wall will reveal any types that haven't been handled.  */
       break;
@@ -844,6 +845,7 @@ c_type_print_varspec_suffix (struct type *type,
     case TYPE_CODE_COMPLEX:
     case TYPE_CODE_NAMESPACE:
     case TYPE_CODE_DECFLOAT:
+    case TYPE_CODE_FIXED_POINT:
       /* These types do not need a suffix.  They are listed so that
 	 gcc -Wall will report types that may not have been
 	 considered.  */
@@ -1683,6 +1685,10 @@ c_type_print_base_1 (struct type *type, struct ui_file *stream,
       fprintf_styled (stream, metadata_style.style (), _("<range type>"));
       break;
 
+    case TYPE_CODE_FIXED_POINT:
+      print_type_fixed_point (type, stream);
+      break;
+
     case TYPE_CODE_NAMESPACE:
       fputs_filtered ("namespace ", stream);
       fputs_filtered (type->name (), stream);
diff --git a/gdb/p-typeprint.c b/gdb/p-typeprint.c
index ef0f254..c2c182a 100644
--- a/gdb/p-typeprint.c
+++ b/gdb/p-typeprint.c
@@ -296,6 +296,7 @@ pascal_type_print_varspec_prefix (struct type *type, struct ui_file *stream,
     case TYPE_CODE_STRING:
     case TYPE_CODE_COMPLEX:
     case TYPE_CODE_TYPEDEF:
+    case TYPE_CODE_FIXED_POINT:
       /* These types need no prefix.  They are listed here so that
 	 gcc -Wall will reveal any types that haven't been handled.  */
       break;
@@ -429,6 +430,7 @@ pascal_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
     case TYPE_CODE_STRING:
     case TYPE_CODE_COMPLEX:
     case TYPE_CODE_TYPEDEF:
+    case TYPE_CODE_FIXED_POINT:
       /* These types do not need a suffix.  They are listed so that
 	 gcc -Wall will report types that may not have been considered.  */
       break;
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 9b9ffe5..2c7b5c5 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,10 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* gdb.ada/fixed_points.exp: Add ptype tests.
+	* gdb.dwarf2/dw2-fixed-point.exp: Likewise.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* gdb.dwarf2/dw2-fixed-point.exp: Add "print /x" tests.
 
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
diff --git a/gdb/testsuite/gdb.ada/fixed_points.exp b/gdb/testsuite/gdb.ada/fixed_points.exp
index 655ee95..1fe2eb2 100644
--- a/gdb/testsuite/gdb.ada/fixed_points.exp
+++ b/gdb/testsuite/gdb.ada/fixed_points.exp
@@ -55,8 +55,44 @@ gdb_test "ptype Overprecise_Object" \
 gdb_test "print fp1_var" \
          " = 0.25"
 
+gdb_test_multiple "ptype fp1_var" "" {
+    -re "type = <1-byte fixed point \\(small = 0\\.0625\\)>\r\n$gdb_prompt $" {
+        pass $gdb_test_name
+    }
+    -re "type = delta 0\\.1 <'small = 0\\.0625>\r\n$gdb_prompt $" {
+        # The (legacy) output we obtain when the compiler described
+        # our fixed point types using the GNAT encodings rather than
+        # standard DWARF.  OK as well.
+        pass $gdb_test_name
+    }
+}
+
 gdb_test "print fp2_var" \
          " = -0.01"
 
+gdb_test_multiple "ptype fp2_var" "" {
+    -re "type = <8-byte fixed point \\(small = 0\\.01\\)>\r\n$gdb_prompt $" {
+        pass $gdb_test_name
+    }
+    -re "type = delta 0\\.01\r\n$gdb_prompt $" {
+        # The (legacy) output we obtain when the compiler described
+        # our fixed point types using the GNAT encodings rather than
+        # standard DWARF.  OK as well.
+        pass $gdb_test_name
+    }
+}
+
 gdb_test "print fp3_var" \
          " = 0.1"
+
+gdb_test_multiple "ptype fp3_var" "" {
+    -re "type = <1-byte fixed point \\(small = 0\\.0333333\\)>\r\n$gdb_prompt $" {
+        pass $gdb_test_name
+    }
+    -re "type = delta 0\\.1 <'small = 0\\.0333333>\r\n$gdb_prompt $" {
+        # The (legacy) output we obtain when the compiler described
+        # our fixed point types using the GNAT encodings rather than
+        # standard DWARF.  OK as well.
+        pass $gdb_test_name
+    }
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
index 27c549c..33a7e74 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
@@ -142,3 +142,47 @@ gdb_test "print pck.fp1_range_var" \
 
 gdb_test "print /x pck.fp1_range_var" \
          " = 0x1"
+
+# Set the language to LANG and do a ptype test on pck__fp1_var,
+# pck__fp2_var and pck__fp3_var, verifying that the output matches
+# FP1_RE, FP2_RE, FP2_RE (resp.).
+
+proc do_ptype_test {lang fp1_re fp2_re fp3_re fp1_range_re} {
+    with_test_prefix "lang=$lang" {
+        gdb_test_no_output "set language $lang" \
+            "set language to $lang for ptype test"
+
+        gdb_test "ptype pck__fp1_var" $fp1_re
+
+        gdb_test "ptype pck__fp2_var" $fp2_re
+
+        gdb_test "ptype pck__fp3_var" $fp3_re
+
+        if { $lang == "modula-2" || $lang == "pascal" } {
+            setup_xfail "*-*-*" "not supported by language"
+        }
+        gdb_test "ptype pck__fp1_range_var" $fp1_range_re
+    }
+}
+
+do_ptype_test "ada" \
+              " = <1-byte fixed point \\(small = 1/16\\)>" \
+              " = <1-byte fixed point \\(small = 1/100\\)>" \
+              " = <1-byte fixed point \\(small = 1/30\\)>" \
+              " = <1-byte fixed point \\(small = 1/16\\)>"
+
+foreach lang [list "c" "d" "go" "objective-c" "opencl" ] {
+    do_ptype_test $lang \
+                  " = 1-byte fixed point \\(small = 1/16\\)" \
+                  " = 1-byte fixed point \\(small = 1/100\\)" \
+                  " = 1-byte fixed point \\(small = 1/30\\)" \
+                  " = <range type>"
+}
+
+foreach lang [list "fortran" "modula-2" "pascal" ] {
+    do_ptype_test $lang \
+                  " = pck__fp1_type" \
+                  " = pck__fp2_type" \
+                  " = pck__fp3_type" \
+                  " = <range type>"
+}
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index acaee44..f947faf 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -662,6 +662,18 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream)
     }
 }
 
+/* See typeprint.h.  */
+
+void
+print_type_fixed_point (struct type *type, struct ui_file *stream)
+{
+  gdb::unique_xmalloc_ptr<char> small_img
+    = fixed_point_scaling_factor (type).str ();
+
+  fprintf_filtered (stream, "%s-byte fixed point (small = %s)",
+		    pulongest (TYPE_LENGTH (type)), small_img.get ());
+}
+
 /* Dump details of a type specified either directly or indirectly.
    Uses the same sort of type lookup mechanism as ptype_command()
    and whatis_command().  */
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index 8936b9a..d595cbe 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -151,6 +151,11 @@ class typedef_hash_table
 
 void print_type_scalar (struct type * type, LONGEST, struct ui_file *);
 
+/* Assuming the TYPE is a fixed point type, print its type description
+   on STREAM.  */
+
+void print_type_fixed_point (struct type *type, struct ui_file *stream);
+
 void c_type_print_args (struct type *, struct ui_file *, int, enum language,
 			const struct type_print_options *);
 
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [pushed/v2 8/9] Add support for fixed-point type arithmetic
  2020-11-15  8:35 ` pushed: " Joel Brobecker
                     ` (6 preceding siblings ...)
  2020-11-15  8:35   ` [pushed/v2 7/9] Add ptype support for DWARF-based fixed-point types Joel Brobecker
@ 2020-11-15  8:35   ` Joel Brobecker
  2020-11-15  8:35   ` [pushed/v2 9/9] Add support for fixed-point type comparison operators Joel Brobecker
                     ` (3 subsequent siblings)
  11 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This patch adds support for binary operations on fixed-point values,
as well as for the negative unary operator.

gdb/ChangeLog:

        * eval.c (binop_promote): Add fixed-point type handling.
        * valarith.c (fixed_point_binop): New function.
        (scalar_binop): Add fixed-point type handling.
        (value_neg): Add fixed-point type handling.
        * valops.c (value_cast_to_fixed_point): New function.
        (value_cast): Add fixed-point type handling.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-fixed-point.exp: Add arithmetic tests.
---
 gdb/ChangeLog                                |  9 +++
 gdb/eval.c                                   |  3 +
 gdb/testsuite/ChangeLog                      |  4 ++
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp | 18 ++++++
 gdb/valarith.c                               | 91 +++++++++++++++++++++++++++-
 gdb/valops.c                                 | 74 +++++++++++++++++++++-
 6 files changed, 196 insertions(+), 3 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 56e54d3..e9f0afd 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,14 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* eval.c (binop_promote): Add fixed-point type handling.
+	* valarith.c (fixed_point_binop): New function.
+	(scalar_binop): Add fixed-point type handling.
+	(value_neg): Add fixed-point type handling.
+	* valops.c (value_cast_to_fixed_point): New function.
+	(value_cast): Add fixed-point type handling.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* ada-typeprint.c (ada_print_type): Add handing of fixed-point
 	range types.
 	* c-typeprint.c (c_type_print_varspec_prefix)
diff --git a/gdb/eval.c b/gdb/eval.c
index 8d0c574..308f477 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -430,6 +430,9 @@ binop_promote (const struct language_defn *language, struct gdbarch *gdbarch,
 	  && !is_integral_type (type2)))
     return;
 
+  if (is_fixed_point_type (type1) || is_fixed_point_type (type2))
+        return;
+
   if (type1->code () == TYPE_CODE_DECFLOAT
       || type2->code () == TYPE_CODE_DECFLOAT)
     {
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 2c7b5c5..3c53f6c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* gdb.dwarf2/dw2-fixed-point.exp: Add arithmetic tests.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* gdb.ada/fixed_points.exp: Add ptype tests.
 	* gdb.dwarf2/dw2-fixed-point.exp: Likewise.
 
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
index 33a7e74..0252195 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
@@ -143,6 +143,24 @@ gdb_test "print pck.fp1_range_var" \
 gdb_test "print /x pck.fp1_range_var" \
          " = 0x1"
 
+gdb_test "print pck.fp1_var + 0.25" \
+         " = 0.5"
+
+gdb_test "print pck.fp2_var - pck.fp2_var" \
+         " = 0"
+
+gdb_test "print pck.fp3_var * 1" \
+         " = 0.1"
+
+gdb_test "print pck.fp3_var / pck.fp3_var" \
+         " = 1"
+
+gdb_test "print pck.fp1_range_var - 0.5" \
+         " = 0.5"
+
+gdb_test "print -pck.fp1_var" \
+         " = -0.25"
+
 # Set the language to LANG and do a ptype test on pck__fp1_var,
 # pck__fp2_var and pck__fp3_var, verifying that the output matches
 # FP1_RE, FP2_RE, FP2_RE (resp.).
diff --git a/gdb/valarith.c b/gdb/valarith.c
index f6caf3d..65a6f13 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -881,6 +881,84 @@ value_args_as_target_float (struct value *arg1, struct value *arg2,
 	     type2->name ());
 }
 
+/* Assuming at last one of ARG1 or ARG2 is a fixed point value,
+   perform the binary operation OP on these two operands, and return
+   the resulting value (also as a fixed point).  */
+
+static struct value *
+fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
+{
+  struct type *type1 = check_typedef (value_type (arg1));
+  struct type *type2 = check_typedef (value_type (arg2));
+
+  struct value *val;
+
+  gdb_assert (is_fixed_point_type (type1) || is_fixed_point_type (type2));
+  if (!is_fixed_point_type (type1))
+    {
+      arg1 = value_cast (type2, arg1);
+      type1 = type2;
+    }
+  if (!is_fixed_point_type (type2))
+    {
+      arg2 = value_cast (type1, arg2);
+      type2 = type1;
+    }
+
+  gdb_mpq v1, v2, res;
+  v1.read_fixed_point (value_contents (arg1), TYPE_LENGTH (type1),
+		       type_byte_order (type1), type1->is_unsigned (),
+		       fixed_point_scaling_factor (type1));
+  v2.read_fixed_point (value_contents (arg2), TYPE_LENGTH (type2),
+		       type_byte_order (type2), type2->is_unsigned (),
+		       fixed_point_scaling_factor (type2));
+
+#define INIT_VAL_WITH_FIXED_POINT_VAL(RESULT) \
+  do { \
+      val = allocate_value (type1); \
+      (RESULT).write_fixed_point			\
+        (value_contents_raw (val), TYPE_LENGTH (type1), \
+	 type_byte_order (type1), type1->is_unsigned (), \
+	 fixed_point_scaling_factor (type1)); \
+     } while (0)
+
+  switch (op)
+    {
+    case BINOP_ADD:
+      mpq_add (res.val, v1.val, v2.val);
+      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      break;
+
+    case BINOP_SUB:
+      mpq_sub (res.val, v1.val, v2.val);
+      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      break;
+
+    case BINOP_MIN:
+      INIT_VAL_WITH_FIXED_POINT_VAL (mpq_cmp (v1.val, v2.val) < 0 ? v1 : v2);
+      break;
+
+    case BINOP_MAX:
+      INIT_VAL_WITH_FIXED_POINT_VAL (mpq_cmp (v1.val, v2.val) > 0 ? v1 : v2);
+      break;
+
+    case BINOP_MUL:
+      mpq_mul (res.val, v1.val, v2.val);
+      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      break;
+
+    case BINOP_DIV:
+      mpq_div (res.val, v1.val, v2.val);
+      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      break;
+
+    default:
+      error (_("Integer-only operation on fixed point number."));
+    }
+
+  return val;
+}
+
 /* A helper function that finds the type to use for a binary operation
    involving TYPE1 and TYPE2.  */
 
@@ -1054,10 +1132,17 @@ scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
       || type2->code () == TYPE_CODE_COMPLEX)
     return complex_binop (arg1, arg2, op);
 
-  if ((!is_floating_value (arg1) && !is_integral_type (type1))
-      || (!is_floating_value (arg2) && !is_integral_type (type2)))
+  if ((!is_floating_value (arg1)
+       && !is_integral_type (type1)
+       && !is_fixed_point_type (type1))
+      || (!is_floating_value (arg2)
+	  && !is_integral_type (type2)
+	  && !is_fixed_point_type (type2)))
     error (_("Argument to arithmetic operation not a number or boolean."));
 
+  if (is_fixed_point_type (type1) || is_fixed_point_type (type2))
+    return fixed_point_binop (arg1, arg2, op);
+
   if (is_floating_type (type1) || is_floating_type (type2))
     {
       result_type = promotion_type (type1, type2);
@@ -1753,6 +1838,8 @@ value_neg (struct value *arg1)
 
   if (is_integral_type (type) || is_floating_type (type))
     return value_binop (value_from_longest (type, 0), arg1, BINOP_SUB);
+  else if (is_fixed_point_type (type))
+    return value_binop (value_zero (type, not_lval), arg1, BINOP_SUB);
   else if (type->code () == TYPE_CODE_ARRAY && type->is_vector ())
     {
       struct value *tmp, *val = allocate_value (type);
diff --git a/gdb/valops.c b/gdb/valops.c
index 4df2538..0f84a70 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -331,6 +331,60 @@ value_cast_pointers (struct type *type, struct value *arg2,
   return arg2;
 }
 
+/* Assuming that TO_TYPE is a fixed point type, return a value
+   corresponding to the cast of FROM_VAL to that type.  */
+
+static struct value *
+value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
+{
+  struct type *from_type = value_type (from_val);
+
+  if (from_type == to_type)
+    return from_val;
+
+  gdb_mpq vq;
+
+  /* Extract the value as a rational number.  */
+
+  if (is_floating_type (from_type))
+    {
+      double d = target_float_to_host_double (value_contents (from_val),
+					      from_type);
+      mpq_set_d (vq.val, d);
+    }
+
+  else if (is_integral_type (from_type) || is_fixed_point_type (from_type))
+    {
+      gdb_mpz vz;
+
+      vz.read (value_contents (from_val), TYPE_LENGTH (from_type),
+	       type_byte_order (from_type), from_type->is_unsigned ());
+      mpq_set_z (vq.val, vz.val);
+
+      if (is_fixed_point_type (from_type))
+	mpq_mul (vq.val, vq.val, fixed_point_scaling_factor (from_type).val);
+    }
+
+  else
+    error (_("Invalid conversion from type %s to fixed point type %s"),
+	   from_type->name (), to_type->name ());
+
+  /* Divide that value by the scaling factor to obtain the unscaled
+     value, first in rational form, and then in integer form.  */
+
+  mpq_div (vq.val, vq.val, fixed_point_scaling_factor (to_type).val);
+  gdb_mpz unscaled = vq.get_rounded ();
+
+  /* Finally, create the result value, and pack the unscaled value
+     in it.  */
+  struct value *result = allocate_value (to_type);
+  unscaled.write (value_contents_raw (result),
+		  TYPE_LENGTH (to_type), type_byte_order (to_type),
+		  to_type->is_unsigned ());
+
+  return result;
+}
+
 /* Cast value ARG2 to type TYPE and return as a value.
    More general than a C cast: accepts any two types of the same length,
    and if ARG2 is an lvalue it can be cast into anything at all.  */
@@ -349,6 +403,9 @@ value_cast (struct type *type, struct value *arg2)
   if (value_type (arg2) == type)
     return arg2;
 
+  if (is_fixed_point_type (type))
+    return value_cast_to_fixed_point (type, arg2);
+
   /* Check if we are casting struct reference to struct reference.  */
   if (TYPE_IS_REFERENCE (check_typedef (type)))
     {
@@ -439,7 +496,8 @@ value_cast (struct type *type, struct value *arg2)
 
   scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT
 	    || code2 == TYPE_CODE_DECFLOAT || code2 == TYPE_CODE_ENUM
-	    || code2 == TYPE_CODE_RANGE);
+	    || code2 == TYPE_CODE_RANGE
+	    || is_fixed_point_type (type2));
 
   if ((code1 == TYPE_CODE_STRUCT || code1 == TYPE_CODE_UNION)
       && (code2 == TYPE_CODE_STRUCT || code2 == TYPE_CODE_UNION)
@@ -460,6 +518,20 @@ value_cast (struct type *type, struct value *arg2)
 				value_contents_raw (v), type);
 	  return v;
 	}
+      else if (is_fixed_point_type (type2))
+	{
+	  gdb_mpq fp_val;
+
+	  fp_val.read_fixed_point
+	    (value_contents (arg2), TYPE_LENGTH (type2),
+	     type_byte_order (type2), type2->is_unsigned (),
+	     fixed_point_scaling_factor (type2));
+
+	  struct value *v = allocate_value (to_type);
+	  target_float_from_host_double (value_contents_raw (v),
+					 to_type, mpq_get_d (fp_val.val));
+	  return v;
+	}
 
       /* The only option left is an integral type.  */
       if (type2->is_unsigned ())
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [pushed/v2 9/9] Add support for fixed-point type comparison operators
  2020-11-15  8:35 ` pushed: " Joel Brobecker
                     ` (7 preceding siblings ...)
  2020-11-15  8:35   ` [pushed/v2 8/9] Add support for fixed-point type arithmetic Joel Brobecker
@ 2020-11-15  8:35   ` Joel Brobecker
  2020-11-16 23:48   ` pushed: Add support for DWARF-based fixed point types Pedro Alves
                     ` (2 subsequent siblings)
  11 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:35 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This patch adds support for binary comparison operators with
fixed-point type values.

gdb/ChangeLog:

        * valarith.c (fixed_point_binop): Add BINOP_EQUAL and BINOP_LESS
        handling.
        (value_less): Add fixed-point handling.

gdb/testsuite/ChangeLog:

        * gdb.ada/fixed_cmp.exp: Add -fgnat-encodings=minimal testing.
        * gdb.dwarf2/dw2-fixed-point.c (pck__fp1_var2): New global.
        (main): Add reference to pck__fp1_var2.
        * gdb.dwarf2/dw2-fixed-point.exp: Add comparison operator testing.
---
 gdb/ChangeLog                                |   6 ++
 gdb/testsuite/ChangeLog                      |   7 ++
 gdb/testsuite/gdb.ada/fixed_cmp.exp          |   2 +-
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c   |   7 ++
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp | 102 +++++++++++++++++++++++++++
 gdb/valarith.c                               |  15 +++-
 6 files changed, 137 insertions(+), 2 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e9f0afd..6d0a0c6 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,11 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* valarith.c (fixed_point_binop): Add BINOP_EQUAL and BINOP_LESS
+	handling.
+	(value_less): Add fixed-point handling.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* eval.c (binop_promote): Add fixed-point type handling.
 	* valarith.c (fixed_point_binop): New function.
 	(scalar_binop): Add fixed-point type handling.
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 3c53f6c..6ecb04c 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,12 @@
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
 
+	* gdb.ada/fixed_cmp.exp: Add -fgnat-encodings=minimal testing.
+	* gdb.dwarf2/dw2-fixed-point.c (pck__fp1_var2): New global.
+	(main): Add reference to pck__fp1_var2.
+	* gdb.dwarf2/dw2-fixed-point.exp: Add comparison operator testing.
+
+2020-11-15  Joel Brobecker  <brobecker@adacore.com>
+
 	* gdb.dwarf2/dw2-fixed-point.exp: Add arithmetic tests.
 
 2020-11-15  Joel Brobecker  <brobecker@adacore.com>
diff --git a/gdb/testsuite/gdb.ada/fixed_cmp.exp b/gdb/testsuite/gdb.ada/fixed_cmp.exp
index cfdbb1c..e2c88b8 100644
--- a/gdb/testsuite/gdb.ada/fixed_cmp.exp
+++ b/gdb/testsuite/gdb.ada/fixed_cmp.exp
@@ -19,7 +19,7 @@ if { [skip_ada_tests] } { return -1 }
 
 standard_ada_testfile fixed
 
-foreach_with_prefix gnat_encodings {all} {
+foreach_with_prefix gnat_encodings {all minimal} {
     set flags [list debug additional_flags=-fgnat-encodings=$gnat_encodings]
 
     if {[gdb_compile_ada "${srcfile}" "${binfile}" executable $flags] != "" } {
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
index d9c811c..971a7a8 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.c
@@ -23,6 +23,12 @@
 int8_t pck__fp1_var = 4;
 
 /* Simulate an Ada variable declared inside package Pck as follow:
+      type FP1_Type is delta 0.1 range -1.0 .. +1.0;
+      FP1_Var2 : FP1_Type := 0.50;
+   Basically, the same as FP1_Var, but with a different value.  */
+int8_t pck__fp1_var2 = 8;
+
+/* Simulate an Ada variable declared inside package Pck as follow:
       type FP2_Type is delta 0.01 digits 14;
       FP2_Var : FP2_Type := -0.01;  */
 int32_t pck__fp2_var = -1;
@@ -41,6 +47,7 @@ int
 main (void)
 {
   pck__fp1_var++;
+  pck__fp1_var2++;
   pck__fp2_var++;
   pck__fp3_var++;
   pck__fp1_range_var++;
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
index 0252195..a82a9af 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
@@ -49,6 +49,15 @@ Dwarf::assemble $asm_file {
                 {external 1 flag}
             }
 
+            DW_TAG_variable {
+                {DW_AT_name pck__fp1_var2}
+                {DW_AT_type :$fp1_base_type}
+                {DW_AT_location {
+                    DW_OP_addr [gdb_target_symbol pck__fp1_var2]
+                } SPECIAL_expr}
+                {external 1 flag}
+            }
+
             fp2_base_type: DW_TAG_base_type {
                 {DW_AT_byte_size     1 DW_FORM_sdata}
                 {DW_AT_encoding      @DW_ATE_signed_fixed}
@@ -161,6 +170,99 @@ gdb_test "print pck.fp1_range_var - 0.5" \
 gdb_test "print -pck.fp1_var" \
          " = -0.25"
 
+gdb_test "print pck.fp1_var = pck.fp1_var" \
+         " = true"
+
+gdb_test "print pck.fp1_var = pck.fp1_var2" \
+         " = false"
+
+gdb_test "print pck.fp1_var /= pck.fp1_var" \
+         " = false"
+
+gdb_test "print pck.fp1_var /= pck.fp1_var2" \
+         " = true"
+
+gdb_test "print pck.fp1_var < pck.fp1_var" \
+         " = false"
+
+gdb_test "print pck.fp1_var < pck.fp1_var2" \
+         " = true"
+
+gdb_test "print pck.fp1_var <= pck.fp1_var2" \
+         " = true"
+
+gdb_test "print pck.fp1_var <= pck.fp1_var" \
+         " = true"
+
+gdb_test "print pck.fp1_var > pck.fp1_var2" \
+         " = false"
+
+gdb_test "print pck.fp1_var2 > pck.fp1_var" \
+         " = true"
+
+gdb_test "print pck.fp1_var >= pck.fp1_var" \
+         " = true"
+
+gdb_test "print pck.fp1_var >= pck.fp1_var2" \
+         " = false"
+
+# Same as above, but with litterals...
+
+gdb_test "print pck.fp1_var = 0.25" \
+         " = true"
+
+gdb_test "print pck.fp1_var = 0.5" \
+         " = false"
+
+gdb_test "print pck.fp1_var = 1" \
+         " = false"
+
+gdb_test "print pck.fp1_var /= 0.25" \
+         " = false"
+
+gdb_test "print pck.fp1_var /= 0.5" \
+         " = true"
+
+gdb_test "print pck.fp1_var /= 1" \
+         " = true"
+
+gdb_test "print pck.fp1_var < 0.25" \
+         " = false"
+
+gdb_test "print pck.fp1_var <  0.5" \
+         " = true"
+
+gdb_test "print pck.fp1_var <  1" \
+         " = true"
+
+gdb_test "print pck.fp1_var <= 0.25" \
+         " = true"
+
+gdb_test "print pck.fp1_var <= 0.5" \
+         " = true"
+
+gdb_test "print pck.fp1_var <= 1" \
+         " = true"
+
+gdb_test "print pck.fp1_var > 0.25" \
+         " = false"
+
+gdb_test "print pck.fp1_var > 0.5" \
+         " = false"
+
+gdb_test "print pck.fp1_var > 1" \
+         " = false"
+
+gdb_test "print pck.fp1_var >= 0.25" \
+         " = true"
+
+gdb_test "print pck.fp1_var >= 0.5" \
+         " = false"
+
+gdb_test "print pck.fp1_var >= 1" \
+         " = false"
+
+
 # Set the language to LANG and do a ptype test on pck__fp1_var,
 # pck__fp2_var and pck__fp3_var, verifying that the output matches
 # FP1_RE, FP2_RE, FP2_RE (resp.).
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 65a6f13..f4497cd 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -890,7 +890,9 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
 {
   struct type *type1 = check_typedef (value_type (arg1));
   struct type *type2 = check_typedef (value_type (arg2));
+  const struct language_defn *language = current_language;
 
+  struct gdbarch *gdbarch = get_type_arch (type1);
   struct value *val;
 
   gdb_assert (is_fixed_point_type (type1) || is_fixed_point_type (type2));
@@ -952,6 +954,16 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
       INIT_VAL_WITH_FIXED_POINT_VAL (res);
       break;
 
+    case BINOP_EQUAL:
+      val = value_from_ulongest (language_bool_type (language, gdbarch),
+				 mpq_cmp (v1.val, v2.val) == 0 ? 1 : 0);
+      break;
+
+    case BINOP_LESS:
+      val = value_from_ulongest (language_bool_type (language, gdbarch),
+				 mpq_cmp (v1.val, v2.val) < 0 ? 1 : 0);
+      break;
+
     default:
       error (_("Integer-only operation on fixed point number."));
     }
@@ -1774,7 +1786,8 @@ value_less (struct value *arg1, struct value *arg2)
   is_int1 = is_integral_type (type1);
   is_int2 = is_integral_type (type2);
 
-  if (is_int1 && is_int2)
+  if ((is_int1 && is_int2)
+      || (is_fixed_point_type (type1) && is_fixed_point_type (type2)))
     return longest_to_int (value_as_long (value_binop (arg1, arg2,
 						       BINOP_LESS)));
   else if ((is_floating_value (arg1) || is_int1)
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* RFA: Various enhancements to the fixed-point support implementation
  2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
                   ` (10 preceding siblings ...)
  2020-11-15  8:35 ` pushed: " Joel Brobecker
@ 2020-11-15  8:49 ` Joel Brobecker
  2020-11-15  8:49   ` [RFA 1/6] change gmp_string_asprintf to return an std::string Joel Brobecker
                     ` (7 more replies)
  11 siblings, 8 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:49 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

Hello,

The following patch series implements the suggestions Simon made
in reviewing the first patch series, which I felt deserved to be
their own patch. I think it allows us to review those changes
independently of the first implementation (which Simon said was
find to push).

  - [RFA 1/6] change gmp_string_asprintf to return an std::string
  - [RFA 2/6] gmp-utils: Convert the read/write methods to using
  - [RFA 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro
  - [RFA 4/6] Make fixed_point_type_base_type a method of struct type
  - [RFA 5/6] Make function fixed_point_scaling_factor a method of struct
  - [RFA 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by

The patches were tested on x86_64-linux.

Thank you!
-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA 1/6] change gmp_string_asprintf to return an std::string
  2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
@ 2020-11-15  8:49   ` Joel Brobecker
  2020-11-16  0:41     ` Simon Marchi
  2020-11-15  8:49   ` [RFA 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view Joel Brobecker
                     ` (6 subsequent siblings)
  7 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:49 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This was suggested by Simon during a code review of this package upstream.
The upside is that this makes the function's API more natural and C++.
The downside is an extra malloc, which might be the reason why we went
for using a unique_xmalloc_ptr in the first place. Since this function
is not expected to be called frequently, the API improvement might be
worth the performance impact.

gdb/ChangeLog:

        * gmp-utils.h (gmp_string_asprintf): Change return type to
        std::string. Update all callers.
        * gmp-utils.c (gmp_string_asprintf): Likewise.
---
 gdb/gdbtypes.c  |  2 +-
 gdb/gmp-utils.c |  6 ++++--
 gdb/gmp-utils.h | 10 ++++------
 gdb/typeprint.c |  5 ++---
 gdb/valprint.c  |  4 ++--
 5 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 2f92887..1c1b0ff 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -4922,7 +4922,7 @@ static void
 print_fixed_point_type_info (struct type *type, int spaces)
 {
   printfi_filtered (spaces + 2, "scaling factor: %s\n",
-		    fixed_point_scaling_factor (type).str ().get ());
+		    fixed_point_scaling_factor (type).str ().c_str ());
 }
 
 static struct obstack dont_print_type_obstack;
diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index db92e57..b70aaa3 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -19,7 +19,7 @@
 
 /* See gmp-utils.h.  */
 
-gdb::unique_xmalloc_ptr<char>
+std::string
 gmp_string_asprintf (const char *fmt, ...)
 {
   va_list vp;
@@ -29,7 +29,9 @@ gmp_string_asprintf (const char *fmt, ...)
   gmp_vasprintf (&buf, fmt, vp);
   va_end (vp);
 
-  return gdb::unique_xmalloc_ptr<char> (buf);
+  std::string result(buf);
+  xfree (buf);
+  return result;
 }
 
 /* See gmp-utils.h.  */
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index 1214b64..7eed29a 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -29,9 +29,9 @@
 #include <gmp.h>
 #include "gdbsupport/traits.h"
 
-/* Same as gmp_asprintf, but returning a convenient wrapper type.  */
+/* Same as gmp_asprintf, but returning an std::string.  */
 
-gdb::unique_xmalloc_ptr<char> gmp_string_asprintf (const char *fmt, ...);
+std::string gmp_string_asprintf (const char *fmt, ...);
 
 /* A class to make it easier to use GMP's mpz_t values within GDB.  */
 
@@ -110,8 +110,7 @@ struct gdb_mpz
 	      bool unsigned_p) const;
 
   /* Return a string containing VAL.  */
-  gdb::unique_xmalloc_ptr<char> str () const
-  { return gmp_string_asprintf ("%Zd", val); }
+  std::string str () const { return gmp_string_asprintf ("%Zd", val); }
 
   /* The destructor.  */
   ~gdb_mpz () { mpz_clear (val); }
@@ -163,8 +162,7 @@ struct gdb_mpq
   }
 
   /* Return a string representing VAL as "<numerator> / <denominator>".  */
-  gdb::unique_xmalloc_ptr<char> str () const
-  { return gmp_string_asprintf ("%Qd", val); }
+  std::string str () const { return gmp_string_asprintf ("%Qd", val); }
 
   /* Return VAL rounded to the nearest integer.  */
   gdb_mpz get_rounded () const;
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index f947faf..0dd3b1c 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -667,11 +667,10 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream)
 void
 print_type_fixed_point (struct type *type, struct ui_file *stream)
 {
-  gdb::unique_xmalloc_ptr<char> small_img
-    = fixed_point_scaling_factor (type).str ();
+  std::string small_img = fixed_point_scaling_factor (type).str ();
 
   fprintf_filtered (stream, "%s-byte fixed point (small = %s)",
-		    pulongest (TYPE_LENGTH (type)), small_img.get ());
+		    pulongest (TYPE_LENGTH (type)), small_img.c_str ());
 }
 
 /* Dump details of a type specified either directly or indirectly.
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 38ae0bd..abef002 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -814,8 +814,8 @@ generic_val_print_fixed_point (struct value *val, struct ui_file *stream,
 			  fixed_point_scaling_factor (type));
 
       const char *fmt = TYPE_LENGTH (type) < 4 ? "%.11Fg" : "%.17Fg";
-      gdb::unique_xmalloc_ptr<char> str = gmp_string_asprintf (fmt, f.val);
-      fprintf_filtered (stream, "%s", str.get ());
+      std::string str = gmp_string_asprintf (fmt, f.val);
+      fprintf_filtered (stream, "%s", str.c_str ());
     }
 }
 
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view
  2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
  2020-11-15  8:49   ` [RFA 1/6] change gmp_string_asprintf to return an std::string Joel Brobecker
@ 2020-11-15  8:49   ` Joel Brobecker
  2020-11-16  0:52     ` Simon Marchi
  2020-11-15  8:49   ` [RFA 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro Joel Brobecker
                     ` (5 subsequent siblings)
  7 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:49 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This commit changes the interfaces of some of the methods declared
in gmp-utils to take a gdb::array_view of gdb_byte instead of a
(gdb_byte *, size) couple.

This makes these methods' API probably more C++-idiomatic.
With the way things are structured, this change introduces a minor
extra complication at the point of call of these methods, since
the data available there is not in the form of an array_view,
and thus the array_view needs to be constructed on the spot.

        * gmp-utils.h (gdb_mpz::read): Change buf and len parameters
        into one single gdb::array_view parameter.
        (gdb_mpz::write): Likewise.
        (gdb_mpq::read_fixed_point, gdb_mpq::write_fixed_point): Likewise.
        * gmp-utils.c (gdb_mpz::read): Change buf and len parameters
        into one single gdb::array_view parameter.
        Adjust implementation accordingly.
        (gdb_mpz::write): Likewise.
        (gdb_mpq::read_fixed_point, gdb_mpq::write_fixed_point): Likewise.
        * unittests/gmp-utils-selftests.c: Adapt following changes above.
        * valarith.c, valops.c, valprint.c, value.c: Likewise.

Change-Id: Ia6e9f077def06b92e089684164066fc81fff5e29
---
 gdb/gmp-utils.c                     | 25 +++++++++++++------------
 gdb/gmp-utils.h                     | 32 ++++++++++++++++++--------------
 gdb/unittests/gmp-utils-selftests.c | 12 ++++++++----
 gdb/valarith.c                      |  9 ++++++---
 gdb/valops.c                        | 11 +++++++----
 gdb/valprint.c                      |  3 ++-
 gdb/value.c                         |  3 ++-
 7 files changed, 56 insertions(+), 39 deletions(-)

diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index b70aaa3..6d80f13 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -37,12 +37,12 @@ gmp_string_asprintf (const char *fmt, ...)
 /* See gmp-utils.h.  */
 
 void
-gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+gdb_mpz::read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
 	       bool unsigned_p)
 {
-  mpz_import (val, 1 /* count */, -1 /* order */, len /* size */,
+  mpz_import (val, 1 /* count */, -1 /* order */, buf.size () /* size */,
 	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
-	      0 /* nails */, buf /* op */);
+	      0 /* nails */, buf.data () /* op */);
 
   if (!unsigned_p)
     {
@@ -51,7 +51,7 @@ gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
 	 was in fact negative, we need to adjust VAL accordingly.  */
       gdb_mpz max;
 
-      mpz_ui_pow_ui (max.val, 2, len * TARGET_CHAR_BIT - 1);
+      mpz_ui_pow_ui (max.val, 2, buf.size () * TARGET_CHAR_BIT - 1);
       if (mpz_cmp (val, max.val) >= 0)
 	mpz_submul_ui (val, max.val, 2);
     }
@@ -60,7 +60,7 @@ gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
 /* See gmp-utils.h.  */
 
 void
-gdb_mpz::write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
 		bool unsigned_p) const
 {
   gdb_mpz exported_val (val);
@@ -72,14 +72,15 @@ gdb_mpz::write (gdb_byte *buf, int len, enum bfd_endian byte_order,
 	 would be the same as our negative value.  */
       gdb_mpz neg_offset;
 
-      mpz_ui_pow_ui (neg_offset.val, 2, len * TARGET_CHAR_BIT);
+      mpz_ui_pow_ui (neg_offset.val, 2, buf.size () * TARGET_CHAR_BIT);
       mpz_add (exported_val.val, exported_val.val, neg_offset.val);
     }
 
   /* Start by clearing the buffer, as mpz_export only writes as many
      bytes as it needs (including none, if the value to export is zero.  */
-  memset (buf, 0, len);
-  mpz_export (buf, NULL /* count */, -1 /* order */, len /* size */,
+  memset (buf.data (), 0, buf.size ());
+  mpz_export (buf.data (), NULL /* count */, -1 /* order */,
+	      buf.size () /* size */,
 	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
 	      0 /* nails */, exported_val.val);
 }
@@ -120,12 +121,12 @@ gdb_mpq::get_rounded () const
 /* See gmp-utils.h.  */
 
 void
-gdb_mpq::read_fixed_point (const gdb_byte *buf, int len,
+gdb_mpq::read_fixed_point (gdb::array_view<const gdb_byte> buf,
 			   enum bfd_endian byte_order, bool unsigned_p,
 			   const gdb_mpq &scaling_factor)
 {
   gdb_mpz vz;
-  vz.read (buf, len, byte_order, unsigned_p);
+  vz.read (buf, byte_order, unsigned_p);
 
   mpq_set_z (val, vz.val);
   mpq_mul (val, val, scaling_factor.val);
@@ -134,7 +135,7 @@ gdb_mpq::read_fixed_point (const gdb_byte *buf, int len,
 /* See gmp-utils.h.  */
 
 void
-gdb_mpq::write_fixed_point (gdb_byte *buf, int len,
+gdb_mpq::write_fixed_point (gdb::array_view<gdb_byte> buf,
 			    enum bfd_endian byte_order, bool unsigned_p,
 			    const gdb_mpq &scaling_factor) const
 {
@@ -143,7 +144,7 @@ gdb_mpq::write_fixed_point (gdb_byte *buf, int len,
   mpq_div (unscaled.val, unscaled.val, scaling_factor.val);
 
   gdb_mpz unscaled_z = unscaled.get_rounded ();
-  unscaled_z.write (buf, len, byte_order, unsigned_p);
+  unscaled_z.write (buf, byte_order, unsigned_p);
 }
 
 /* A wrapper around xrealloc that we can then register with GMP
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index 7eed29a..ac6bb0d 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -96,17 +96,19 @@ struct gdb_mpz
      The return type can signed or unsigned, with no size restriction.  */
   template<typename T> T as_integer () const;
 
-  /* Set VAL by importing the number stored in the byte buffer (BUF),
-     given its size (LEN) and BYTE_ORDER.
+  /* Set VAL by importing the number stored in the byte array (BUF),
+     using the given BYTE_ORDER.  The size of the data to read is
+     the byte array's size.
 
      UNSIGNED_P indicates whether the number has an unsigned type.  */
-  void read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+  void read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
 	     bool unsigned_p);
 
-  /* Write VAL into BUF as a LEN-bytes number with the given BYTE_ORDER.
+  /* Write VAL into BUF as a number whose byte size is the size of BUF,
+     using the given BYTE_ORDER.
 
      UNSIGNED_P indicates whether the number has an unsigned type.  */
-  void write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+  void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
 	      bool unsigned_p) const;
 
   /* Return a string containing VAL.  */
@@ -167,24 +169,26 @@ struct gdb_mpq
   /* Return VAL rounded to the nearest integer.  */
   gdb_mpz get_rounded () const;
 
-  /* Set VAL from the contents of the given buffer (BUF), which
-     contains the unscaled value of a fixed point type object
-     with the given size (LEN) and byte order (BYTE_ORDER).
+  /* Set VAL from the contents of the given byte array (BUF), which
+     contains the unscaled value of a fixed point type object.
+     The byte size of the data is the size of BUF.
+
+     BYTE_ORDER provides the byte_order to use when reading the data.
 
      UNSIGNED_P indicates whether the number has an unsigned type.
      SCALING_FACTOR is the scaling factor to apply after having
      read the unscaled value from our buffer.  */
-  void read_fixed_point (const gdb_byte *buf, int len,
+  void read_fixed_point (gdb::array_view<const gdb_byte> buf,
 			 enum bfd_endian byte_order, bool unsigned_p,
 			 const gdb_mpq &scaling_factor);
 
-  /* Write VAL into BUF as a LEN-bytes fixed point value following
-     the given BYTE_ORDER.
+  /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
+     The size of BUF is used as the length to write the value into.
 
      UNSIGNED_P indicates whether the number has an unsigned type.
      SCALING_FACTOR is the scaling factor to apply before writing
      the unscaled value to our buffer.  */
-  void write_fixed_point (gdb_byte *buf, int len,
+  void write_fixed_point (gdb::array_view<gdb_byte> buf,
 			  enum bfd_endian byte_order, bool unsigned_p,
 			  const gdb_mpq &scaling_factor) const;
 
@@ -213,13 +217,13 @@ struct gdb_mpf
      UNSIGNED_P indicates whether the number has an unsigned type.
      SCALING_FACTOR is the scaling factor to apply after having
      read the unscaled value from our buffer.  */
-  void read_fixed_point (const gdb_byte *buf, int len,
+  void read_fixed_point (gdb::array_view<const gdb_byte> buf,
 			 enum bfd_endian byte_order, bool unsigned_p,
 			 const gdb_mpq &scaling_factor)
   {
     gdb_mpq tmp_q;
 
-    tmp_q.read_fixed_point (buf, len, byte_order, unsigned_p, scaling_factor);
+    tmp_q.read_fixed_point (buf, byte_order, unsigned_p, scaling_factor);
     mpf_set_q (val, tmp_q.val);
   }
 
diff --git a/gdb/unittests/gmp-utils-selftests.c b/gdb/unittests/gmp-utils-selftests.c
index e8c3c5c..933d523 100644
--- a/gdb/unittests/gmp-utils-selftests.c
+++ b/gdb/unittests/gmp-utils-selftests.c
@@ -109,7 +109,8 @@ store_and_read_back (T val, int buf_len, enum bfd_endian byte_order,
   mpz_set (actual.val, expected.val);
   mpz_sub_ui (actual.val, actual.val, 500);
 
-  actual.read (buf, buf_len, byte_order, !std::is_signed<T>::value);
+  actual.read (gdb::array_view<const gdb_byte> (buf, buf_len),
+	       byte_order, !std::is_signed<T>::value);
 }
 
 /* Test the gdb_mpz::read method over a reasonable range of values.
@@ -234,7 +235,8 @@ write_and_extract (T val, int buf_len, enum bfd_endian byte_order)
   SELF_CHECK (v.as_integer<T> () == val);
 
   gdb_byte *buf = (gdb_byte *) alloca (buf_len);
-  v.write (buf, buf_len, byte_order, !std::is_signed<T>::value);
+  v.write (gdb::array_view<gdb_byte> (buf, buf_len),
+	   byte_order, !std::is_signed<T>::value);
 
   return extract_integer<T> (buf, buf_len, byte_order);
 }
@@ -333,7 +335,8 @@ read_fp_test (int unscaled, const gdb_mpq &scaling_factor,
   gdb_byte buf[len];
   store_signed_integer (buf, len, byte_order, unscaled);
 
-  actual.read_fixed_point (buf, len, byte_order, 0, scaling_factor);
+  actual.read_fixed_point (gdb::array_view<const gdb_byte> (buf, len),
+			   byte_order, 0, scaling_factor);
 
   mpq_set_si (expected.val, unscaled, 1);
   mpq_mul (expected.val, expected.val, scaling_factor.val);
@@ -402,7 +405,8 @@ write_fp_test (int numerator, unsigned int denominator,
   gdb_mpq v;
   mpq_set_ui (v.val, numerator, denominator);
   mpq_canonicalize (v.val);
-  v.write_fixed_point (buf, len, byte_order, 0, scaling_factor);
+  v.write_fixed_point (gdb::array_view<gdb_byte> (buf, len),
+		       byte_order, 0, scaling_factor);
 
   return extract_unsigned_integer (buf, len, byte_order);
 }
diff --git a/gdb/valarith.c b/gdb/valarith.c
index f4497cd..8c47249 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -908,10 +908,12 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
     }
 
   gdb_mpq v1, v2, res;
-  v1.read_fixed_point (value_contents (arg1), TYPE_LENGTH (type1),
+  v1.read_fixed_point (gdb::array_view <const gdb_byte> (value_contents (arg1),
+							 TYPE_LENGTH (type1)),
 		       type_byte_order (type1), type1->is_unsigned (),
 		       fixed_point_scaling_factor (type1));
-  v2.read_fixed_point (value_contents (arg2), TYPE_LENGTH (type2),
+  v2.read_fixed_point (gdb::array_view <const gdb_byte> (value_contents (arg2),
+							 TYPE_LENGTH (type2)),
 		       type_byte_order (type2), type2->is_unsigned (),
 		       fixed_point_scaling_factor (type2));
 
@@ -919,7 +921,8 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   do { \
       val = allocate_value (type1); \
       (RESULT).write_fixed_point			\
-        (value_contents_raw (val), TYPE_LENGTH (type1), \
+        (gdb::array_view <gdb_byte> (value_contents_raw (val), \
+				     TYPE_LENGTH (type1)), \
 	 type_byte_order (type1), type1->is_unsigned (), \
 	 fixed_point_scaling_factor (type1)); \
      } while (0)
diff --git a/gdb/valops.c b/gdb/valops.c
index 0f84a70..b4c6d88 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -357,7 +357,8 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
     {
       gdb_mpz vz;
 
-      vz.read (value_contents (from_val), TYPE_LENGTH (from_type),
+      vz.read (gdb::array_view<const gdb_byte> (value_contents (from_val),
+						TYPE_LENGTH (from_type)),
 	       type_byte_order (from_type), from_type->is_unsigned ());
       mpq_set_z (vq.val, vz.val);
 
@@ -378,8 +379,9 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
   /* Finally, create the result value, and pack the unscaled value
      in it.  */
   struct value *result = allocate_value (to_type);
-  unscaled.write (value_contents_raw (result),
-		  TYPE_LENGTH (to_type), type_byte_order (to_type),
+  unscaled.write (gdb::array_view<gdb_byte> (value_contents_raw (result),
+					     TYPE_LENGTH (to_type)),
+		  type_byte_order (to_type),
 		  to_type->is_unsigned ());
 
   return result;
@@ -523,7 +525,8 @@ value_cast (struct type *type, struct value *arg2)
 	  gdb_mpq fp_val;
 
 	  fp_val.read_fixed_point
-	    (value_contents (arg2), TYPE_LENGTH (type2),
+	    (gdb::array_view<const gdb_byte> (value_contents (arg2),
+					      TYPE_LENGTH (type2)),
 	     type_byte_order (type2), type2->is_unsigned (),
 	     fixed_point_scaling_factor (type2));
 
diff --git a/gdb/valprint.c b/gdb/valprint.c
index abef002..21a4bf4 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -809,7 +809,8 @@ generic_val_print_fixed_point (struct value *val, struct ui_file *stream,
       const gdb_byte *valaddr = value_contents_for_printing (val);
       gdb_mpf f;
 
-      f.read_fixed_point (valaddr, TYPE_LENGTH (type),
+      f.read_fixed_point (gdb::array_view<const gdb_byte> (valaddr,
+							   TYPE_LENGTH (type)),
 			  type_byte_order (type), type->is_unsigned (),
 			  fixed_point_scaling_factor (type));
 
diff --git a/gdb/value.c b/gdb/value.c
index a0546af..7444e79 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2812,7 +2812,8 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
     case TYPE_CODE_FIXED_POINT:
       {
 	gdb_mpq vq;
-	vq.read_fixed_point (valaddr, len, byte_order, nosign,
+	vq.read_fixed_point (gdb::array_view<const gdb_byte> (valaddr, len),
+			     byte_order, nosign,
 			     fixed_point_scaling_factor (type));
 
 	gdb_mpz vz;
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro
  2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
  2020-11-15  8:49   ` [RFA 1/6] change gmp_string_asprintf to return an std::string Joel Brobecker
  2020-11-15  8:49   ` [RFA 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view Joel Brobecker
@ 2020-11-15  8:49   ` Joel Brobecker
  2020-11-15  8:49   ` [RFA 4/6] Make fixed_point_type_base_type a method of struct type Joel Brobecker
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:49 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This is one step further towards the removal of all these macros.

gdb/ChangeLog:

        * gdbtypes.h (struct type) <fixed_point_info, set_fixed_point_info>:
        New methods.
        (INIT_FIXED_POINT_SPECIFIC): Adjust.
        (TYPE_FIXED_POINT_INFO): Delete macro.
        (allocate_fixed_point_type_info): Change return type to void.
        * gdbtypes.c (copy_type_recursive): Replace the use of
        TYPE_FIXED_POINT_INFO by a call to the fixed_point_info method.
        (fixed_point_scaling_factor): Likewise.
        (allocate_fixed_point_type_info): Change return type to void.
        Adjust implementation accordingly.
        * dwarf2/read.c (finish_fixed_point_type): Replace the use of
        TYPE_FIXED_POINT_INFO by a call to the fixed_point_info method.
---
 gdb/dwarf2/read.c |  4 ++--
 gdb/gdbtypes.c    | 16 ++++++++--------
 gdb/gdbtypes.h    | 29 +++++++++++++++++++++++------
 3 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 3c5982629..cff5a4c 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -18162,7 +18162,7 @@ get_dwarf2_unsigned_rational_constant (struct die_info *die,
 }
 
 /* Assuming DIE corresponds to a fixed point type, finish the creation
-   of the corresponding TYPE by setting its TYPE_FIXED_POINT_INFO.
+   of the corresponding TYPE by setting its type-specific data.
    CU is the DIE's CU.  */
 
 static void
@@ -18232,7 +18232,7 @@ finish_fixed_point_type (struct type *type, struct die_info *die,
 		 sect_offset_str (die->sect_off));
     }
 
-  gdb_mpq &scaling_factor = TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+  gdb_mpq &scaling_factor = type->fixed_point_info ().scaling_factor;
 
   gdb_mpz tmp_z (scale_num);
   mpz_set (mpq_numref (scaling_factor.val), tmp_z.val);
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 1c1b0ff..255d9e3 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -5498,8 +5498,8 @@ copy_type_recursive (struct objfile *objfile,
       break;
     case TYPE_SPECIFIC_FIXED_POINT:
       INIT_FIXED_POINT_SPECIFIC (new_type);
-      TYPE_FIXED_POINT_INFO (new_type)->scaling_factor
-	= TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+      new_type->fixed_point_info ().scaling_factor
+	= type->fixed_point_info ().scaling_factor;
       break;
     case TYPE_SPECIFIC_INT:
       TYPE_SPECIFIC_FIELD (new_type) = TYPE_SPECIFIC_INT;
@@ -5821,11 +5821,11 @@ static const struct objfile_key<fixed_point_type_storage>
 
 /* See gdbtypes.h.  */
 
-fixed_point_type_info *
+void
 allocate_fixed_point_type_info (struct type *type)
 {
   std::unique_ptr<fixed_point_type_info> up (new fixed_point_type_info);
-  fixed_point_type_info *result;
+  fixed_point_type_info *info;
 
   if (TYPE_OBJFILE_OWNED (type))
     {
@@ -5833,17 +5833,17 @@ allocate_fixed_point_type_info (struct type *type)
 	= fixed_point_objfile_key.get (TYPE_OBJFILE (type));
       if (storage == nullptr)
 	storage = fixed_point_objfile_key.emplace (TYPE_OBJFILE (type));
-      result = up.get ();
+      info = up.get ();
       storage->push_back (std::move (up));
     }
   else
     {
       /* We just leak the memory, because that's what we do generally
 	 for non-objfile-attached types.  */
-      result = up.release ();
+      info = up.release ();
     }
 
-  return result;
+  type->set_fixed_point_info (info);
 }
 
 /* See gdbtypes.h.  */
@@ -5878,7 +5878,7 @@ fixed_point_scaling_factor (struct type *type)
 {
   type = fixed_point_type_base_type (type);
 
-  return TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+  return type->fixed_point_info ().scaling_factor;
 }
 
 \f
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 5f9ac27..b05d000 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1194,6 +1194,27 @@ struct type
     this->main_type->m_flag_endianity_not_default = endianity_is_not_default;
   }
 
+  /* * Assuming that THIS is a TYPE_CODE_FIXED_POINT, return a reference
+     to this type's fixed_point_info.  */
+
+  struct fixed_point_type_info &fixed_point_info () const
+  {
+    gdb_assert (this->code () == TYPE_CODE_FIXED_POINT);
+    gdb_assert (this->main_type->type_specific.fixed_point_info != nullptr);
+
+    return *this->main_type->type_specific.fixed_point_info;
+  }
+
+  /* * Assuming that THIS is a TYPE_CODE_FIXED_POINT, set this type's
+     fixed_point_info to INFO.  */
+
+  void set_fixed_point_info (struct fixed_point_type_info *info) const
+  {
+    gdb_assert (this->code () == TYPE_CODE_FIXED_POINT);
+
+    this->main_type->type_specific.fixed_point_info = info;
+  }
+
   /* * Return the dynamic property of the requested KIND from this type's
      list of dynamic properties.  */
   dynamic_prop *dyn_prop (dynamic_prop_node_kind kind) const;
@@ -1747,7 +1768,7 @@ extern void allocate_gnat_aux_type (struct type *);
    handled.  */
 #define INIT_FIXED_POINT_SPECIFIC(type) \
   (TYPE_SPECIFIC_FIELD (type) = TYPE_SPECIFIC_FIXED_POINT, \
-   TYPE_FIXED_POINT_INFO (type) = allocate_fixed_point_type_info (type))
+   allocate_fixed_point_type_info (type))
 
 #define TYPE_MAIN_TYPE(thistype) (thistype)->main_type
 #define TYPE_TARGET_TYPE(thistype) TYPE_MAIN_TYPE(thistype)->target_type
@@ -1845,9 +1866,6 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
   (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits == NULL ? 0 \
     : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index)))
 
-#define TYPE_FIXED_POINT_INFO(thistype) \
-  (TYPE_MAIN_TYPE(thistype)->type_specific.fixed_point_info)
-
 #define FIELD_NAME(thisfld) ((thisfld).name)
 #define FIELD_LOC_KIND(thisfld) ((thisfld).loc_kind)
 #define FIELD_BITPOS_LVAL(thisfld) ((thisfld).loc.bitpos)
@@ -2575,8 +2593,7 @@ extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);
 
 /* Allocate a fixed-point type info for TYPE.  This should only be
    called by INIT_FIXED_POINT_SPECIFIC.  */
-extern fixed_point_type_info *allocate_fixed_point_type_info
-  (struct type *type);
+extern void allocate_fixed_point_type_info (struct type *type);
 
 /* * When the type includes explicit byte ordering, return that.
    Otherwise, the byte ordering from gdbarch_byte_order for 
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA 4/6] Make fixed_point_type_base_type a method of struct type
  2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
                     ` (2 preceding siblings ...)
  2020-11-15  8:49   ` [RFA 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro Joel Brobecker
@ 2020-11-15  8:49   ` Joel Brobecker
  2020-11-15  8:49   ` [RFA 5/6] Make function fixed_point_scaling_factor " Joel Brobecker
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:49 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

As suggested by Simon, to logically connect this function to
the object it inspects.

Note that, logically, this method should be "const". Unfortunately,
the implementation iterates on struct type objects starting with "this",
and thus trying to declare the method "const" triggers a compilation
error.

gdb/ChangeLog:

        * gdbtypes.h (struct type) <fixed_point_type_base_type> New method,
        replacing the fixed_point_type_base_type function. All callers
        updated throughout this project.
        (fixed_point_type_base_type): Remove declaration.
        * gdbtypes.c (type::fixed_point_type_base_type): Replaces
        fixed_point_type_base_type.  Adjust implementation accordingly.
---
 gdb/ada-valprint.c |  2 +-
 gdb/gdbtypes.c     |  6 ++++--
 gdb/gdbtypes.h     | 17 +++++++++--------
 gdb/valprint.c     |  2 +-
 gdb/value.c        |  2 +-
 5 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c
index 482069a..6ddb584 100644
--- a/gdb/ada-valprint.c
+++ b/gdb/ada-valprint.c
@@ -1028,7 +1028,7 @@ ada_value_print_1 (struct value *val, struct ui_file *stream, int recurse,
     }
 
   if (is_fixed_point_type (type))
-    type = fixed_point_type_base_type (type);
+    type = type->fixed_point_type_base_type ();
 
   switch (type->code ())
     {
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 255d9e3..eb176c9 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -5861,8 +5861,10 @@ is_fixed_point_type (struct type *type)
 /* See gdbtypes.h.  */
 
 struct type *
-fixed_point_type_base_type (struct type *type)
+type::fixed_point_type_base_type ()
 {
+  struct type *type = this;
+
   while (check_typedef (type)->code () == TYPE_CODE_RANGE)
     type = TYPE_TARGET_TYPE (check_typedef (type));
   type = check_typedef (type);
@@ -5876,7 +5878,7 @@ fixed_point_type_base_type (struct type *type)
 const gdb_mpq &
 fixed_point_scaling_factor (struct type *type)
 {
-  type = fixed_point_type_base_type (type);
+  type = type->fixed_point_type_base_type ();
 
   return type->fixed_point_info ().scaling_factor;
 }
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index b05d000..19f95f4 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1215,6 +1215,15 @@ struct type
     this->main_type->type_specific.fixed_point_info = info;
   }
 
+  /* * Assuming that THIS is a TYPE_CODE_FIXED_POINT, return its base type.
+
+     In other words, this returns the type after having peeled all
+     intermediate type layers (such as TYPE_CODE_RANGE, for instance).
+     The TYPE_CODE of the type returned is guaranteed to be
+     a TYPE_CODE_FIXED_POINT.  */
+
+  struct type *fixed_point_type_base_type ();
+
   /* * Return the dynamic property of the requested KIND from this type's
      list of dynamic properties.  */
   dynamic_prop *dyn_prop (dynamic_prop_node_kind kind) const;
@@ -2580,14 +2589,6 @@ extern int type_not_associated (const struct type *type);
    a range type whose base type is a TYPE_CODE_FIXED_POINT.  */
 extern bool is_fixed_point_type (struct type *type);
 
-/* Assuming that TYPE is a fixed point type, return its base type.
-
-   In other words, this returns the type after having peeled all
-   intermediate type layers (such as TYPE_CODE_RANGE, for instance).
-   The TYPE_CODE of the type returned is guaranteed to be
-   a TYPE_CODE_FIXED_POINT.  */
-extern struct type *fixed_point_type_base_type (struct type *type);
-
 /* Given TYPE, which is a fixed point type, return its scaling factor.  */
 extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);
 
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 21a4bf4..66f8de9 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -872,7 +872,7 @@ generic_value_print (struct value *val, struct ui_file *stream, int recurse,
   type = check_typedef (type);
 
   if (is_fixed_point_type (type))
-    type = fixed_point_type_base_type (type);
+    type = type->fixed_point_type_base_type ();
 
   switch (type->code ())
     {
diff --git a/gdb/value.c b/gdb/value.c
index 7444e79..f3f5169 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2759,7 +2759,7 @@ LONGEST
 unpack_long (struct type *type, const gdb_byte *valaddr)
 {
   if (is_fixed_point_type (type))
-    type = fixed_point_type_base_type (type);
+    type = type->fixed_point_type_base_type ();
 
   enum bfd_endian byte_order = type_byte_order (type);
   enum type_code code = type->code ();
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA 5/6] Make function fixed_point_scaling_factor a method of struct type
  2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
                     ` (3 preceding siblings ...)
  2020-11-15  8:49   ` [RFA 4/6] Make fixed_point_type_base_type a method of struct type Joel Brobecker
@ 2020-11-15  8:49   ` Joel Brobecker
  2020-11-15  8:49   ` [RFA 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by lambda Joel Brobecker
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:49 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This logically connects this function to the object it inspects.

gdb/ChangeLog:

        * gdbtypes.h (struct type) <fixed_point_scaling_factor>: New method,
        replacing fixed_point_scaling_factor.  All callers updated
        throughout this project.
        (fixed_point_scaling_factor): Delete declaration.
        * gdbtypes.c (type::fixed_point_scaling_factor): Replaces
        fixed_point_scaling_factor.  Adjust implementation accordingly.
---
 gdb/gdbtypes.c  | 6 +++---
 gdb/gdbtypes.h  | 8 +++++---
 gdb/typeprint.c | 2 +-
 gdb/valarith.c  | 6 +++---
 gdb/valops.c    | 6 +++---
 gdb/valprint.c  | 2 +-
 gdb/value.c     | 2 +-
 7 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index eb176c9..79c8121 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -4922,7 +4922,7 @@ static void
 print_fixed_point_type_info (struct type *type, int spaces)
 {
   printfi_filtered (spaces + 2, "scaling factor: %s\n",
-		    fixed_point_scaling_factor (type).str ().c_str ());
+		    type->fixed_point_scaling_factor ().str ().c_str ());
 }
 
 static struct obstack dont_print_type_obstack;
@@ -5876,9 +5876,9 @@ type::fixed_point_type_base_type ()
 /* See gdbtypes.h.  */
 
 const gdb_mpq &
-fixed_point_scaling_factor (struct type *type)
+type::fixed_point_scaling_factor ()
 {
-  type = type->fixed_point_type_base_type ();
+  struct type *type = this->fixed_point_type_base_type ();
 
   return type->fixed_point_info ().scaling_factor;
 }
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 19f95f4..dc37f63 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1224,6 +1224,11 @@ struct type
 
   struct type *fixed_point_type_base_type ();
 
+  /* * Assuming that THIS is a TYPE_CODE_FIXED_POINT, return its scaling
+     factor.  */
+
+  const gdb_mpq &fixed_point_scaling_factor ();
+
   /* * Return the dynamic property of the requested KIND from this type's
      list of dynamic properties.  */
   dynamic_prop *dyn_prop (dynamic_prop_node_kind kind) const;
@@ -2589,9 +2594,6 @@ extern int type_not_associated (const struct type *type);
    a range type whose base type is a TYPE_CODE_FIXED_POINT.  */
 extern bool is_fixed_point_type (struct type *type);
 
-/* Given TYPE, which is a fixed point type, return its scaling factor.  */
-extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);
-
 /* Allocate a fixed-point type info for TYPE.  This should only be
    called by INIT_FIXED_POINT_SPECIFIC.  */
 extern void allocate_fixed_point_type_info (struct type *type);
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 0dd3b1c..a3fc9cc 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -667,7 +667,7 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream)
 void
 print_type_fixed_point (struct type *type, struct ui_file *stream)
 {
-  std::string small_img = fixed_point_scaling_factor (type).str ();
+  std::string small_img = type->fixed_point_scaling_factor ().str ();
 
   fprintf_filtered (stream, "%s-byte fixed point (small = %s)",
 		    pulongest (TYPE_LENGTH (type)), small_img.c_str ());
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 8c47249..1c6ef2c 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -911,11 +911,11 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   v1.read_fixed_point (gdb::array_view <const gdb_byte> (value_contents (arg1),
 							 TYPE_LENGTH (type1)),
 		       type_byte_order (type1), type1->is_unsigned (),
-		       fixed_point_scaling_factor (type1));
+		       type1->fixed_point_scaling_factor ());
   v2.read_fixed_point (gdb::array_view <const gdb_byte> (value_contents (arg2),
 							 TYPE_LENGTH (type2)),
 		       type_byte_order (type2), type2->is_unsigned (),
-		       fixed_point_scaling_factor (type2));
+		       type2->fixed_point_scaling_factor ());
 
 #define INIT_VAL_WITH_FIXED_POINT_VAL(RESULT) \
   do { \
@@ -924,7 +924,7 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
         (gdb::array_view <gdb_byte> (value_contents_raw (val), \
 				     TYPE_LENGTH (type1)), \
 	 type_byte_order (type1), type1->is_unsigned (), \
-	 fixed_point_scaling_factor (type1)); \
+	 type1->fixed_point_scaling_factor ()); \
      } while (0)
 
   switch (op)
diff --git a/gdb/valops.c b/gdb/valops.c
index b4c6d88..bfddf62 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -363,7 +363,7 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
       mpq_set_z (vq.val, vz.val);
 
       if (is_fixed_point_type (from_type))
-	mpq_mul (vq.val, vq.val, fixed_point_scaling_factor (from_type).val);
+	mpq_mul (vq.val, vq.val, from_type->fixed_point_scaling_factor ().val);
     }
 
   else
@@ -373,7 +373,7 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
   /* Divide that value by the scaling factor to obtain the unscaled
      value, first in rational form, and then in integer form.  */
 
-  mpq_div (vq.val, vq.val, fixed_point_scaling_factor (to_type).val);
+  mpq_div (vq.val, vq.val, to_type->fixed_point_scaling_factor ().val);
   gdb_mpz unscaled = vq.get_rounded ();
 
   /* Finally, create the result value, and pack the unscaled value
@@ -528,7 +528,7 @@ value_cast (struct type *type, struct value *arg2)
 	    (gdb::array_view<const gdb_byte> (value_contents (arg2),
 					      TYPE_LENGTH (type2)),
 	     type_byte_order (type2), type2->is_unsigned (),
-	     fixed_point_scaling_factor (type2));
+	     type2->fixed_point_scaling_factor ());
 
 	  struct value *v = allocate_value (to_type);
 	  target_float_from_host_double (value_contents_raw (v),
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 66f8de9..0d66ed4 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -812,7 +812,7 @@ generic_val_print_fixed_point (struct value *val, struct ui_file *stream,
       f.read_fixed_point (gdb::array_view<const gdb_byte> (valaddr,
 							   TYPE_LENGTH (type)),
 			  type_byte_order (type), type->is_unsigned (),
-			  fixed_point_scaling_factor (type));
+			  type->fixed_point_scaling_factor ());
 
       const char *fmt = TYPE_LENGTH (type) < 4 ? "%.11Fg" : "%.17Fg";
       std::string str = gmp_string_asprintf (fmt, f.val);
diff --git a/gdb/value.c b/gdb/value.c
index f3f5169..0b3d463 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2814,7 +2814,7 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
 	gdb_mpq vq;
 	vq.read_fixed_point (gdb::array_view<const gdb_byte> (valaddr, len),
 			     byte_order, nosign,
-			     fixed_point_scaling_factor (type));
+			     type->fixed_point_scaling_factor ());
 
 	gdb_mpz vz;
 	mpz_tdiv_q (vz.val, mpq_numref (vq.val), mpq_denref (vq.val));
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by lambda
  2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
                     ` (4 preceding siblings ...)
  2020-11-15  8:49   ` [RFA 5/6] Make function fixed_point_scaling_factor " Joel Brobecker
@ 2020-11-15  8:49   ` Joel Brobecker
  2020-11-16  1:01   ` RFA: Various enhancements to the fixed-point support implementation Simon Marchi
  2020-11-22 11:14   ` RFA v2: " Joel Brobecker
  7 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-15  8:49 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

gdb/ChangeLog (Simon Marchi  <simark@simark.ca>):

        * valarith.c (fixed_point_binop): Replace the
        INIT_VAL_WITH_FIXED_POINT_VAL macro by a lambda.  Update all
        users accordingly.
---
 gdb/valarith.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/gdb/valarith.c b/gdb/valarith.c
index 1c6ef2c..7be91ed 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -917,44 +917,48 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
 		       type_byte_order (type2), type2->is_unsigned (),
 		       type2->fixed_point_scaling_factor ());
 
-#define INIT_VAL_WITH_FIXED_POINT_VAL(RESULT) \
-  do { \
-      val = allocate_value (type1); \
-      (RESULT).write_fixed_point			\
-        (gdb::array_view <gdb_byte> (value_contents_raw (val), \
-				     TYPE_LENGTH (type1)), \
-	 type_byte_order (type1), type1->is_unsigned (), \
-	 type1->fixed_point_scaling_factor ()); \
-     } while (0)
+  auto fixed_point_to_value = [type1] (const gdb_mpq &fp)
+    {
+      value *fp_val = allocate_value (type1);
+
+      fp.write_fixed_point
+	(gdb::array_view <gdb_byte> (value_contents_raw (fp_val),
+				     TYPE_LENGTH (type1)),
+	 type_byte_order (type1),
+	 type1->is_unsigned (),
+	 type1->fixed_point_scaling_factor ());
+
+      return fp_val;
+    };
 
   switch (op)
     {
     case BINOP_ADD:
       mpq_add (res.val, v1.val, v2.val);
-      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      val = fixed_point_to_value (res);
       break;
 
     case BINOP_SUB:
       mpq_sub (res.val, v1.val, v2.val);
-      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      val = fixed_point_to_value (res);
       break;
 
     case BINOP_MIN:
-      INIT_VAL_WITH_FIXED_POINT_VAL (mpq_cmp (v1.val, v2.val) < 0 ? v1 : v2);
+      val = fixed_point_to_value (mpq_cmp (v1.val, v2.val) < 0 ? v1 : v2);
       break;
 
     case BINOP_MAX:
-      INIT_VAL_WITH_FIXED_POINT_VAL (mpq_cmp (v1.val, v2.val) > 0 ? v1 : v2);
+      val = fixed_point_to_value (mpq_cmp (v1.val, v2.val) > 0 ? v1 : v2);
       break;
 
     case BINOP_MUL:
       mpq_mul (res.val, v1.val, v2.val);
-      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      val = fixed_point_to_value (res);
       break;
 
     case BINOP_DIV:
       mpq_div (res.val, v1.val, v2.val);
-      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      val = fixed_point_to_value (res);
       break;
 
     case BINOP_EQUAL:
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [pushed/v2 1/9] gdb/configure: Add --with-libgmp-prefix option
  2020-11-15  8:35   ` [pushed/v2 1/9] gdb/configure: Add --with-libgmp-prefix option Joel Brobecker
@ 2020-11-15 15:52     ` Bernd Edlinger
  2020-11-16  3:45       ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Bernd Edlinger @ 2020-11-15 15:52 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches; +Cc: Simon Marchi

[-- Attachment #1: Type: text/plain, Size: 1670 bytes --]

Hi Joel,

On 11/15/20 9:35 AM, Joel Brobecker wrote:
> This patch allows a user to tell gdb's configure script where
> his GMP library is installed.
> 
> gdb/ChangeLog:
> 
>         * configure.ac: Add support for --with-libgmp-prefix.
>         * Makefile.in (LIBGMP): New variable.
>         (CLIBS): Include $(LIBGMP).
>         * configure, config.in: Regenerate
> ---
>  gdb/ChangeLog    |   7 +
>  gdb/Makefile.in  |   5 +-
>  gdb/config.in    |   3 +
>  gdb/configure    | 488 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/configure.ac |   5 +
>  5 files changed, 507 insertions(+), 1 deletion(-)
> 

I noticed that this does not allow to build gmp in-tree like it is
possible for gcc.  I tried to overcome this by the attached patch.

While doing so, I also noticed an incompatibility with the top level
configure stript, which advertises, and passes -with-gmp-include
and -with-gmp-lib if in-tree gmp is found.

So the --with-libgmp-prefix is not that the top level configure
script suggests:

$ ./configure --help | grep gmp
  --with-gmp-dir=PATH     this option has been REMOVED
  --with-gmp=PATH         specify prefix directory for the installed GMP
                          --with-gmp-include=PATH/include plus
                          --with-gmp-lib=PATH/lib
  --with-gmp-include=PATH specify directory for installed GMP include files
  --with-gmp-lib=PATH     specify directory for the installed GMP library

What do you think, can we allow these traditional configure options
additional to the new --with-libgmp-prefix?

Can we the top level Makefile.def change in binutils-gdb or has this
be checked-in first in gcc?


Thanks
Bernd.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Enable-GDB-build-with-in-tree-GMP.patch --]
[-- Type: text/x-patch; name="0001-Enable-GDB-build-with-in-tree-GMP.patch", Size: 5336 bytes --]

From ec85565bb963df25bdd46db19e1aeadc596c8424 Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Sun, 15 Nov 2020 15:37:22 +0100
Subject: [PATCH] Enable GDB build with in-tree GMP

Add --with-gmp= --with-gmp-include and --with-gmp-lib=
for compatibility with top level configure script.

2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* Makefile.def: Prepare for GDB build with intree GMP.
	* Makefile.in: Regenerate.

gdb:
2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* configure.ac: Add --with-gmp= --with-gmp-include= and --with-gmp-lib=
	for compatibility with top level configure script.
	* configure: Regenerate.
---
 Makefile.def     |  4 +++-
 Makefile.in      |  3 ++-
 gdb/configure    | 35 +++++++++++++++++++++++++++++++++++
 gdb/configure.ac | 16 ++++++++++++++++
 4 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/Makefile.def b/Makefile.def
index 089e70a..89aaef5 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -115,7 +115,8 @@ host_modules= { module= zlib; no_install=true; no_check=true;
 host_modules= { module= gnulib; };
 host_modules= { module= gdbsupport; };
 host_modules= { module= gdbserver; };
-host_modules= { module= gdb; };
+host_modules= { module= gdb;
+		extra_configure_flags='@extra_mpfr_configure_flags@';};
 host_modules= { module= expect; };
 host_modules= { module= guile; };
 host_modules= { module= tk; };
@@ -391,6 +392,7 @@ dependencies = { module=all-intl; on=all-libiconv; };
 
 // Host modules specific to gdb.
 dependencies = { module=configure-gdb; on=all-intl; };
+dependencies = { module=configure-gdb; on=all-gmp; };
 dependencies = { module=configure-gdb; on=configure-sim; };
 dependencies = { module=configure-gdb; on=all-bfd; };
 dependencies = { module=configure-gdb; on=all-gnulib; };
diff --git a/Makefile.in b/Makefile.in
index fe34132..93780b7 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -29491,7 +29491,7 @@ configure-gdb:
 	  $$s/$$module_srcdir/configure \
 	  --srcdir=$${topdir}/$$module_srcdir \
 	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
-	  --target=${target_alias}  \
+	  --target=${target_alias} @extra_mpfr_configure_flags@ \
 	  || exit 1
 @endif gdb
 
@@ -52449,6 +52449,7 @@ configure-libcc1: maybe-configure-gcc
 all-libcc1: maybe-all-gcc
 all-utils: maybe-all-libiberty
 configure-gdb: maybe-all-intl
+configure-gdb: maybe-all-gmp
 configure-gdb: maybe-all-bfd
 configure-gdb: maybe-all-libiconv
 all-gdb: maybe-all-libiberty
diff --git a/gdb/configure b/gdb/configure
index a3e73b4..44bbce3 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -899,6 +899,9 @@ with_jit_reader_dir
 with_expat
 with_libexpat_prefix
 with_libexpat_type
+with_gmp_include
+with_gmp_lib
+with_gmp
 with_libgmp_prefix
 with_libgmp_type
 with_mpfr
@@ -1644,6 +1647,9 @@ Optional Packages:
   --with-libexpat-prefix[=DIR]  search for libexpat in DIR/include and DIR/lib
   --without-libexpat-prefix     don't search for libexpat in includedir and libdir
   --with-libexpat-type=TYPE     type of library to search for (auto/static/shared)
+  --with-gmp-include=DIR  GMP include directory
+  --with-gmp-lib=DIR      GMP lib directory
+  --with-gmp=DIR          GMP install directory
   --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
   --without-libgmp-prefix     don't search for libgmp in includedir and libdir
   --with-libgmp-type=TYPE     type of library to search for (auto/static/shared)
@@ -9990,6 +9996,35 @@ done
   fi
 fi
 
+
+# Check whether --with-gmp_include was given.
+if test "${with_gmp_include+set}" = set; then :
+  withval=$with_gmp_include; CPPFLAGS="$CPPFLAGS -I$withval"
+fi
+
+
+# Check whether --with-gmp_lib was given.
+if test "${with_gmp_lib+set}" = set; then :
+  withval=$with_gmp_lib; LDFLAGS="$LDFLAGS -L$withval"
+fi
+
+
+# Check whether --with-gmp was given.
+if test "${with_gmp+set}" = set; then :
+  withval=$with_gmp;
+   if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
+      CPPFLAGS="$CPPFLAGS -I$withval/include"
+      LDFLAGS="$LDFLAGS -L$withval/lib"
+   else
+      { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.
+See \`config.log' for more details" "$LINENO" 5; }
+   fi
+
+fi
+
+
 # Verify that we have a usable GMP library.
 
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 32f25d9..a6a7cd3 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -683,6 +683,22 @@ else
   fi
 fi
 
+AC_ARG_WITH(gmp_include,
+   [  --with-gmp-include=DIR  GMP include directory ],
+   CPPFLAGS="$CPPFLAGS -I$withval")
+AC_ARG_WITH(gmp_lib,
+   [  --with-gmp-lib=DIR      GMP lib directory ],
+   LDFLAGS="$LDFLAGS -L$withval")
+AC_ARG_WITH(gmp,
+   [  --with-gmp=DIR          GMP install directory ], [
+   if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
+      CPPFLAGS="$CPPFLAGS -I$withval/include"
+      LDFLAGS="$LDFLAGS -L$withval/lib"
+   else
+      AC_MSG_FAILURE([Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.])
+   fi
+  ])
+
 # Verify that we have a usable GMP library.
 AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
                       [mpz_t n;
-- 
1.9.1


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects
  2020-11-15  6:33     ` Joel Brobecker
@ 2020-11-16  0:13       ` Simon Marchi
  0 siblings, 0 replies; 140+ messages in thread
From: Simon Marchi @ 2020-11-16  0:13 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: GDB patches

On 2020-11-15 1:33 a.m., Joel Brobecker wrote:
> In pratice, this wouldn't work. The main reason-d'etre for this function
> is that fixed point types can be both a TYPE_CODE_FIXED_POINT as well
> as a TYPE_CODE_RANGE of a TYPE_CODE_FIXED_POINT. What the function
> above does is first call fixed_point_type_base_type in order to get
> to the type which actually has the fixed_point_info, and then from
> there accesses the scaling factor.
> 
> What we can do is make that a method of struct type instead...
> This is what the attached patch does.

Ahh, I see.  Well, I think that's fine as-is.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 7/9] Add ptype support for DWARF-based fixed-point types
  2020-11-15  7:09       ` Joel Brobecker
@ 2020-11-16  0:16         ` Simon Marchi
  2020-11-16  4:03           ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-16  0:16 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On 2020-11-15 2:09 a.m., Joel Brobecker wrote:
>>>> +        gdb_test_no_output "set language $lang" \
>>>> +            "set language to $lang for ptype test"
>>>> +
>>>> +        gdb_test "ptype pck__fp1_var" $fp1_re
>>>> +
>>>> +        gdb_test "ptype pck__fp2_var" $fp2_re
>>>> +
>>>> +        gdb_test "ptype pck__fp3_var" $fp3_re
>>>> +
>>>> +        if { $lang == "modula-2" || $lang == "pascal" } {
>>>> +            setup_xfail "*-*-*" "not supported by language"
>>>> +        }
>>>
>>> Can you give more details about this?  What prevents these languages
>>> from printing <range type>?  I'm confused, because as far as I can tell
>>> C doesn't support range types more than these two languages, and it's
>>> able to print <range type>.
>>
>> Both trigger the following error:
>>
>>     (gdb) ptype pck__fp1_range_var
>>     type = [Invalid type code in symbol table.
>>
>> It didn't seem to be worth the effort of going any further than that,
>> because I didn't didn't think either language would have fixed point
>> types.
>
> I should probably expand a bit: I tried to make the implementation
> of this feature as generic as possible, so that all current and
> future languages that provide support for these kinds of types can
> benefit from it with as little work as possible. For some reason,
> this doesn't work for M2 and Pascal, and the decision I made at
> the time was to ignore these issues on the basis that these are errors
> a real user is unlikely to hit.

My guess is that it works for C just because of this single case in its
type print function:

https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/c-typeprint.c;h=10631fff9a8006baf885dcd03720074d5f95f8b9;hb=5778e0dd5d7bb872398a136b6504b9b99d5ce434#l1683

If it's a matter of just adding this case to the m2 and pascal in their
type print functions, I think it would be nice simply to avoid the
special case in the test.  If it's anything more complex than that, then
I agree with you that it's not worth it.

Simon


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 1/6] change gmp_string_asprintf to return an std::string
  2020-11-15  8:49   ` [RFA 1/6] change gmp_string_asprintf to return an std::string Joel Brobecker
@ 2020-11-16  0:41     ` Simon Marchi
  2020-11-16  3:55       ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-16  0:41 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches


On 2020-11-15 3:49 a.m., Joel Brobecker wrote:
> This was suggested by Simon during a code review of this package upstream.
> The upside is that this makes the function's API more natural and C++.
> The downside is an extra malloc, which might be the reason why we went
> for using a unique_xmalloc_ptr in the first place. Since this function
> is not expected to be called frequently, the API improvement might be
> worth the performance impact.

In fact, I was thinking of doing the exact same thing as the
string_print function.  By calling vsnprintf with a NULL buffer, you can
get how many bytes would be required to hold the result.  You can then
allocate the required buffer and call vsprintf with it.

So, there's no extra allocation, although it requires formatting twice.
But if it's good enough for string_printf (which is heavily used), it's
good enough for gmp_string_printf.

I was just wondering whether gmp_vsnprintf supported passing a NULL
buffer like vsnprintf does, and it seems like yes.  I tried the
implementation shown below and it works (with gmp 6.2.0 at least).

I would suggest renaming the function to gmp_string_printf for symmetry
with plain string_printf.

std::string
gmp_string_asprintf (const char *fmt, ...)
{
  va_list vp;

  va_start (vp, fmt);
  int size = gmp_vsnprintf (NULL, 0, fmt, vp);
  va_end (vp);

  std::string str (size, '\0');

  /* C++11 and later guarantee std::string uses contiguous memory and
     always includes the terminating '\0'.  */
  va_start (vp, fmt);
  gmp_vsprintf (&str[0], fmt, vp);
  va_end (vp);

  return str;
}

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view
  2020-11-15  8:49   ` [RFA 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view Joel Brobecker
@ 2020-11-16  0:52     ` Simon Marchi
  2020-11-16 23:05       ` Pedro Alves
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-16  0:52 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

On 2020-11-15 3:49 a.m., Joel Brobecker wrote:
> This commit changes the interfaces of some of the methods declared
> in gmp-utils to take a gdb::array_view of gdb_byte instead of a
> (gdb_byte *, size) couple.
>
> This makes these methods' API probably more C++-idiomatic.
> With the way things are structured, this change introduces a minor
> extra complication at the point of call of these methods, since
> the data available there is not in the form of an array_view,
> and thus the array_view needs to be constructed on the spot.

I'd suggest using gdb::make_array_view (ptr, len) instead of the
array_view constructor.  This way, you don't need to specify the
template type, it's automatically deduced, so it's a bit less verbose.
Otherwise, LGTM.

To alleviate the need to create array_view at all these points, I could
very well imagine (as a future change that would probably be quite
invasive) that the various value_contents functions could return
array_view instead of plain pointers.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: RFA: Various enhancements to the fixed-point support implementation
  2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
                     ` (5 preceding siblings ...)
  2020-11-15  8:49   ` [RFA 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by lambda Joel Brobecker
@ 2020-11-16  1:01   ` Simon Marchi
  2020-11-22 11:14   ` RFA v2: " Joel Brobecker
  7 siblings, 0 replies; 140+ messages in thread
From: Simon Marchi @ 2020-11-16  1:01 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

On 2020-11-15 3:49 a.m., Joel Brobecker wrote:
> Hello,
> 
> The following patch series implements the suggestions Simon made
> in reviewing the first patch series, which I felt deserved to be
> their own patch. I think it allows us to review those changes
> independently of the first implementation (which Simon said was
> find to push).
> 
>   - [RFA 1/6] change gmp_string_asprintf to return an std::string
>   - [RFA 2/6] gmp-utils: Convert the read/write methods to using
>   - [RFA 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro
>   - [RFA 4/6] Make fixed_point_type_base_type a method of struct type
>   - [RFA 5/6] Make function fixed_point_scaling_factor a method of struct
>   - [RFA 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by
> 
> The patches were tested on x86_64-linux.
> 
> Thank you!
> -- 
> Joel
> 

Apart from my comments on patches 1 and 2, it all LGTM, thanks!

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [pushed/v2 1/9] gdb/configure: Add --with-libgmp-prefix option
  2020-11-15 15:52     ` Bernd Edlinger
@ 2020-11-16  3:45       ` Joel Brobecker
  2020-11-16 14:20         ` Bernd Edlinger
  0 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-16  3:45 UTC (permalink / raw)
  To: Bernd Edlinger; +Cc: gdb-patches, Simon Marchi

Hi Bernd,

> I noticed that this does not allow to build gmp in-tree like it is
> possible for gcc.  I tried to overcome this by the attached patch.

Indeed. It's not something I had considered.

> While doing so, I also noticed an incompatibility with the top level
> configure stript, which advertises, and passes -with-gmp-include
> and -with-gmp-lib if in-tree gmp is found.
> 
> So the --with-libgmp-prefix is not that the top level configure
> script suggests:
> 
> $ ./configure --help | grep gmp
>   --with-gmp-dir=PATH     this option has been REMOVED
>   --with-gmp=PATH         specify prefix directory for the installed GMP
>                           --with-gmp-include=PATH/include plus
>                           --with-gmp-lib=PATH/lib
>   --with-gmp-include=PATH specify directory for installed GMP include files
>   --with-gmp-lib=PATH     specify directory for the installed GMP library
> 
> What do you think, can we allow these traditional configure options
> additional to the new --with-libgmp-prefix?

Can you check if these options are actually used elsewhere in
the binutils-gdb project? The idea I have in the back of my mind
is to see whether we can use the same options as the ones we've been
using in GDB or not. The fact that we have an AC_LIB_HAVE_LINKFLAGS
macro which takes care of handling dependencies for us tells me
that we are transitioning away from the model above where we add
the options "by hand" in configure.ac, and instead rely on the new
macro.

One thing I did note is that GDB has some options for MPFR support
and in particular, it has --with-mpfr:

  --with-mpfr             include MPFR support (auto/yes/no)

As you can see, the --with-gmp option you propose is not consistent
with the above.

Unfortunately, in digging further, I found that toplevel configure
*also* has --with-mpfr, with a different meaning:

  --with-mpfr=PATH        specify prefix directory for installed MPFR package.
                          Equivalent to --with-mpfr-include=PATH/include plus
                          --with-mpfr-lib=PATH/lib

The way we expect people to configure GDB is to configure it as
part of the binutils-gdb project, so I don't see how GDB's --with-mpfr
could work, unless the top-level configury is more elaborate than
I remembered.

Depending on the above, perhaps it might be better to actually
to change the top-level configury to advertise the --with-gmp-prefix
options instead of adding parallel support for the old-style
options in GDB's configury. And while at it, perhaps start deprecating
the old-style ones in the top-level configury.

One more note: For me, I think we can handle the question of
in-tree building independently of the question of the configury's
options -- which is good, because I think the latterm might require
a bit of discussion.

> Can we the top level Makefile.def change in binutils-gdb or has this
> be checked-in first in gcc?

That's a good question. I *think* that binutils + GDB now have
ownership, but I might be wrong. Hopefully others know better.
If not, I will ask.

> 2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>
> 
> 	* Makefile.def: Prepare for GDB build with intree GMP.
> 	* Makefile.in: Regenerate.
> 
> gdb:
> 2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>
> 
> 	* configure.ac: Add --with-gmp= --with-gmp-include= and --with-gmp-lib=
> 	for compatibility with top level configure script.
> 	* configure: Regenerate.

Looking at your patch, I'm wondering how this would all fit together...
Would it all work automatically (like it does for libiconv, I believe),
or where you planning on having to pass --with-gmp options ?

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 1/6] change gmp_string_asprintf to return an std::string
  2020-11-16  0:41     ` Simon Marchi
@ 2020-11-16  3:55       ` Joel Brobecker
  2020-11-16 20:10         ` Simon Marchi
  0 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-16  3:55 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

Hi Simon,

> On 2020-11-15 3:49 a.m., Joel Brobecker wrote:
> > This was suggested by Simon during a code review of this package upstream.
> > The upside is that this makes the function's API more natural and C++.
> > The downside is an extra malloc, which might be the reason why we went
> > for using a unique_xmalloc_ptr in the first place. Since this function
> > is not expected to be called frequently, the API improvement might be
> > worth the performance impact.
> 
> In fact, I was thinking of doing the exact same thing as the
> string_print function.  By calling vsnprintf with a NULL buffer, you can
> get how many bytes would be required to hold the result.  You can then
> allocate the required buffer and call vsprintf with it.
> 
> So, there's no extra allocation, although it requires formatting twice.
> But if it's good enough for string_printf (which is heavily used), it's
> good enough for gmp_string_printf.
> 
> I was just wondering whether gmp_vsnprintf supported passing a NULL
> buffer like vsnprintf does, and it seems like yes.  I tried the
> implementation shown below and it works (with gmp 6.2.0 at least).
> 
> I would suggest renaming the function to gmp_string_printf for symmetry
> with plain string_printf.
> 
> std::string
> gmp_string_asprintf (const char *fmt, ...)
> {
>   va_list vp;
> 
>   va_start (vp, fmt);
>   int size = gmp_vsnprintf (NULL, 0, fmt, vp);
>   va_end (vp);
> 
>   std::string str (size, '\0');
> 
>   /* C++11 and later guarantee std::string uses contiguous memory and
>      always includes the terminating '\0'.  */
>   va_start (vp, fmt);
>   gmp_vsprintf (&str[0], fmt, vp);
>   va_end (vp);
> 
>   return str;
> }

Thanks for the clear suggestion. We can do the above.

I don't know if that's really important in the context of this function
which I don't think will be called often, but your suggestion raises
a question: Which option should we favor? Allocating a memory region
twice, or formatting twice...

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 7/9] Add ptype support for DWARF-based fixed-point types
  2020-11-16  0:16         ` Simon Marchi
@ 2020-11-16  4:03           ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-16  4:03 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

> My guess is that it works for C just because of this single case in its
> type print function:
> 
> https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/c-typeprint.c;h=10631fff9a8006baf885dcd03720074d5f95f8b9;hb=5778e0dd5d7bb872398a136b6504b9b99d5ce434#l1683
> 
> If it's a matter of just adding this case to the m2 and pascal in their
> type print functions, I think it would be nice simply to avoid the
> special case in the test.  If it's anything more complex than that, then
> I agree with you that it's not worth it.

It's indeed nicer, but the thing that stopped me is that ultimately
it's time spent doing something unlikely to be useful. Even if it is
only 10-15 min to make the change, test and submit it, it's still time
away from more useful changes. That being said, I think you are actually
right with this. Now that I was made to look into it, I think the issue
is in the common type printer, and so adding support there would seem
logical, considering how I tried to make said support as generic as
possible.

I will look further into it next weekend.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [pushed/v2 1/9] gdb/configure: Add --with-libgmp-prefix option
  2020-11-16  3:45       ` Joel Brobecker
@ 2020-11-16 14:20         ` Bernd Edlinger
  2020-11-17  7:41           ` [PATCH] Enable GDB build with in-tree GMP and MPFR Bernd Edlinger
  0 siblings, 1 reply; 140+ messages in thread
From: Bernd Edlinger @ 2020-11-16 14:20 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches, Simon Marchi



On 11/16/20 4:45 AM, Joel Brobecker wrote:
> Hi Bernd,
> 
>> I noticed that this does not allow to build gmp in-tree like it is
>> possible for gcc.  I tried to overcome this by the attached patch.
> 
> Indeed. It's not something I had considered.
> 
>> While doing so, I also noticed an incompatibility with the top level
>> configure stript, which advertises, and passes -with-gmp-include
>> and -with-gmp-lib if in-tree gmp is found.
>>
>> So the --with-libgmp-prefix is not that the top level configure
>> script suggests:
>>
>> $ ./configure --help | grep gmp
>>   --with-gmp-dir=PATH     this option has been REMOVED
>>   --with-gmp=PATH         specify prefix directory for the installed GMP
>>                           --with-gmp-include=PATH/include plus
>>                           --with-gmp-lib=PATH/lib
>>   --with-gmp-include=PATH specify directory for installed GMP include files
>>   --with-gmp-lib=PATH     specify directory for the installed GMP library
>>
>> What do you think, can we allow these traditional configure options
>> additional to the new --with-libgmp-prefix?
> 
> Can you check if these options are actually used elsewhere in
> the binutils-gdb project? The idea I have in the back of my mind
> is to see whether we can use the same options as the ones we've been
> using in GDB or not. The fact that we have an AC_LIB_HAVE_LINKFLAGS
> macro which takes care of handling dependencies for us tells me
> that we are transitioning away from the model above where we add
> the options "by hand" in configure.ac, and instead rely on the new
> macro.
> 

I think they are also used as configuration options in mpfr
and mpc, and understood by the top level configuration.

$ mpc-1.0.3/configure --help
[...]
  --with-mpfr-include=DIR MPFR include directory
  --with-mpfr-lib=DIR     MPFR lib directory
  --with-mpfr=DIR         MPFR install directory
  --with-gmp-include=DIR  GMP include directory
  --with-gmp-lib=DIR      GMP lib directory
  --with-gmp=DIR          GMP install directory
[...]
$
[...]
  --with-gmp-include=DIR  GMP include directory
  --with-gmp-lib=DIR      GMP lib directory
  --with-gmp=DIR          GMP install directory
  --with-gmp-build=DIR    GMP build directory (please read INSTALL file)
[...]


> One thing I did note is that GDB has some options for MPFR support
> and in particular, it has --with-mpfr:
> 
>   --with-mpfr             include MPFR support (auto/yes/no)
> 
> As you can see, the --with-gmp option you propose is not consistent
> with the above.
> 

Hmm, yes, indeed, the --with-mpfr seems to be hand-crafted, since there is
currently no --with-gmp=[auto/yes/no], (neither before or after my patch).
I think the --with-mpfr might probably cause problems with mpc in-tree build,
if that ever happens.

Of course the this mpfr support does not work with in-tree mpfr either.
For that to work we would need at minimum --with-mpfr-include=DIR and
--with-mpfr-lib=DIR or equivalent, however mpfr is probably not worth the effort.


> Unfortunately, in digging further, I found that toplevel configure
> *also* has --with-mpfr, with a different meaning:
> 
>   --with-mpfr=PATH        specify prefix directory for installed MPFR package.
>                           Equivalent to --with-mpfr-include=PATH/include plus
>                           --with-mpfr-lib=PATH/lib
> 
> The way we expect people to configure GDB is to configure it as
> part of the binutils-gdb project, so I don't see how GDB's --with-mpfr
> could work, unless the top-level configury is more elaborate than
> I remembered.
> 
> Depending on the above, perhaps it might be better to actually
> to change the top-level configury to advertise the --with-gmp-prefix
> options instead of adding parallel support for the old-style
> options in GDB's configury. And while at it, perhaps start deprecating
> the old-style ones in the top-level configury.
> 

Of course there is still mpfr's --with-gmp=DIR configuration option.

But there may also be other surprises like this in configure.ac :

  *-*-freebsd*)
    if test "x$with_gmp" = x && test "x$with_gmp_dir" = x \
        && ! test -d ${srcdir}/gmp \
        && test -f /usr/local/include/gmp.h; then
      with_gmp=/usr/local
    fi
    ;;

as you see, this option was already there for a while.

> One more note: For me, I think we can handle the question of
> in-tree building independently of the question of the configury's
> options -- which is good, because I think the latterm might require
> a bit of discussion.
> 
>> Can we the top level Makefile.def change in binutils-gdb or has this
>> be checked-in first in gcc?
> 
> That's a good question. I *think* that binutils + GDB now have
> ownership, but I might be wrong. Hopefully others know better.
> If not, I will ask.
> 
>> 2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>
>>
>> 	* Makefile.def: Prepare for GDB build with intree GMP.
>> 	* Makefile.in: Regenerate.
>>
>> gdb:
>> 2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>
>>
>> 	* configure.ac: Add --with-gmp= --with-gmp-include= and --with-gmp-lib=
>> 	for compatibility with top level configure script.
>> 	* configure: Regenerate.
> 
> Looking at your patch, I'm wondering how this would all fit together...
> Would it all work automatically (like it does for libiconv, I believe),
> or where you planning on having to pass --with-gmp options ?
> 

No, all it needs, is a symlink named "gmp" pointing to gmp's source tree, in the
top level directory, like gcc's contrib/download_prerequisites does.

Once the gmp directory is there the --with-gmp-include and --with-gmp-lib options
are passed to in-tree mpfr if any, and now additionally to gdb.

The --with-gmp=DIR option itself is not needed at all for the in-tree build.


Bernd.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects
  2020-11-13 15:04       ` Tom Tromey
  2020-11-13 15:06         ` Simon Marchi
@ 2020-11-16 16:18         ` Tom Tromey
  1 sibling, 0 replies; 140+ messages in thread
From: Tom Tromey @ 2020-11-16 16:18 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Joel Brobecker, Simon Marchi, gdb-patches

Tom> Also perhaps instead of updating these we should reconsider using the
Tom> c++ classes that come with gmp.  See gmpxx.h or
Tom> (info "(gmp) C++ Class Interface")
Tom> (I'm don't recall why these weren't used, maybe it's the caveat in the
Tom> manual.  However I think we can probably deal with that ok.)

I took a brief look at this, and this isn't a header-only wrapper -- it
requires another library, and at least on Fedora this is packaged
separately.  For me at least this puts it into the "overkill" category;
so I plan to look at just modifying our wrapper classes instead.

Tom

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects
  2020-11-08  6:30 ` [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects Joel Brobecker
  2020-11-10 20:15   ` Simon Marchi
@ 2020-11-16 16:34   ` Luis Machado
  2020-11-18  3:52     ` Joel Brobecker
  1 sibling, 1 reply; 140+ messages in thread
From: Luis Machado @ 2020-11-16 16:34 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

Just a quick comment... shouldn't gmp-utils.c go into gdbsupport so 
gdbserver can use it as well?

On 11/8/20 3:30 AM, Joel Brobecker wrote:
> This API was motivated by a number of reasons:
>    - GMP's API does not handle "long long" and "unsigned long long",
>      so using LONGEST and ULONGEST is not straightforward;
>    - Automate the need to initialize GMP objects before use, and
>      clear them when no longer used.
> 
> However, this API grew also to help with similar matter such
> as formatting to a string, and also reading/writing fixed-point
> values from byte buffers.
> 
> Dedicated unit testing is also added.
> 
> gdb/ChangeLog:
> 
>          * gmp-utils.h,  gmp-utils.h: New file.

Typo in the filename.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 1/6] change gmp_string_asprintf to return an std::string
  2020-11-16  3:55       ` Joel Brobecker
@ 2020-11-16 20:10         ` Simon Marchi
  0 siblings, 0 replies; 140+ messages in thread
From: Simon Marchi @ 2020-11-16 20:10 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On 2020-11-15 10:55 p.m., Joel Brobecker wrote:
> I don't know if that's really important in the context of this function
> which I don't think will be called often, but your suggestion raises
> a question: Which option should we favor? Allocating a memory region
> twice, or formatting twice...

I think that memory allocation is in general heavier than the formatting
part.  In the best case, allocation can be very quick, but in the worst
case it can be quite costly, I guess that depends on the allocator.
Allocating could involve some locking or some syscall.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view
  2020-11-16  0:52     ` Simon Marchi
@ 2020-11-16 23:05       ` Pedro Alves
  2020-11-17 14:32         ` Simon Marchi
  0 siblings, 1 reply; 140+ messages in thread
From: Pedro Alves @ 2020-11-16 23:05 UTC (permalink / raw)
  To: Simon Marchi, Joel Brobecker, gdb-patches

On 11/16/20 12:52 AM, Simon Marchi wrote:
> On 2020-11-15 3:49 a.m., Joel Brobecker wrote:
>> This commit changes the interfaces of some of the methods declared
>> in gmp-utils to take a gdb::array_view of gdb_byte instead of a
>> (gdb_byte *, size) couple.
>>
>> This makes these methods' API probably more C++-idiomatic.
>> With the way things are structured, this change introduces a minor
>> extra complication at the point of call of these methods, since
>> the data available there is not in the form of an array_view,
>> and thus the array_view needs to be constructed on the spot.
> 
> I'd suggest using gdb::make_array_view (ptr, len) instead of the
> array_view constructor.  This way, you don't need to specify the
> template type, it's automatically deduced, so it's a bit less verbose.
> Otherwise, LGTM.

Note gdb::make_array_view is only necessary if the type of len
is not size_t.  If it is size_t, then the shorter "{ptr, len}" works.

As an illustration:

--- i/gdb/unittests/gmp-utils-selftests.c
+++ w/gdb/unittests/gmp-utils-selftests.c
@@ -95,7 +95,7 @@ gdb_mpz_as_integer ()
 
 template<typename T>
 void
-store_and_read_back (T val, int buf_len, enum bfd_endian byte_order,
+store_and_read_back (T val, size_t buf_len, enum bfd_endian byte_order,
                     gdb_mpz &expected, gdb_mpz &actual)
 {
   gdb_byte *buf;
@@ -109,8 +109,7 @@ store_and_read_back (T val, int buf_len, enum bfd_endian byte_order,
   mpz_set (actual.val, expected.val);
   mpz_sub_ui (actual.val, actual.val, 500);
 
-  actual.read (gdb::array_view<const gdb_byte> (buf, buf_len),
-              byte_order, !std::is_signed<T>::value);
+  actual.read ({buf, buf_len}, byte_order, !std::is_signed<T>::value);
 }

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: pushed: Add support for DWARF-based fixed point types
  2020-11-15  8:35 ` pushed: " Joel Brobecker
                     ` (8 preceding siblings ...)
  2020-11-15  8:35   ` [pushed/v2 9/9] Add support for fixed-point type comparison operators Joel Brobecker
@ 2020-11-16 23:48   ` Pedro Alves
  2020-11-17 14:25     ` Simon Marchi
  2020-11-20 14:08   ` pushed: Add support for DWARF-based fixed point types Pedro Alves
  2020-11-22 11:56   ` RFA/doco: Various changes related to GMP and fixed point type support Joel Brobecker
  11 siblings, 1 reply; 140+ messages in thread
From: Pedro Alves @ 2020-11-16 23:48 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches; +Cc: Simon Marchi

Hi Joel,

On 11/15/20 8:35 AM, Joel Brobecker wrote:
> Hi everyone,
> 
> I just finished pusing the following patch series to branch master.

I noticed that a new unit test added by this series is failing for me on
Ubuntu 20.04, which has libgmp.so.10.4.0 :

 $ ./gdb -ex "maint selftest gdb_mpq_write_fixed_point"
 GNU gdb (GDB) 11.0.50.20201116-git
 ...
 Running selftest gdb_mpq_write_fixed_point.
 *** stack smashing detected ***: terminated
 Aborted (core dumped)
 $

I've built a clean gdb from scratch to confirm.

The test passes on Fedora 27, which has libgmp.so.10.3.2:

 $ ./gdb -ex "maint selftest gdb_mpq_write_fixed_point"
 GNU gdb (GDB) 11.0.50.20201116-git
 Running selftest gdb_mpq_write_fixed_point.
 Ran 1 unit tests, 0 failed

Anyone else seeing this?

^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PATCH] Enable GDB build with in-tree GMP and MPFR
  2020-11-16 14:20         ` Bernd Edlinger
@ 2020-11-17  7:41           ` Bernd Edlinger
  2020-11-18  3:44             ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Bernd Edlinger @ 2020-11-17  7:41 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches, Simon Marchi

[-- Attachment #1: Type: text/plain, Size: 766 bytes --]

Hi,

this enables GDB build with in-tree GMP and MPFR.

This updated version of my patch added support for in-tree MPFR.

While there is no preexisting --with-gmp configure option in gdb,
this leaves the current --with-mpfr=yes/no/auto as it is, since it seems
to work by accident.  The top level config script thinks "no" is
a DIR, and skips the detection of in-tree MPFR in that case, while
gdb honors --with-mpfr=no, so that is what's expected.

The in-tree build works only when no --with-mpfr and no
--with-gmp is given.  While it does not advertise --with-gmp-prefix=DIR
and/or --with-mpfr-prefix=DIR with "./configure --help", I'll leave that
for another patch.


Tested on x86_64-pc-linux-gnu and cross-build for arm.
Is it OK for the trunk?


Thanks
Bernd.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR.patch --]
[-- Type: text/x-patch; name="0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR.patch", Size: 7186 bytes --]

From 503435680f463cf5ed060ce32b902051cb19e801 Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Sun, 15 Nov 2020 15:37:22 +0100
Subject: [PATCH] Enable GDB build with in-tree GMP and MPFR

With this patch GDB can be built with in-tree GMP and/or
MPFR.  This works also for cross-builds.

All that is needed, is a sym-link in the source tree,
like this:

gmp -> ../gmp-6.1.0
mpfr -> ../mpfr-3.1.4

2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* Makefile.def: Prepare for GDB build with intree GMP.
	* Makefile.in: Regenerate.

gdb:
2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* configure.ac: Add --with-gmp=DIR, --with-gmp-include=DIR
	and --with-gmp-lib=DIR
	as well as --with-mpfr-include=DIR and --with-mpfr-lib=DIR
	for compatibility with top level configure script.
	* configure: Regenerate.
---
 Makefile.def     |  5 ++++-
 Makefile.in      |  4 +++-
 gdb/configure    | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/configure.ac | 25 +++++++++++++++++++++++++
 4 files changed, 84 insertions(+), 2 deletions(-)

diff --git a/Makefile.def b/Makefile.def
index 089e70a..1b99b42 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -115,7 +115,8 @@ host_modules= { module= zlib; no_install=true; no_check=true;
 host_modules= { module= gnulib; };
 host_modules= { module= gdbsupport; };
 host_modules= { module= gdbserver; };
-host_modules= { module= gdb; };
+host_modules= { module= gdb;
+		extra_configure_flags='@extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@';};
 host_modules= { module= expect; };
 host_modules= { module= guile; };
 host_modules= { module= tk; };
@@ -391,6 +392,8 @@ dependencies = { module=all-intl; on=all-libiconv; };
 
 // Host modules specific to gdb.
 dependencies = { module=configure-gdb; on=all-intl; };
+dependencies = { module=configure-gdb; on=all-gmp; };
+dependencies = { module=configure-gdb; on=all-mpfr; };
 dependencies = { module=configure-gdb; on=configure-sim; };
 dependencies = { module=configure-gdb; on=all-bfd; };
 dependencies = { module=configure-gdb; on=all-gnulib; };
diff --git a/Makefile.in b/Makefile.in
index fe34132..738fd32 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -29491,7 +29491,7 @@ configure-gdb:
 	  $$s/$$module_srcdir/configure \
 	  --srcdir=$${topdir}/$$module_srcdir \
 	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
-	  --target=${target_alias}  \
+	  --target=${target_alias} @extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@ \
 	  || exit 1
 @endif gdb
 
@@ -52449,6 +52449,8 @@ configure-libcc1: maybe-configure-gcc
 all-libcc1: maybe-all-gcc
 all-utils: maybe-all-libiberty
 configure-gdb: maybe-all-intl
+configure-gdb: maybe-all-gmp
+configure-gdb: maybe-all-mpfr
 configure-gdb: maybe-all-bfd
 configure-gdb: maybe-all-libiconv
 all-gdb: maybe-all-libiberty
diff --git a/gdb/configure b/gdb/configure
index a3e73b4..034485d 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -899,8 +899,13 @@ with_jit_reader_dir
 with_expat
 with_libexpat_prefix
 with_libexpat_type
+with_gmp_include
+with_gmp_lib
+with_gmp
 with_libgmp_prefix
 with_libgmp_type
+with_mpfr_include
+with_mpfr_lib
 with_mpfr
 with_libmpfr_prefix
 with_libmpfr_type
@@ -1644,9 +1649,14 @@ Optional Packages:
   --with-libexpat-prefix[=DIR]  search for libexpat in DIR/include and DIR/lib
   --without-libexpat-prefix     don't search for libexpat in includedir and libdir
   --with-libexpat-type=TYPE     type of library to search for (auto/static/shared)
+  --with-gmp-include=DIR  GMP include directory
+  --with-gmp-lib=DIR      GMP lib directory
+  --with-gmp=DIR          GMP install directory
   --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
   --without-libgmp-prefix     don't search for libgmp in includedir and libdir
   --with-libgmp-type=TYPE     type of library to search for (auto/static/shared)
+  --with-mpfr-include=DIR MPFR include directory
+  --with-mpfr-lib=DIR     MPFR lib directory
   --with-mpfr             include MPFR support (auto/yes/no)
   --with-libmpfr-prefix[=DIR]  search for libmpfr in DIR/include and DIR/lib
   --without-libmpfr-prefix     don't search for libmpfr in includedir and libdir
@@ -9990,6 +10000,35 @@ done
   fi
 fi
 
+
+# Check whether --with-gmp_include was given.
+if test "${with_gmp_include+set}" = set; then :
+  withval=$with_gmp_include; CPPFLAGS="$CPPFLAGS -I$withval"
+fi
+
+
+# Check whether --with-gmp_lib was given.
+if test "${with_gmp_lib+set}" = set; then :
+  withval=$with_gmp_lib; LDFLAGS="$LDFLAGS -L$withval"
+fi
+
+
+# Check whether --with-gmp was given.
+if test "${with_gmp+set}" = set; then :
+  withval=$with_gmp;
+   if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
+      CPPFLAGS="$CPPFLAGS -I$withval/include"
+      LDFLAGS="$LDFLAGS -L$withval/lib"
+   else
+      { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.
+See \`config.log' for more details" "$LINENO" 5; }
+   fi
+
+fi
+
+
 # Verify that we have a usable GMP library.
 
 
@@ -10474,6 +10513,19 @@ if test "$HAVE_LIBGMP" != yes; then
 fi
 
 
+# Check whether --with-mpfr_include was given.
+if test "${with_mpfr_include+set}" = set; then :
+  withval=$with_mpfr_include; CPPFLAGS="-I$withval $CPPFLAGS"
+fi
+
+
+# Check whether --with-mpfr_lib was given.
+if test "${with_mpfr_lib+set}" = set; then :
+  withval=$with_mpfr_lib; LDFLAGS="-L$withval $LDFLAGS"
+fi
+
+
+
 # Check whether --with-mpfr was given.
 if test "${with_mpfr+set}" = set; then :
   withval=$with_mpfr;
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 32f25d9..97f43ce 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -683,6 +683,22 @@ else
   fi
 fi
 
+AC_ARG_WITH(gmp_include,
+   [  --with-gmp-include=DIR  GMP include directory ],
+   CPPFLAGS="$CPPFLAGS -I$withval")
+AC_ARG_WITH(gmp_lib,
+   [  --with-gmp-lib=DIR      GMP lib directory ],
+   LDFLAGS="$LDFLAGS -L$withval")
+AC_ARG_WITH(gmp,
+   [  --with-gmp=DIR          GMP install directory ], [
+   if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
+      CPPFLAGS="$CPPFLAGS -I$withval/include"
+      LDFLAGS="$LDFLAGS -L$withval/lib"
+   else
+      AC_MSG_FAILURE([Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.])
+   fi
+  ])
+
 # Verify that we have a usable GMP library.
 AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
                       [mpz_t n;
@@ -691,6 +707,15 @@ if test "$HAVE_LIBGMP" != yes; then
   AC_MSG_ERROR([GMP is missing or unusable])
 fi
 
+AC_ARG_WITH([mpfr_include],
+            [AC_HELP_STRING([--with-mpfr-include=DIR],
+                            [MPFR include directory])],
+            [CPPFLAGS="-I$withval $CPPFLAGS"])
+AC_ARG_WITH([mpfr_lib],
+            [AC_HELP_STRING([--with-mpfr-lib=DIR],
+                            [MPFR lib directory])],
+            [LDFLAGS="-L$withval $LDFLAGS"])
+
 AC_ARG_WITH(mpfr,
   AS_HELP_STRING([--with-mpfr], [include MPFR support (auto/yes/no)]),
   [], [with_mpfr=auto])
-- 
1.9.1


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: pushed: Add support for DWARF-based fixed point types
  2020-11-16 23:48   ` pushed: Add support for DWARF-based fixed point types Pedro Alves
@ 2020-11-17 14:25     ` Simon Marchi
  2020-11-18  3:47       ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-17 14:25 UTC (permalink / raw)
  To: Pedro Alves, Joel Brobecker, gdb-patches

On 2020-11-16 6:48 p.m., Pedro Alves wrote:
> Hi Joel,
> 
> On 11/15/20 8:35 AM, Joel Brobecker wrote:
>> Hi everyone,
>>
>> I just finished pusing the following patch series to branch master.
> 
> I noticed that a new unit test added by this series is failing for me on
> Ubuntu 20.04, which has libgmp.so.10.4.0 :
> 
>  $ ./gdb -ex "maint selftest gdb_mpq_write_fixed_point"
>  GNU gdb (GDB) 11.0.50.20201116-git
>  ...
>  Running selftest gdb_mpq_write_fixed_point.
>  *** stack smashing detected ***: terminated
>  Aborted (core dumped)
>  $
> 
> I've built a clean gdb from scratch to confirm.
> 
> The test passes on Fedora 27, which has libgmp.so.10.3.2:
> 
>  $ ./gdb -ex "maint selftest gdb_mpq_write_fixed_point"
>  GNU gdb (GDB) 11.0.50.20201116-git
>  Running selftest gdb_mpq_write_fixed_point.
>  Ran 1 unit tests, 0 failed
> 
> Anyone else seeing this?
> 

I didn't see it in my -O0 compiled GDB, but I do see it in my -O2 compiled GDB.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view
  2020-11-16 23:05       ` Pedro Alves
@ 2020-11-17 14:32         ` Simon Marchi
  0 siblings, 0 replies; 140+ messages in thread
From: Simon Marchi @ 2020-11-17 14:32 UTC (permalink / raw)
  To: Pedro Alves, Joel Brobecker, gdb-patches

On 2020-11-16 6:05 p.m., Pedro Alves wrote:
> On 11/16/20 12:52 AM, Simon Marchi wrote:
>> On 2020-11-15 3:49 a.m., Joel Brobecker wrote:
>>> This commit changes the interfaces of some of the methods declared
>>> in gmp-utils to take a gdb::array_view of gdb_byte instead of a
>>> (gdb_byte *, size) couple.
>>>
>>> This makes these methods' API probably more C++-idiomatic.
>>> With the way things are structured, this change introduces a minor
>>> extra complication at the point of call of these methods, since
>>> the data available there is not in the form of an array_view,
>>> and thus the array_view needs to be constructed on the spot.
>>
>> I'd suggest using gdb::make_array_view (ptr, len) instead of the
>> array_view constructor.  This way, you don't need to specify the
>> template type, it's automatically deduced, so it's a bit less verbose.
>> Otherwise, LGTM.
> 
> Note gdb::make_array_view is only necessary if the type of len
> is not size_t.  If it is size_t, then the shorter "{ptr, len}" works.
> 
> As an illustration:
> 
> --- i/gdb/unittests/gmp-utils-selftests.c
> +++ w/gdb/unittests/gmp-utils-selftests.c
> @@ -95,7 +95,7 @@ gdb_mpz_as_integer ()
>  
>  template<typename T>
>  void
> -store_and_read_back (T val, int buf_len, enum bfd_endian byte_order,
> +store_and_read_back (T val, size_t buf_len, enum bfd_endian byte_order,
>                      gdb_mpz &expected, gdb_mpz &actual)
>  {
>    gdb_byte *buf;
> @@ -109,8 +109,7 @@ store_and_read_back (T val, int buf_len, enum bfd_endian byte_order,
>    mpz_set (actual.val, expected.val);
>    mpz_sub_ui (actual.val, actual.val, 500);
>  
> -  actual.read (gdb::array_view<const gdb_byte> (buf, buf_len),
> -              byte_order, !std::is_signed<T>::value);
> +  actual.read ({buf, buf_len}, byte_order, !std::is_signed<T>::value);
>  }
> 

Well, +1 for using that.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH] Enable GDB build with in-tree GMP and MPFR
  2020-11-17  7:41           ` [PATCH] Enable GDB build with in-tree GMP and MPFR Bernd Edlinger
@ 2020-11-18  3:44             ` Joel Brobecker
  2020-11-18  8:14               ` Bernd Edlinger
  0 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-18  3:44 UTC (permalink / raw)
  To: Bernd Edlinger; +Cc: Simon Marchi, gdb-patches

> this enables GDB build with in-tree GMP and MPFR.
> 
> This updated version of my patch added support for in-tree MPFR.
> 
> While there is no preexisting --with-gmp configure option in gdb,
> this leaves the current --with-mpfr=yes/no/auto as it is, since it seems
> to work by accident.  The top level config script thinks "no" is
> a DIR, and skips the detection of in-tree MPFR in that case, while
> gdb honors --with-mpfr=no, so that is what's expected.
> 
> The in-tree build works only when no --with-mpfr and no
> --with-gmp is given.  While it does not advertise --with-gmp-prefix=DIR
> and/or --with-mpfr-prefix=DIR with "./configure --help", I'll leave that
> for another patch.

I think we better sort the discrepancy between GCC and GDB
if we can, but this is going to take time. From what you were
explaining before, I believe you can separate this part of
your patch (adding the above to GDB's configury) from the part
where you're adding support for in-tree building?

> Tested on x86_64-pc-linux-gnu and cross-build for arm.
> Is it OK for the trunk?

These are changes in areas I am not familiar with, and wouldn't
have very much time to look into. I talked to Tom yesterday,
and he kindly agreed to take a look.

> From 503435680f463cf5ed060ce32b902051cb19e801 Mon Sep 17 00:00:00 2001
> From: Bernd Edlinger <bernd.edlinger@hotmail.de>
> Date: Sun, 15 Nov 2020 15:37:22 +0100
> Subject: [PATCH] Enable GDB build with in-tree GMP and MPFR
> 
> With this patch GDB can be built with in-tree GMP and/or
> MPFR.  This works also for cross-builds.
> 
> All that is needed, is a sym-link in the source tree,
> like this:
> 
> gmp -> ../gmp-6.1.0
> mpfr -> ../mpfr-3.1.4
> 
> 2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>
> 
> 	* Makefile.def: Prepare for GDB build with intree GMP.
> 	* Makefile.in: Regenerate.

I got the answer about approval for toplevel tree changes; we're still
keeping in sync with GCC. However, Tom said that these kinds of changes
are OK to discuss and eventually push locally, before we bring them
to GCC next. It's better the other way around, but discussing them
here is also an option, because it's a minor change taking advantage
of infrastructure that's already in place.

In this particular instance, I would indeed _not_ rush discussing
with GCC, in case the tie with GDB affects the changes we would need
in toplevel.

> gdb:
> 2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>
> 
> 	* configure.ac: Add --with-gmp=DIR, --with-gmp-include=DIR
> 	and --with-gmp-lib=DIR
> 	as well as --with-mpfr-include=DIR and --with-mpfr-lib=DIR
> 	for compatibility with top level configure script.
> 	* configure: Regenerate.
> ---
>  Makefile.def     |  5 ++++-
>  Makefile.in      |  4 +++-
>  gdb/configure    | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/configure.ac | 25 +++++++++++++++++++++++++
>  4 files changed, 84 insertions(+), 2 deletions(-)
> 
> diff --git a/Makefile.def b/Makefile.def
> index 089e70a..1b99b42 100644
> --- a/Makefile.def
> +++ b/Makefile.def
> @@ -115,7 +115,8 @@ host_modules= { module= zlib; no_install=true; no_check=true;
>  host_modules= { module= gnulib; };
>  host_modules= { module= gdbsupport; };
>  host_modules= { module= gdbserver; };
> -host_modules= { module= gdb; };
> +host_modules= { module= gdb;
> +		extra_configure_flags='@extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@';};
>  host_modules= { module= expect; };
>  host_modules= { module= guile; };
>  host_modules= { module= tk; };
> @@ -391,6 +392,8 @@ dependencies = { module=all-intl; on=all-libiconv; };
>  
>  // Host modules specific to gdb.
>  dependencies = { module=configure-gdb; on=all-intl; };
> +dependencies = { module=configure-gdb; on=all-gmp; };
> +dependencies = { module=configure-gdb; on=all-mpfr; };
>  dependencies = { module=configure-gdb; on=configure-sim; };
>  dependencies = { module=configure-gdb; on=all-bfd; };
>  dependencies = { module=configure-gdb; on=all-gnulib; };
> diff --git a/Makefile.in b/Makefile.in
> index fe34132..738fd32 100644
> --- a/Makefile.in
> +++ b/Makefile.in
> @@ -29491,7 +29491,7 @@ configure-gdb:
>  	  $$s/$$module_srcdir/configure \
>  	  --srcdir=$${topdir}/$$module_srcdir \
>  	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
> -	  --target=${target_alias}  \
> +	  --target=${target_alias} @extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@ \
>  	  || exit 1
>  @endif gdb
>  
> @@ -52449,6 +52449,8 @@ configure-libcc1: maybe-configure-gcc
>  all-libcc1: maybe-all-gcc
>  all-utils: maybe-all-libiberty
>  configure-gdb: maybe-all-intl
> +configure-gdb: maybe-all-gmp
> +configure-gdb: maybe-all-mpfr
>  configure-gdb: maybe-all-bfd
>  configure-gdb: maybe-all-libiconv
>  all-gdb: maybe-all-libiberty
> diff --git a/gdb/configure b/gdb/configure
> index a3e73b4..034485d 100755
> --- a/gdb/configure
> +++ b/gdb/configure
> @@ -899,8 +899,13 @@ with_jit_reader_dir
>  with_expat
>  with_libexpat_prefix
>  with_libexpat_type
> +with_gmp_include
> +with_gmp_lib
> +with_gmp
>  with_libgmp_prefix
>  with_libgmp_type
> +with_mpfr_include
> +with_mpfr_lib
>  with_mpfr
>  with_libmpfr_prefix
>  with_libmpfr_type
> @@ -1644,9 +1649,14 @@ Optional Packages:
>    --with-libexpat-prefix[=DIR]  search for libexpat in DIR/include and DIR/lib
>    --without-libexpat-prefix     don't search for libexpat in includedir and libdir
>    --with-libexpat-type=TYPE     type of library to search for (auto/static/shared)
> +  --with-gmp-include=DIR  GMP include directory
> +  --with-gmp-lib=DIR      GMP lib directory
> +  --with-gmp=DIR          GMP install directory
>    --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
>    --without-libgmp-prefix     don't search for libgmp in includedir and libdir
>    --with-libgmp-type=TYPE     type of library to search for (auto/static/shared)
> +  --with-mpfr-include=DIR MPFR include directory
> +  --with-mpfr-lib=DIR     MPFR lib directory
>    --with-mpfr             include MPFR support (auto/yes/no)
>    --with-libmpfr-prefix[=DIR]  search for libmpfr in DIR/include and DIR/lib
>    --without-libmpfr-prefix     don't search for libmpfr in includedir and libdir
> @@ -9990,6 +10000,35 @@ done
>    fi
>  fi
>  
> +
> +# Check whether --with-gmp_include was given.
> +if test "${with_gmp_include+set}" = set; then :
> +  withval=$with_gmp_include; CPPFLAGS="$CPPFLAGS -I$withval"
> +fi
> +
> +
> +# Check whether --with-gmp_lib was given.
> +if test "${with_gmp_lib+set}" = set; then :
> +  withval=$with_gmp_lib; LDFLAGS="$LDFLAGS -L$withval"
> +fi
> +
> +
> +# Check whether --with-gmp was given.
> +if test "${with_gmp+set}" = set; then :
> +  withval=$with_gmp;
> +   if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
> +      CPPFLAGS="$CPPFLAGS -I$withval/include"
> +      LDFLAGS="$LDFLAGS -L$withval/lib"
> +   else
> +      { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
> +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
> +as_fn_error $? "Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.
> +See \`config.log' for more details" "$LINENO" 5; }
> +   fi
> +
> +fi
> +
> +
>  # Verify that we have a usable GMP library.
>  
>  
> @@ -10474,6 +10513,19 @@ if test "$HAVE_LIBGMP" != yes; then
>  fi
>  
>  
> +# Check whether --with-mpfr_include was given.
> +if test "${with_mpfr_include+set}" = set; then :
> +  withval=$with_mpfr_include; CPPFLAGS="-I$withval $CPPFLAGS"
> +fi
> +
> +
> +# Check whether --with-mpfr_lib was given.
> +if test "${with_mpfr_lib+set}" = set; then :
> +  withval=$with_mpfr_lib; LDFLAGS="-L$withval $LDFLAGS"
> +fi
> +
> +
> +
>  # Check whether --with-mpfr was given.
>  if test "${with_mpfr+set}" = set; then :
>    withval=$with_mpfr;
> diff --git a/gdb/configure.ac b/gdb/configure.ac
> index 32f25d9..97f43ce 100644
> --- a/gdb/configure.ac
> +++ b/gdb/configure.ac
> @@ -683,6 +683,22 @@ else
>    fi
>  fi
>  
> +AC_ARG_WITH(gmp_include,
> +   [  --with-gmp-include=DIR  GMP include directory ],
> +   CPPFLAGS="$CPPFLAGS -I$withval")
> +AC_ARG_WITH(gmp_lib,
> +   [  --with-gmp-lib=DIR      GMP lib directory ],
> +   LDFLAGS="$LDFLAGS -L$withval")
> +AC_ARG_WITH(gmp,
> +   [  --with-gmp=DIR          GMP install directory ], [
> +   if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
> +      CPPFLAGS="$CPPFLAGS -I$withval/include"
> +      LDFLAGS="$LDFLAGS -L$withval/lib"
> +   else
> +      AC_MSG_FAILURE([Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.])
> +   fi
> +  ])
> +
>  # Verify that we have a usable GMP library.
>  AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
>                        [mpz_t n;
> @@ -691,6 +707,15 @@ if test "$HAVE_LIBGMP" != yes; then
>    AC_MSG_ERROR([GMP is missing or unusable])
>  fi
>  
> +AC_ARG_WITH([mpfr_include],
> +            [AC_HELP_STRING([--with-mpfr-include=DIR],
> +                            [MPFR include directory])],
> +            [CPPFLAGS="-I$withval $CPPFLAGS"])
> +AC_ARG_WITH([mpfr_lib],
> +            [AC_HELP_STRING([--with-mpfr-lib=DIR],
> +                            [MPFR lib directory])],
> +            [LDFLAGS="-L$withval $LDFLAGS"])
> +
>  AC_ARG_WITH(mpfr,
>    AS_HELP_STRING([--with-mpfr], [include MPFR support (auto/yes/no)]),
>    [], [with_mpfr=auto])
> -- 
> 1.9.1
> 


-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: pushed: Add support for DWARF-based fixed point types
  2020-11-17 14:25     ` Simon Marchi
@ 2020-11-18  3:47       ` Joel Brobecker
  2020-11-22 13:12         ` [RFA] Add TYPE_CODE_FIXED_POINT handling in print_type_scalar Joel Brobecker
  2020-11-22 14:00         ` pushed: Add support for DWARF-based fixed point types Joel Brobecker
  0 siblings, 2 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-18  3:47 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Pedro Alves, gdb-patches

> >  $ ./gdb -ex "maint selftest gdb_mpq_write_fixed_point"
> >  GNU gdb (GDB) 11.0.50.20201116-git
> >  ...
> >  Running selftest gdb_mpq_write_fixed_point.
> >  *** stack smashing detected ***: terminated
> >  Aborted (core dumped)
> >  $
> > 
> > I've built a clean gdb from scratch to confirm.
> > 
> > The test passes on Fedora 27, which has libgmp.so.10.3.2:
> > 
> >  $ ./gdb -ex "maint selftest gdb_mpq_write_fixed_point"
> >  GNU gdb (GDB) 11.0.50.20201116-git
> >  Running selftest gdb_mpq_write_fixed_point.
> >  Ran 1 unit tests, 0 failed
> > 
> > Anyone else seeing this?
> > 
> 
> I didn't see it in my -O0 compiled GDB, but I do see it in my -O2 compiled GDB.

Hmmm, I'm wondering if this might be indicative of a bug in GDB,
rather than in GMP. I will take a look at it this weekend.

Thanks Pedro and Simon.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects
  2020-11-16 16:34   ` Luis Machado
@ 2020-11-18  3:52     ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-18  3:52 UTC (permalink / raw)
  To: Luis Machado; +Cc: gdb-patches

Hi Luis,

> Just a quick comment... shouldn't gmp-utils.c go into gdbsupport so
> gdbserver can use it as well?

I think you would need to make GDBserver require GMP support first.
I don't see where GDBserver would benefit from GMP, but if it does,
I don't believe it would be a problem to move it to gdbsupport.

> On 11/8/20 3:30 AM, Joel Brobecker wrote:
> > This API was motivated by a number of reasons:
> >    - GMP's API does not handle "long long" and "unsigned long long",
> >      so using LONGEST and ULONGEST is not straightforward;
> >    - Automate the need to initialize GMP objects before use, and
> >      clear them when no longer used.
> > 
> > However, this API grew also to help with similar matter such
> > as formatting to a string, and also reading/writing fixed-point
> > values from byte buffers.
> > 
> > Dedicated unit testing is also added.
> > 
> > gdb/ChangeLog:
> > 
> >          * gmp-utils.h,  gmp-utils.h: New file.
> 
> Typo in the filename.

Thanks for catching this, I will fix.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH] Enable GDB build with in-tree GMP and MPFR
  2020-11-18  3:44             ` Joel Brobecker
@ 2020-11-18  8:14               ` Bernd Edlinger
  2020-12-01 19:29                 ` Bernd Edlinger
  0 siblings, 1 reply; 140+ messages in thread
From: Bernd Edlinger @ 2020-11-18  8:14 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Simon Marchi, gdb-patches

On 11/18/20 4:44 AM, Joel Brobecker wrote:
>> this enables GDB build with in-tree GMP and MPFR.
>>
>> This updated version of my patch added support for in-tree MPFR.
>>
>> While there is no preexisting --with-gmp configure option in gdb,
>> this leaves the current --with-mpfr=yes/no/auto as it is, since it seems
>> to work by accident.  The top level config script thinks "no" is
>> a DIR, and skips the detection of in-tree MPFR in that case, while
>> gdb honors --with-mpfr=no, so that is what's expected.
>>
>> The in-tree build works only when no --with-mpfr and no
>> --with-gmp is given.  While it does not advertise --with-gmp-prefix=DIR
>> and/or --with-mpfr-prefix=DIR with "./configure --help", I'll leave that
>> for another patch.
> 
> I think we better sort the discrepancy between GCC and GDB
> if we can, but this is going to take time. From what you were
> explaining before, I believe you can separate this part of
> your patch (adding the above to GDB's configury) from the part
> where you're adding support for in-tree building?
> 


99% of the top-level configury is already there, but it needs
still a dependency between gdb and (in-tree) gmp / mpfr,
and pass the options where to find gmp and mpfr to gdb,
I don't know how to actually resolve the differences ATM.
If the top-level configure script advertises GDB-style options
It will at least have to translate them for in-tree MPFR,
MPC, and ISL.

I believe this change is just the bare minimum and will not
cause additional incompatibilities with GCC.


>> Tested on x86_64-pc-linux-gnu and cross-build for arm.
>> Is it OK for the trunk?
> 
> These are changes in areas I am not familiar with, and wouldn't
> have very much time to look into. I talked to Tom yesterday,
> and he kindly agreed to take a look.
> 
>> From 503435680f463cf5ed060ce32b902051cb19e801 Mon Sep 17 00:00:00 2001
>> From: Bernd Edlinger <bernd.edlinger@hotmail.de>
>> Date: Sun, 15 Nov 2020 15:37:22 +0100
>> Subject: [PATCH] Enable GDB build with in-tree GMP and MPFR
>>
>> With this patch GDB can be built with in-tree GMP and/or
>> MPFR.  This works also for cross-builds.
>>
>> All that is needed, is a sym-link in the source tree,
>> like this:
>>
>> gmp -> ../gmp-6.1.0
>> mpfr -> ../mpfr-3.1.4
>>
>> 2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>
>>
>> 	* Makefile.def: Prepare for GDB build with intree GMP.
>> 	* Makefile.in: Regenerate.
> 
> I got the answer about approval for toplevel tree changes; we're still
> keeping in sync with GCC. However, Tom said that these kinds of changes
> are OK to discuss and eventually push locally, before we bring them
> to GCC next. It's better the other way around, but discussing them
> here is also an option, because it's a minor change taking advantage
> of infrastructure that's already in place.
> 
> In this particular instance, I would indeed _not_ rush discussing
> with GCC, in case the tie with GDB affects the changes we would need
> in toplevel.
> 

Yep, agreed.


Thanks
Bernd.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: pushed: Add support for DWARF-based fixed point types
  2020-11-15  8:35 ` pushed: " Joel Brobecker
                     ` (9 preceding siblings ...)
  2020-11-16 23:48   ` pushed: Add support for DWARF-based fixed point types Pedro Alves
@ 2020-11-20 14:08   ` Pedro Alves
  2020-11-20 14:14     ` Joel Brobecker
  2020-11-22 11:56   ` RFA/doco: Various changes related to GMP and fixed point type support Joel Brobecker
  11 siblings, 1 reply; 140+ messages in thread
From: Pedro Alves @ 2020-11-20 14:08 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches; +Cc: Simon Marchi

Hi Joel,

On 11/15/20 8:35 AM, Joel Brobecker wrote:
> Hi everyone,
> 
> I just finished pusing the following patch series to branch master.
> 
>   -  gdb/configure: Add --with-libgmp-prefix option
>   -  gdb: Make GMP a required dependency for building GDB
>   -  gmp-utils: New API to simply use of GMP's
>   -  Move uinteger_pow gdb/valarith.c to gdb/utils.c and
>   -  Add support for printing value of DWARF-based
>   -  fix printing of DWARF fixed-point type objects with
>   -  Add ptype support for DWARF-based fixed-point types
>   -  Add support for fixed-point type arithmetic
>   -  Add support for fixed-point type comparison operators


I noticed now that this didn't come with a NEWS entry.

Shouldn't it have one?  I.e.:

 - mention that GMP is now a dependency for building GDB

 - support for fixed point types seems NEWS worthy too

Also, gdb/README documents configure options and we mention --with-mpfr there.
Shouldn't we mention --with-libgmp-prefix there too?

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: pushed: Add support for DWARF-based fixed point types
  2020-11-20 14:08   ` pushed: Add support for DWARF-based fixed point types Pedro Alves
@ 2020-11-20 14:14     ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-20 14:14 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Simon Marchi

> I noticed now that this didn't come with a NEWS entry.
> 
> Shouldn't it have one?  I.e.:
> 
>  - mention that GMP is now a dependency for building GDB
> 
>  - support for fixed point types seems NEWS worthy too
> 
> Also, gdb/README documents configure options and we mention --with-mpfr there.
> Shouldn't we mention --with-libgmp-prefix there too?

Hmmm, indeed on all counts. Thanks for the reminder, Pedro. I will add
that to the list for this weekend.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* RFA v2: Various enhancements to the fixed-point support implementation
  2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
                     ` (6 preceding siblings ...)
  2020-11-16  1:01   ` RFA: Various enhancements to the fixed-point support implementation Simon Marchi
@ 2020-11-22 11:14   ` Joel Brobecker
  2020-11-22 11:14     ` [RFA v2 1/6] change and rename gmp_string_asprintf to return an std::string Joel Brobecker
                       ` (6 more replies)
  7 siblings, 7 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:14 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

Hello,

This is v2 of the following patch series:

  - [RFA v2 1/6] change and rename gmp_string_asprintf to return an
  - [RFA v2 2/6] gmp-utils: Convert the read/write methods to using
  - [RFA v2 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro
  - [RFA v2 4/6] Make fixed_point_type_base_type a method of struct type
  - [RFA v2 5/6] Make function fixed_point_scaling_factor a method of
  - [RFA v2 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro

The only changes I made were to patch #1 and patch #2, following
the commends made by Simon and Pedro:

  - [RFA v2 1/6] change and rename gmp_string_asprintf to return an

        Rename the function to gmp_string_printf as recommended,
        and use the suggestion to rely on gmp_vsnprintf to only
        allocate the string buffer once.

  - [RFA v2 2/6] gmp-utils: Convert the read/write methods to using

        Improve the patch using either the form {ptr, len} to construct
        the gdb_byte array, or else gdb::make_array_view.

The other patches are just plain rebases.

Each patch was individually tested on x86_64-linux, with no regression.

There are still a number of comments which were made by Simon and
Pedro (xfail for m2 and pascal, NEWS entries, selftest error
using Ubuntu's GMP, etc), and I will address those next, in
separate submissions.

Note that I almost dropped patch #5 (turning fixed_point_scaling_factor
from function to method), since Simon replied to the discussion
about this topic that the the current form (a separate function) was fine.
In particular, I tried to think about it in a possible future context
where types are a tree of classes rather than one class with a type-code.
In that situation, the fixed_point_scaling_factor method would logically
be "attached" to the fixed point type class. This in turn means that
ranges of fixed point types would not have this method, forcing users
to have to call fixed_point_type_base_type first before they can query
the fixed_point_scaling_factor method. In other words, because
the functionality applies to two types where one is not the child of
the other (in terms of class inheritance), a functioned did seem better.

However, one could argue that the fixed_point_type_base_type method
is in exactly the same boat: It applies to both range types and
fixed point. So, in the name of being consistent, this patch series
keeps them both. My thinking process is based on a hypothetical
scenario, which I'm not even sure ever got discussed here anyways.

That being said, now that I write my thoughts, for the case of
fixed_point_type_base_type, if we did have a hierarchy of classes,
I could perhaps see how all types would have a "base_type" method
whose default implementation would simply return the type itself,
and were range types would return the target type. In that scenario,
the two methods are no longer in the same boat, and we can think
of dropping the fixed_point_scaling_factor patch if we wanted to.

I do not have a strong opinion and thus can easily drop any patch.
The reason I kept the change in the end is that it just seemed
more logical to act on what is today, rather than decide based on
what the code might be tomorrow.

Let me know what you guys think.

Thanks,
-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA v2 1/6] change and rename gmp_string_asprintf to return an std::string
  2020-11-22 11:14   ` RFA v2: " Joel Brobecker
@ 2020-11-22 11:14     ` Joel Brobecker
  2020-11-22 11:14     ` [RFA v2 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view Joel Brobecker
                       ` (5 subsequent siblings)
  6 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:14 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This was suggested by Simon during a code review of this package upstream.
The upside is that this makes the function's API more natural and C++.
The downside is an extra malloc, which might be the reason why we went
for using a unique_xmalloc_ptr in the first place. Since this function
is not expected to be called frequently, the API improvement might be
worth the performance impact.

gdb/ChangeLog:

        * gmp-utils.h (gmp_string_printf): Rename from gmp_string_asprintf.
        Change return type to std::string. Update all callers.
        * gmp-utils.c (gmp_string_printf): Likewise.
---
 gdb/gdbtypes.c  |  2 +-
 gdb/gmp-utils.c | 17 ++++++++++++-----
 gdb/gmp-utils.h | 10 ++++------
 gdb/typeprint.c |  5 ++---
 gdb/valprint.c  |  4 ++--
 5 files changed, 21 insertions(+), 17 deletions(-)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index e6f70bb..3879eeb 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -4927,7 +4927,7 @@ static void
 print_fixed_point_type_info (struct type *type, int spaces)
 {
   printfi_filtered (spaces + 2, "scaling factor: %s\n",
-		    fixed_point_scaling_factor (type).str ().get ());
+		    fixed_point_scaling_factor (type).str ().c_str ());
 }
 
 static struct obstack dont_print_type_obstack;
diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index db92e57..44fe156 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -19,17 +19,24 @@
 
 /* See gmp-utils.h.  */
 
-gdb::unique_xmalloc_ptr<char>
-gmp_string_asprintf (const char *fmt, ...)
+std::string
+gmp_string_printf (const char *fmt, ...)
 {
   va_list vp;
-  char *buf;
 
   va_start (vp, fmt);
-  gmp_vasprintf (&buf, fmt, vp);
+  int size = gmp_vsnprintf (NULL, 0, fmt, vp);
   va_end (vp);
 
-  return gdb::unique_xmalloc_ptr<char> (buf);
+  std::string str (size, '\0');
+
+  /* C++11 and later guarantee std::string uses contiguous memory and
+     always includes the terminating '\0'.  */
+  va_start (vp, fmt);
+  gmp_vsprintf (&str[0], fmt, vp);
+  va_end (vp);
+
+  return str;
 }
 
 /* See gmp-utils.h.  */
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index 1214b64..59965e5 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -29,9 +29,9 @@
 #include <gmp.h>
 #include "gdbsupport/traits.h"
 
-/* Same as gmp_asprintf, but returning a convenient wrapper type.  */
+/* Same as gmp_asprintf, but returning an std::string.  */
 
-gdb::unique_xmalloc_ptr<char> gmp_string_asprintf (const char *fmt, ...);
+std::string gmp_string_printf (const char *fmt, ...);
 
 /* A class to make it easier to use GMP's mpz_t values within GDB.  */
 
@@ -110,8 +110,7 @@ struct gdb_mpz
 	      bool unsigned_p) const;
 
   /* Return a string containing VAL.  */
-  gdb::unique_xmalloc_ptr<char> str () const
-  { return gmp_string_asprintf ("%Zd", val); }
+  std::string str () const { return gmp_string_printf ("%Zd", val); }
 
   /* The destructor.  */
   ~gdb_mpz () { mpz_clear (val); }
@@ -163,8 +162,7 @@ struct gdb_mpq
   }
 
   /* Return a string representing VAL as "<numerator> / <denominator>".  */
-  gdb::unique_xmalloc_ptr<char> str () const
-  { return gmp_string_asprintf ("%Qd", val); }
+  std::string str () const { return gmp_string_printf ("%Qd", val); }
 
   /* Return VAL rounded to the nearest integer.  */
   gdb_mpz get_rounded () const;
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index f947faf..0dd3b1c 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -667,11 +667,10 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream)
 void
 print_type_fixed_point (struct type *type, struct ui_file *stream)
 {
-  gdb::unique_xmalloc_ptr<char> small_img
-    = fixed_point_scaling_factor (type).str ();
+  std::string small_img = fixed_point_scaling_factor (type).str ();
 
   fprintf_filtered (stream, "%s-byte fixed point (small = %s)",
-		    pulongest (TYPE_LENGTH (type)), small_img.get ());
+		    pulongest (TYPE_LENGTH (type)), small_img.c_str ());
 }
 
 /* Dump details of a type specified either directly or indirectly.
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 38ae0bd..b102ff4 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -814,8 +814,8 @@ generic_val_print_fixed_point (struct value *val, struct ui_file *stream,
 			  fixed_point_scaling_factor (type));
 
       const char *fmt = TYPE_LENGTH (type) < 4 ? "%.11Fg" : "%.17Fg";
-      gdb::unique_xmalloc_ptr<char> str = gmp_string_asprintf (fmt, f.val);
-      fprintf_filtered (stream, "%s", str.get ());
+      std::string str = gmp_string_printf (fmt, f.val);
+      fprintf_filtered (stream, "%s", str.c_str ());
     }
 }
 
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA v2 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view
  2020-11-22 11:14   ` RFA v2: " Joel Brobecker
  2020-11-22 11:14     ` [RFA v2 1/6] change and rename gmp_string_asprintf to return an std::string Joel Brobecker
@ 2020-11-22 11:14     ` Joel Brobecker
  2020-11-22 11:14     ` [RFA v2 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro Joel Brobecker
                       ` (4 subsequent siblings)
  6 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:14 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This commit changes the interfaces of some of the methods declared
in gmp-utils to take a gdb::array_view of gdb_byte instead of a
(gdb_byte *, size) couple.

This makes these methods' API probably more C++-idiomatic.

        * gmp-utils.h (gdb_mpz::read): Change buf and len parameters
        into one single gdb::array_view parameter.
        (gdb_mpz::write): Likewise.
        (gdb_mpq::read_fixed_point, gdb_mpq::write_fixed_point): Likewise.
        * gmp-utils.c (gdb_mpz::read): Change buf and len parameters
        into one single gdb::array_view parameter.
        Adjust implementation accordingly.
        (gdb_mpz::write): Likewise.
        (gdb_mpq::read_fixed_point, gdb_mpq::write_fixed_point): Likewise.
        * unittests/gmp-utils-selftests.c: Adapt following changes above.
        * valarith.c, valops.c, valprint.c, value.c: Likewise.
---
 gdb/gmp-utils.c                     | 25 +++++++++++++------------
 gdb/gmp-utils.h                     | 32 ++++++++++++++++++--------------
 gdb/unittests/gmp-utils-selftests.c | 16 ++++++++--------
 gdb/valarith.c                      |  9 ++++++---
 gdb/valops.c                        | 10 ++++++----
 gdb/valprint.c                      |  2 +-
 gdb/value.c                         |  3 ++-
 7 files changed, 54 insertions(+), 43 deletions(-)

diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index 44fe156..7994108 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -42,12 +42,12 @@ gmp_string_printf (const char *fmt, ...)
 /* See gmp-utils.h.  */
 
 void
-gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+gdb_mpz::read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
 	       bool unsigned_p)
 {
-  mpz_import (val, 1 /* count */, -1 /* order */, len /* size */,
+  mpz_import (val, 1 /* count */, -1 /* order */, buf.size () /* size */,
 	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
-	      0 /* nails */, buf /* op */);
+	      0 /* nails */, buf.data () /* op */);
 
   if (!unsigned_p)
     {
@@ -56,7 +56,7 @@ gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
 	 was in fact negative, we need to adjust VAL accordingly.  */
       gdb_mpz max;
 
-      mpz_ui_pow_ui (max.val, 2, len * TARGET_CHAR_BIT - 1);
+      mpz_ui_pow_ui (max.val, 2, buf.size () * TARGET_CHAR_BIT - 1);
       if (mpz_cmp (val, max.val) >= 0)
 	mpz_submul_ui (val, max.val, 2);
     }
@@ -65,7 +65,7 @@ gdb_mpz::read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
 /* See gmp-utils.h.  */
 
 void
-gdb_mpz::write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
 		bool unsigned_p) const
 {
   gdb_mpz exported_val (val);
@@ -77,14 +77,15 @@ gdb_mpz::write (gdb_byte *buf, int len, enum bfd_endian byte_order,
 	 would be the same as our negative value.  */
       gdb_mpz neg_offset;
 
-      mpz_ui_pow_ui (neg_offset.val, 2, len * TARGET_CHAR_BIT);
+      mpz_ui_pow_ui (neg_offset.val, 2, buf.size () * TARGET_CHAR_BIT);
       mpz_add (exported_val.val, exported_val.val, neg_offset.val);
     }
 
   /* Start by clearing the buffer, as mpz_export only writes as many
      bytes as it needs (including none, if the value to export is zero.  */
-  memset (buf, 0, len);
-  mpz_export (buf, NULL /* count */, -1 /* order */, len /* size */,
+  memset (buf.data (), 0, buf.size ());
+  mpz_export (buf.data (), NULL /* count */, -1 /* order */,
+	      buf.size () /* size */,
 	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
 	      0 /* nails */, exported_val.val);
 }
@@ -125,12 +126,12 @@ gdb_mpq::get_rounded () const
 /* See gmp-utils.h.  */
 
 void
-gdb_mpq::read_fixed_point (const gdb_byte *buf, int len,
+gdb_mpq::read_fixed_point (gdb::array_view<const gdb_byte> buf,
 			   enum bfd_endian byte_order, bool unsigned_p,
 			   const gdb_mpq &scaling_factor)
 {
   gdb_mpz vz;
-  vz.read (buf, len, byte_order, unsigned_p);
+  vz.read (buf, byte_order, unsigned_p);
 
   mpq_set_z (val, vz.val);
   mpq_mul (val, val, scaling_factor.val);
@@ -139,7 +140,7 @@ gdb_mpq::read_fixed_point (const gdb_byte *buf, int len,
 /* See gmp-utils.h.  */
 
 void
-gdb_mpq::write_fixed_point (gdb_byte *buf, int len,
+gdb_mpq::write_fixed_point (gdb::array_view<gdb_byte> buf,
 			    enum bfd_endian byte_order, bool unsigned_p,
 			    const gdb_mpq &scaling_factor) const
 {
@@ -148,7 +149,7 @@ gdb_mpq::write_fixed_point (gdb_byte *buf, int len,
   mpq_div (unscaled.val, unscaled.val, scaling_factor.val);
 
   gdb_mpz unscaled_z = unscaled.get_rounded ();
-  unscaled_z.write (buf, len, byte_order, unsigned_p);
+  unscaled_z.write (buf, byte_order, unsigned_p);
 }
 
 /* A wrapper around xrealloc that we can then register with GMP
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index 59965e5..12e4f8e 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -96,17 +96,19 @@ struct gdb_mpz
      The return type can signed or unsigned, with no size restriction.  */
   template<typename T> T as_integer () const;
 
-  /* Set VAL by importing the number stored in the byte buffer (BUF),
-     given its size (LEN) and BYTE_ORDER.
+  /* Set VAL by importing the number stored in the byte array (BUF),
+     using the given BYTE_ORDER.  The size of the data to read is
+     the byte array's size.
 
      UNSIGNED_P indicates whether the number has an unsigned type.  */
-  void read (const gdb_byte *buf, int len, enum bfd_endian byte_order,
+  void read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
 	     bool unsigned_p);
 
-  /* Write VAL into BUF as a LEN-bytes number with the given BYTE_ORDER.
+  /* Write VAL into BUF as a number whose byte size is the size of BUF,
+     using the given BYTE_ORDER.
 
      UNSIGNED_P indicates whether the number has an unsigned type.  */
-  void write (gdb_byte *buf, int len, enum bfd_endian byte_order,
+  void write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
 	      bool unsigned_p) const;
 
   /* Return a string containing VAL.  */
@@ -167,24 +169,26 @@ struct gdb_mpq
   /* Return VAL rounded to the nearest integer.  */
   gdb_mpz get_rounded () const;
 
-  /* Set VAL from the contents of the given buffer (BUF), which
-     contains the unscaled value of a fixed point type object
-     with the given size (LEN) and byte order (BYTE_ORDER).
+  /* Set VAL from the contents of the given byte array (BUF), which
+     contains the unscaled value of a fixed point type object.
+     The byte size of the data is the size of BUF.
+
+     BYTE_ORDER provides the byte_order to use when reading the data.
 
      UNSIGNED_P indicates whether the number has an unsigned type.
      SCALING_FACTOR is the scaling factor to apply after having
      read the unscaled value from our buffer.  */
-  void read_fixed_point (const gdb_byte *buf, int len,
+  void read_fixed_point (gdb::array_view<const gdb_byte> buf,
 			 enum bfd_endian byte_order, bool unsigned_p,
 			 const gdb_mpq &scaling_factor);
 
-  /* Write VAL into BUF as a LEN-bytes fixed point value following
-     the given BYTE_ORDER.
+  /* Write VAL into BUF as fixed point value following the given BYTE_ORDER.
+     The size of BUF is used as the length to write the value into.
 
      UNSIGNED_P indicates whether the number has an unsigned type.
      SCALING_FACTOR is the scaling factor to apply before writing
      the unscaled value to our buffer.  */
-  void write_fixed_point (gdb_byte *buf, int len,
+  void write_fixed_point (gdb::array_view<gdb_byte> buf,
 			  enum bfd_endian byte_order, bool unsigned_p,
 			  const gdb_mpq &scaling_factor) const;
 
@@ -213,13 +217,13 @@ struct gdb_mpf
      UNSIGNED_P indicates whether the number has an unsigned type.
      SCALING_FACTOR is the scaling factor to apply after having
      read the unscaled value from our buffer.  */
-  void read_fixed_point (const gdb_byte *buf, int len,
+  void read_fixed_point (gdb::array_view<const gdb_byte> buf,
 			 enum bfd_endian byte_order, bool unsigned_p,
 			 const gdb_mpq &scaling_factor)
   {
     gdb_mpq tmp_q;
 
-    tmp_q.read_fixed_point (buf, len, byte_order, unsigned_p, scaling_factor);
+    tmp_q.read_fixed_point (buf, byte_order, unsigned_p, scaling_factor);
     mpf_set_q (val, tmp_q.val);
   }
 
diff --git a/gdb/unittests/gmp-utils-selftests.c b/gdb/unittests/gmp-utils-selftests.c
index af5bc65..be78ac3 100644
--- a/gdb/unittests/gmp-utils-selftests.c
+++ b/gdb/unittests/gmp-utils-selftests.c
@@ -95,7 +95,7 @@ gdb_mpz_as_integer ()
 
 template<typename T>
 void
-store_and_read_back (T val, int buf_len, enum bfd_endian byte_order,
+store_and_read_back (T val, size_t buf_len, enum bfd_endian byte_order,
 		     gdb_mpz &expected, gdb_mpz &actual)
 {
   gdb_byte *buf;
@@ -109,7 +109,7 @@ store_and_read_back (T val, int buf_len, enum bfd_endian byte_order,
   mpz_set (actual.val, expected.val);
   mpz_sub_ui (actual.val, actual.val, 500);
 
-  actual.read (buf, buf_len, byte_order, !std::is_signed<T>::value);
+  actual.read ({buf, buf_len}, byte_order, !std::is_signed<T>::value);
 }
 
 /* Test the gdb_mpz::read method over a reasonable range of values.
@@ -227,14 +227,14 @@ gdb_mpz_read_min_max ()
 
 template<typename T>
 T
-write_and_extract (T val, int buf_len, enum bfd_endian byte_order)
+write_and_extract (T val, size_t buf_len, enum bfd_endian byte_order)
 {
   gdb_mpz v (val);
 
   SELF_CHECK (v.as_integer<T> () == val);
 
   gdb_byte *buf = (gdb_byte *) alloca (buf_len);
-  v.write (buf, buf_len, byte_order, !std::is_signed<T>::value);
+  v.write ({buf, buf_len}, byte_order, !std::is_signed<T>::value);
 
   return extract_integer<T> (buf, buf_len, byte_order);
 }
@@ -329,11 +329,11 @@ read_fp_test (int unscaled, const gdb_mpq &scaling_factor,
 {
   /* For this kind of testing, we'll use a buffer the same size as
      our unscaled parameter.  */
-  const int len = sizeof (unscaled);
+  const size_t len = sizeof (unscaled);
   gdb_byte buf[len];
   store_signed_integer (buf, len, byte_order, unscaled);
 
-  actual.read_fixed_point (buf, len, byte_order, 0, scaling_factor);
+  actual.read_fixed_point ({buf, len}, byte_order, 0, scaling_factor);
 
   mpq_set_si (expected.val, unscaled, 1);
   mpq_mul (expected.val, expected.val, scaling_factor.val);
@@ -395,14 +395,14 @@ write_fp_test (int numerator, unsigned int denominator,
      This is really an arbitrary decision, as long as the buffer
      is long enough to hold the unscaled values that we'll be
      writing.  */
-  const int len = sizeof (LONGEST);
+  const size_t len = sizeof (LONGEST);
   gdb_byte buf[len];
   memset (buf, 0, len);
 
   gdb_mpq v;
   mpq_set_ui (v.val, numerator, denominator);
   mpq_canonicalize (v.val);
-  v.write_fixed_point (buf, len, byte_order, 0, scaling_factor);
+  v.write_fixed_point ({buf, len}, byte_order, 0, scaling_factor);
 
   return extract_unsigned_integer (buf, len, byte_order);
 }
diff --git a/gdb/valarith.c b/gdb/valarith.c
index f4497cd..7ab183c 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -908,10 +908,12 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
     }
 
   gdb_mpq v1, v2, res;
-  v1.read_fixed_point (value_contents (arg1), TYPE_LENGTH (type1),
+  v1.read_fixed_point (gdb::make_array_view (value_contents (arg1),
+					     TYPE_LENGTH (type1)),
 		       type_byte_order (type1), type1->is_unsigned (),
 		       fixed_point_scaling_factor (type1));
-  v2.read_fixed_point (value_contents (arg2), TYPE_LENGTH (type2),
+  v2.read_fixed_point (gdb::make_array_view (value_contents (arg2),
+					     TYPE_LENGTH (type2)),
 		       type_byte_order (type2), type2->is_unsigned (),
 		       fixed_point_scaling_factor (type2));
 
@@ -919,7 +921,8 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   do { \
       val = allocate_value (type1); \
       (RESULT).write_fixed_point			\
-        (value_contents_raw (val), TYPE_LENGTH (type1), \
+        (gdb::make_array_view (value_contents_raw (val), \
+			       TYPE_LENGTH (type1)), \
 	 type_byte_order (type1), type1->is_unsigned (), \
 	 fixed_point_scaling_factor (type1)); \
      } while (0)
diff --git a/gdb/valops.c b/gdb/valops.c
index 0f84a70..3e2d5d3 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -357,7 +357,8 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
     {
       gdb_mpz vz;
 
-      vz.read (value_contents (from_val), TYPE_LENGTH (from_type),
+      vz.read (gdb::make_array_view (value_contents (from_val),
+				     TYPE_LENGTH (from_type)),
 	       type_byte_order (from_type), from_type->is_unsigned ());
       mpq_set_z (vq.val, vz.val);
 
@@ -378,8 +379,9 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
   /* Finally, create the result value, and pack the unscaled value
      in it.  */
   struct value *result = allocate_value (to_type);
-  unscaled.write (value_contents_raw (result),
-		  TYPE_LENGTH (to_type), type_byte_order (to_type),
+  unscaled.write (gdb::make_array_view (value_contents_raw (result),
+					TYPE_LENGTH (to_type)),
+		  type_byte_order (to_type),
 		  to_type->is_unsigned ());
 
   return result;
@@ -523,7 +525,7 @@ value_cast (struct type *type, struct value *arg2)
 	  gdb_mpq fp_val;
 
 	  fp_val.read_fixed_point
-	    (value_contents (arg2), TYPE_LENGTH (type2),
+	    (gdb::make_array_view (value_contents (arg2), TYPE_LENGTH (type2)),
 	     type_byte_order (type2), type2->is_unsigned (),
 	     fixed_point_scaling_factor (type2));
 
diff --git a/gdb/valprint.c b/gdb/valprint.c
index b102ff4..f428eb5 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -809,7 +809,7 @@ generic_val_print_fixed_point (struct value *val, struct ui_file *stream,
       const gdb_byte *valaddr = value_contents_for_printing (val);
       gdb_mpf f;
 
-      f.read_fixed_point (valaddr, TYPE_LENGTH (type),
+      f.read_fixed_point (gdb::make_array_view (valaddr, TYPE_LENGTH (type)),
 			  type_byte_order (type), type->is_unsigned (),
 			  fixed_point_scaling_factor (type));
 
diff --git a/gdb/value.c b/gdb/value.c
index a0546af..a122674 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2812,7 +2812,8 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
     case TYPE_CODE_FIXED_POINT:
       {
 	gdb_mpq vq;
-	vq.read_fixed_point (valaddr, len, byte_order, nosign,
+	vq.read_fixed_point (gdb::make_array_view (valaddr, len),
+			     byte_order, nosign,
 			     fixed_point_scaling_factor (type));
 
 	gdb_mpz vz;
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA v2 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro
  2020-11-22 11:14   ` RFA v2: " Joel Brobecker
  2020-11-22 11:14     ` [RFA v2 1/6] change and rename gmp_string_asprintf to return an std::string Joel Brobecker
  2020-11-22 11:14     ` [RFA v2 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view Joel Brobecker
@ 2020-11-22 11:14     ` Joel Brobecker
  2020-11-22 11:14     ` [RFA v2 4/6] Make fixed_point_type_base_type a method of struct type Joel Brobecker
                       ` (3 subsequent siblings)
  6 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:14 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This is one step further towards the removal of all these macros.

gdb/ChangeLog:

        * gdbtypes.h (struct type) <fixed_point_info, set_fixed_point_info>:
        New methods.
        (INIT_FIXED_POINT_SPECIFIC): Adjust.
        (TYPE_FIXED_POINT_INFO): Delete macro.
        (allocate_fixed_point_type_info): Change return type to void.
        * gdbtypes.c (copy_type_recursive): Replace the use of
        TYPE_FIXED_POINT_INFO by a call to the fixed_point_info method.
        (fixed_point_scaling_factor): Likewise.
        (allocate_fixed_point_type_info): Change return type to void.
        Adjust implementation accordingly.
        * dwarf2/read.c (finish_fixed_point_type): Replace the use of
        TYPE_FIXED_POINT_INFO by a call to the fixed_point_info method.
---
 gdb/dwarf2/read.c |  4 ++--
 gdb/gdbtypes.c    | 16 ++++++++--------
 gdb/gdbtypes.h    | 29 +++++++++++++++++++++++------
 3 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index f879753..601a571 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -18162,7 +18162,7 @@ get_dwarf2_unsigned_rational_constant (struct die_info *die,
 }
 
 /* Assuming DIE corresponds to a fixed point type, finish the creation
-   of the corresponding TYPE by setting its TYPE_FIXED_POINT_INFO.
+   of the corresponding TYPE by setting its type-specific data.
    CU is the DIE's CU.  */
 
 static void
@@ -18232,7 +18232,7 @@ finish_fixed_point_type (struct type *type, struct die_info *die,
 		 sect_offset_str (die->sect_off));
     }
 
-  gdb_mpq &scaling_factor = TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+  gdb_mpq &scaling_factor = type->fixed_point_info ().scaling_factor;
 
   gdb_mpz tmp_z (scale_num);
   mpz_set (mpq_numref (scaling_factor.val), tmp_z.val);
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 3879eeb..f0d9c24 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -5503,8 +5503,8 @@ copy_type_recursive (struct objfile *objfile,
       break;
     case TYPE_SPECIFIC_FIXED_POINT:
       INIT_FIXED_POINT_SPECIFIC (new_type);
-      TYPE_FIXED_POINT_INFO (new_type)->scaling_factor
-	= TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+      new_type->fixed_point_info ().scaling_factor
+	= type->fixed_point_info ().scaling_factor;
       break;
     case TYPE_SPECIFIC_INT:
       TYPE_SPECIFIC_FIELD (new_type) = TYPE_SPECIFIC_INT;
@@ -5826,11 +5826,11 @@ static const struct objfile_key<fixed_point_type_storage>
 
 /* See gdbtypes.h.  */
 
-fixed_point_type_info *
+void
 allocate_fixed_point_type_info (struct type *type)
 {
   std::unique_ptr<fixed_point_type_info> up (new fixed_point_type_info);
-  fixed_point_type_info *result;
+  fixed_point_type_info *info;
 
   if (TYPE_OBJFILE_OWNED (type))
     {
@@ -5838,17 +5838,17 @@ allocate_fixed_point_type_info (struct type *type)
 	= fixed_point_objfile_key.get (TYPE_OBJFILE (type));
       if (storage == nullptr)
 	storage = fixed_point_objfile_key.emplace (TYPE_OBJFILE (type));
-      result = up.get ();
+      info = up.get ();
       storage->push_back (std::move (up));
     }
   else
     {
       /* We just leak the memory, because that's what we do generally
 	 for non-objfile-attached types.  */
-      result = up.release ();
+      info = up.release ();
     }
 
-  return result;
+  type->set_fixed_point_info (info);
 }
 
 /* See gdbtypes.h.  */
@@ -5883,7 +5883,7 @@ fixed_point_scaling_factor (struct type *type)
 {
   type = fixed_point_type_base_type (type);
 
-  return TYPE_FIXED_POINT_INFO (type)->scaling_factor;
+  return type->fixed_point_info ().scaling_factor;
 }
 
 \f
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 2b6f599f..c9d2343 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1194,6 +1194,27 @@ struct type
     this->main_type->m_flag_endianity_not_default = endianity_is_not_default;
   }
 
+  /* * Assuming that THIS is a TYPE_CODE_FIXED_POINT, return a reference
+     to this type's fixed_point_info.  */
+
+  struct fixed_point_type_info &fixed_point_info () const
+  {
+    gdb_assert (this->code () == TYPE_CODE_FIXED_POINT);
+    gdb_assert (this->main_type->type_specific.fixed_point_info != nullptr);
+
+    return *this->main_type->type_specific.fixed_point_info;
+  }
+
+  /* * Assuming that THIS is a TYPE_CODE_FIXED_POINT, set this type's
+     fixed_point_info to INFO.  */
+
+  void set_fixed_point_info (struct fixed_point_type_info *info) const
+  {
+    gdb_assert (this->code () == TYPE_CODE_FIXED_POINT);
+
+    this->main_type->type_specific.fixed_point_info = info;
+  }
+
   /* * Return the dynamic property of the requested KIND from this type's
      list of dynamic properties.  */
   dynamic_prop *dyn_prop (dynamic_prop_node_kind kind) const;
@@ -1747,7 +1768,7 @@ extern void allocate_gnat_aux_type (struct type *);
    handled.  */
 #define INIT_FIXED_POINT_SPECIFIC(type) \
   (TYPE_SPECIFIC_FIELD (type) = TYPE_SPECIFIC_FIXED_POINT, \
-   TYPE_FIXED_POINT_INFO (type) = allocate_fixed_point_type_info (type))
+   allocate_fixed_point_type_info (type))
 
 #define TYPE_MAIN_TYPE(thistype) (thistype)->main_type
 #define TYPE_TARGET_TYPE(thistype) TYPE_MAIN_TYPE(thistype)->target_type
@@ -1845,9 +1866,6 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
   (TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits == NULL ? 0 \
     : B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (index)))
 
-#define TYPE_FIXED_POINT_INFO(thistype) \
-  (TYPE_MAIN_TYPE(thistype)->type_specific.fixed_point_info)
-
 #define FIELD_NAME(thisfld) ((thisfld).name)
 #define FIELD_LOC_KIND(thisfld) ((thisfld).loc_kind)
 #define FIELD_BITPOS_LVAL(thisfld) ((thisfld).loc.bitpos)
@@ -2582,8 +2600,7 @@ extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);
 
 /* Allocate a fixed-point type info for TYPE.  This should only be
    called by INIT_FIXED_POINT_SPECIFIC.  */
-extern fixed_point_type_info *allocate_fixed_point_type_info
-  (struct type *type);
+extern void allocate_fixed_point_type_info (struct type *type);
 
 /* * When the type includes explicit byte ordering, return that.
    Otherwise, the byte ordering from gdbarch_byte_order for 
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA v2 4/6] Make fixed_point_type_base_type a method of struct type
  2020-11-22 11:14   ` RFA v2: " Joel Brobecker
                       ` (2 preceding siblings ...)
  2020-11-22 11:14     ` [RFA v2 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro Joel Brobecker
@ 2020-11-22 11:14     ` Joel Brobecker
  2020-11-22 11:14     ` [RFA v2 5/6] Make function fixed_point_scaling_factor " Joel Brobecker
                       ` (2 subsequent siblings)
  6 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:14 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

As suggested by Simon, to logically connect this function to
the object it inspects.

Note that, logically, this method should be "const". Unfortunately,
the implementation iterates on struct type objects starting with "this",
and thus trying to declare the method "const" triggers a compilation
error.

gdb/ChangeLog:

        * gdbtypes.h (struct type) <fixed_point_type_base_type> New method,
        replacing the fixed_point_type_base_type function. All callers
        updated throughout this project.
        (fixed_point_type_base_type): Remove declaration.
        * gdbtypes.c (type::fixed_point_type_base_type): Replaces
        fixed_point_type_base_type.  Adjust implementation accordingly.
---
 gdb/ada-valprint.c |  2 +-
 gdb/gdbtypes.c     |  6 ++++--
 gdb/gdbtypes.h     | 17 +++++++++--------
 gdb/valprint.c     |  2 +-
 gdb/value.c        |  2 +-
 5 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c
index 482069a..6ddb584 100644
--- a/gdb/ada-valprint.c
+++ b/gdb/ada-valprint.c
@@ -1028,7 +1028,7 @@ ada_value_print_1 (struct value *val, struct ui_file *stream, int recurse,
     }
 
   if (is_fixed_point_type (type))
-    type = fixed_point_type_base_type (type);
+    type = type->fixed_point_type_base_type ();
 
   switch (type->code ())
     {
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index f0d9c24..fa4e8f0 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -5866,8 +5866,10 @@ is_fixed_point_type (struct type *type)
 /* See gdbtypes.h.  */
 
 struct type *
-fixed_point_type_base_type (struct type *type)
+type::fixed_point_type_base_type ()
 {
+  struct type *type = this;
+
   while (check_typedef (type)->code () == TYPE_CODE_RANGE)
     type = TYPE_TARGET_TYPE (check_typedef (type));
   type = check_typedef (type);
@@ -5881,7 +5883,7 @@ fixed_point_type_base_type (struct type *type)
 const gdb_mpq &
 fixed_point_scaling_factor (struct type *type)
 {
-  type = fixed_point_type_base_type (type);
+  type = type->fixed_point_type_base_type ();
 
   return type->fixed_point_info ().scaling_factor;
 }
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index c9d2343..88fb0e7 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1215,6 +1215,15 @@ struct type
     this->main_type->type_specific.fixed_point_info = info;
   }
 
+  /* * Assuming that THIS is a TYPE_CODE_FIXED_POINT, return its base type.
+
+     In other words, this returns the type after having peeled all
+     intermediate type layers (such as TYPE_CODE_RANGE, for instance).
+     The TYPE_CODE of the type returned is guaranteed to be
+     a TYPE_CODE_FIXED_POINT.  */
+
+  struct type *fixed_point_type_base_type ();
+
   /* * Return the dynamic property of the requested KIND from this type's
      list of dynamic properties.  */
   dynamic_prop *dyn_prop (dynamic_prop_node_kind kind) const;
@@ -2587,14 +2596,6 @@ extern int type_not_associated (const struct type *type);
    a range type whose base type is a TYPE_CODE_FIXED_POINT.  */
 extern bool is_fixed_point_type (struct type *type);
 
-/* Assuming that TYPE is a fixed point type, return its base type.
-
-   In other words, this returns the type after having peeled all
-   intermediate type layers (such as TYPE_CODE_RANGE, for instance).
-   The TYPE_CODE of the type returned is guaranteed to be
-   a TYPE_CODE_FIXED_POINT.  */
-extern struct type *fixed_point_type_base_type (struct type *type);
-
 /* Given TYPE, which is a fixed point type, return its scaling factor.  */
 extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);
 
diff --git a/gdb/valprint.c b/gdb/valprint.c
index f428eb5..6e9262e 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -871,7 +871,7 @@ generic_value_print (struct value *val, struct ui_file *stream, int recurse,
   type = check_typedef (type);
 
   if (is_fixed_point_type (type))
-    type = fixed_point_type_base_type (type);
+    type = type->fixed_point_type_base_type ();
 
   switch (type->code ())
     {
diff --git a/gdb/value.c b/gdb/value.c
index a122674..f6c1a36 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2759,7 +2759,7 @@ LONGEST
 unpack_long (struct type *type, const gdb_byte *valaddr)
 {
   if (is_fixed_point_type (type))
-    type = fixed_point_type_base_type (type);
+    type = type->fixed_point_type_base_type ();
 
   enum bfd_endian byte_order = type_byte_order (type);
   enum type_code code = type->code ();
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA v2 5/6] Make function fixed_point_scaling_factor a method of struct type
  2020-11-22 11:14   ` RFA v2: " Joel Brobecker
                       ` (3 preceding siblings ...)
  2020-11-22 11:14     ` [RFA v2 4/6] Make fixed_point_type_base_type a method of struct type Joel Brobecker
@ 2020-11-22 11:14     ` Joel Brobecker
  2020-11-22 11:14     ` [RFA v2 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by lambda Joel Brobecker
  2020-11-23 16:46     ` RFA v2: Various enhancements to the fixed-point support implementation Simon Marchi
  6 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:14 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

This logically connects this function to the object it inspects.

gdb/ChangeLog:

        * gdbtypes.h (struct type) <fixed_point_scaling_factor>: New method,
        replacing fixed_point_scaling_factor.  All callers updated
        throughout this project.
        (fixed_point_scaling_factor): Delete declaration.
        * gdbtypes.c (type::fixed_point_scaling_factor): Replaces
        fixed_point_scaling_factor.  Adjust implementation accordingly.
---
 gdb/gdbtypes.c  | 6 +++---
 gdb/gdbtypes.h  | 8 +++++---
 gdb/typeprint.c | 2 +-
 gdb/valarith.c  | 6 +++---
 gdb/valops.c    | 6 +++---
 gdb/valprint.c  | 2 +-
 gdb/value.c     | 2 +-
 7 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index fa4e8f0..4eaefa5 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -4927,7 +4927,7 @@ static void
 print_fixed_point_type_info (struct type *type, int spaces)
 {
   printfi_filtered (spaces + 2, "scaling factor: %s\n",
-		    fixed_point_scaling_factor (type).str ().c_str ());
+		    type->fixed_point_scaling_factor ().str ().c_str ());
 }
 
 static struct obstack dont_print_type_obstack;
@@ -5881,9 +5881,9 @@ type::fixed_point_type_base_type ()
 /* See gdbtypes.h.  */
 
 const gdb_mpq &
-fixed_point_scaling_factor (struct type *type)
+type::fixed_point_scaling_factor ()
 {
-  type = type->fixed_point_type_base_type ();
+  struct type *type = this->fixed_point_type_base_type ();
 
   return type->fixed_point_info ().scaling_factor;
 }
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 88fb0e7..eecd874 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1224,6 +1224,11 @@ struct type
 
   struct type *fixed_point_type_base_type ();
 
+  /* * Assuming that THIS is a TYPE_CODE_FIXED_POINT, return its scaling
+     factor.  */
+
+  const gdb_mpq &fixed_point_scaling_factor ();
+
   /* * Return the dynamic property of the requested KIND from this type's
      list of dynamic properties.  */
   dynamic_prop *dyn_prop (dynamic_prop_node_kind kind) const;
@@ -2596,9 +2601,6 @@ extern int type_not_associated (const struct type *type);
    a range type whose base type is a TYPE_CODE_FIXED_POINT.  */
 extern bool is_fixed_point_type (struct type *type);
 
-/* Given TYPE, which is a fixed point type, return its scaling factor.  */
-extern const gdb_mpq &fixed_point_scaling_factor (struct type *type);
-
 /* Allocate a fixed-point type info for TYPE.  This should only be
    called by INIT_FIXED_POINT_SPECIFIC.  */
 extern void allocate_fixed_point_type_info (struct type *type);
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 0dd3b1c..a3fc9cc 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -667,7 +667,7 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream)
 void
 print_type_fixed_point (struct type *type, struct ui_file *stream)
 {
-  std::string small_img = fixed_point_scaling_factor (type).str ();
+  std::string small_img = type->fixed_point_scaling_factor ().str ();
 
   fprintf_filtered (stream, "%s-byte fixed point (small = %s)",
 		    pulongest (TYPE_LENGTH (type)), small_img.c_str ());
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 7ab183c..29ac46b 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -911,11 +911,11 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   v1.read_fixed_point (gdb::make_array_view (value_contents (arg1),
 					     TYPE_LENGTH (type1)),
 		       type_byte_order (type1), type1->is_unsigned (),
-		       fixed_point_scaling_factor (type1));
+		       type1->fixed_point_scaling_factor ());
   v2.read_fixed_point (gdb::make_array_view (value_contents (arg2),
 					     TYPE_LENGTH (type2)),
 		       type_byte_order (type2), type2->is_unsigned (),
-		       fixed_point_scaling_factor (type2));
+		       type2->fixed_point_scaling_factor ());
 
 #define INIT_VAL_WITH_FIXED_POINT_VAL(RESULT) \
   do { \
@@ -924,7 +924,7 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
         (gdb::make_array_view (value_contents_raw (val), \
 			       TYPE_LENGTH (type1)), \
 	 type_byte_order (type1), type1->is_unsigned (), \
-	 fixed_point_scaling_factor (type1)); \
+	 type1->fixed_point_scaling_factor ()); \
      } while (0)
 
   switch (op)
diff --git a/gdb/valops.c b/gdb/valops.c
index 3e2d5d3..4d0e002 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -363,7 +363,7 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
       mpq_set_z (vq.val, vz.val);
 
       if (is_fixed_point_type (from_type))
-	mpq_mul (vq.val, vq.val, fixed_point_scaling_factor (from_type).val);
+	mpq_mul (vq.val, vq.val, from_type->fixed_point_scaling_factor ().val);
     }
 
   else
@@ -373,7 +373,7 @@ value_cast_to_fixed_point (struct type *to_type, struct value *from_val)
   /* Divide that value by the scaling factor to obtain the unscaled
      value, first in rational form, and then in integer form.  */
 
-  mpq_div (vq.val, vq.val, fixed_point_scaling_factor (to_type).val);
+  mpq_div (vq.val, vq.val, to_type->fixed_point_scaling_factor ().val);
   gdb_mpz unscaled = vq.get_rounded ();
 
   /* Finally, create the result value, and pack the unscaled value
@@ -527,7 +527,7 @@ value_cast (struct type *type, struct value *arg2)
 	  fp_val.read_fixed_point
 	    (gdb::make_array_view (value_contents (arg2), TYPE_LENGTH (type2)),
 	     type_byte_order (type2), type2->is_unsigned (),
-	     fixed_point_scaling_factor (type2));
+	     type2->fixed_point_scaling_factor ());
 
 	  struct value *v = allocate_value (to_type);
 	  target_float_from_host_double (value_contents_raw (v),
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 6e9262e..50278ac 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -811,7 +811,7 @@ generic_val_print_fixed_point (struct value *val, struct ui_file *stream,
 
       f.read_fixed_point (gdb::make_array_view (valaddr, TYPE_LENGTH (type)),
 			  type_byte_order (type), type->is_unsigned (),
-			  fixed_point_scaling_factor (type));
+			  type->fixed_point_scaling_factor ());
 
       const char *fmt = TYPE_LENGTH (type) < 4 ? "%.11Fg" : "%.17Fg";
       std::string str = gmp_string_printf (fmt, f.val);
diff --git a/gdb/value.c b/gdb/value.c
index f6c1a36..0087fe5 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2814,7 +2814,7 @@ unpack_long (struct type *type, const gdb_byte *valaddr)
 	gdb_mpq vq;
 	vq.read_fixed_point (gdb::make_array_view (valaddr, len),
 			     byte_order, nosign,
-			     fixed_point_scaling_factor (type));
+			     type->fixed_point_scaling_factor ());
 
 	gdb_mpz vz;
 	mpz_tdiv_q (vz.val, mpq_numref (vq.val), mpq_denref (vq.val));
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA v2 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by lambda
  2020-11-22 11:14   ` RFA v2: " Joel Brobecker
                       ` (4 preceding siblings ...)
  2020-11-22 11:14     ` [RFA v2 5/6] Make function fixed_point_scaling_factor " Joel Brobecker
@ 2020-11-22 11:14     ` Joel Brobecker
  2020-11-23 16:46     ` RFA v2: Various enhancements to the fixed-point support implementation Simon Marchi
  6 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:14 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

gdb/ChangeLog (Simon Marchi  <simark@simark.ca>):

        * valarith.c (fixed_point_binop): Replace the
        INIT_VAL_WITH_FIXED_POINT_VAL macro by a lambda.  Update all
        users accordingly.
---
 gdb/valarith.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/gdb/valarith.c b/gdb/valarith.c
index 29ac46b..5b2bf18 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -917,44 +917,48 @@ fixed_point_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
 		       type_byte_order (type2), type2->is_unsigned (),
 		       type2->fixed_point_scaling_factor ());
 
-#define INIT_VAL_WITH_FIXED_POINT_VAL(RESULT) \
-  do { \
-      val = allocate_value (type1); \
-      (RESULT).write_fixed_point			\
-        (gdb::make_array_view (value_contents_raw (val), \
-			       TYPE_LENGTH (type1)), \
-	 type_byte_order (type1), type1->is_unsigned (), \
-	 type1->fixed_point_scaling_factor ()); \
-     } while (0)
+  auto fixed_point_to_value = [type1] (const gdb_mpq &fp)
+    {
+      value *fp_val = allocate_value (type1);
+
+      fp.write_fixed_point
+	(gdb::make_array_view (value_contents_raw (fp_val),
+			       TYPE_LENGTH (type1)),
+	 type_byte_order (type1),
+	 type1->is_unsigned (),
+	 type1->fixed_point_scaling_factor ());
+
+      return fp_val;
+    };
 
   switch (op)
     {
     case BINOP_ADD:
       mpq_add (res.val, v1.val, v2.val);
-      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      val = fixed_point_to_value (res);
       break;
 
     case BINOP_SUB:
       mpq_sub (res.val, v1.val, v2.val);
-      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      val = fixed_point_to_value (res);
       break;
 
     case BINOP_MIN:
-      INIT_VAL_WITH_FIXED_POINT_VAL (mpq_cmp (v1.val, v2.val) < 0 ? v1 : v2);
+      val = fixed_point_to_value (mpq_cmp (v1.val, v2.val) < 0 ? v1 : v2);
       break;
 
     case BINOP_MAX:
-      INIT_VAL_WITH_FIXED_POINT_VAL (mpq_cmp (v1.val, v2.val) > 0 ? v1 : v2);
+      val = fixed_point_to_value (mpq_cmp (v1.val, v2.val) > 0 ? v1 : v2);
       break;
 
     case BINOP_MUL:
       mpq_mul (res.val, v1.val, v2.val);
-      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      val = fixed_point_to_value (res);
       break;
 
     case BINOP_DIV:
       mpq_div (res.val, v1.val, v2.val);
-      INIT_VAL_WITH_FIXED_POINT_VAL (res);
+      val = fixed_point_to_value (res);
       break;
 
     case BINOP_EQUAL:
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* RFA/doco: Various changes related to GMP and fixed point type support
  2020-11-15  8:35 ` pushed: " Joel Brobecker
                     ` (10 preceding siblings ...)
  2020-11-20 14:08   ` pushed: Add support for DWARF-based fixed point types Pedro Alves
@ 2020-11-22 11:56   ` Joel Brobecker
  2020-11-22 11:56     ` [RFA/doco 1/4] gdb/NEWS: Document that building GDB now requires GMP Joel Brobecker
                       ` (3 more replies)
  11 siblings, 4 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:56 UTC (permalink / raw)
  To: gdb-patches

Hello,

This patch series only updates our NEWS and README files, following
some changes I pushed recently (thanks to Pedro for reminding me
of this).

  - [RFA/doco 1/4] gdb/NEWS: Document that building GDB now requires GMP
  - [RFA/doco 2/4] gdb/NEWS: Document that GDB now supports DWARF-based
  - [RFA/doco 3/4] gdb/README: Document the --with-libgmp-prefix
  - [RFA/doco 4/4] gdb/README: Fix the URL of the MPFR website (now

OK to push to master?

Thank you!
-- 
Joel


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA/doco 1/4] gdb/NEWS: Document that building GDB now requires GMP
  2020-11-22 11:56   ` RFA/doco: Various changes related to GMP and fixed point type support Joel Brobecker
@ 2020-11-22 11:56     ` Joel Brobecker
  2020-11-22 15:31       ` Eli Zaretskii
  2020-11-22 11:56     ` [RFA/doco 2/4] gdb/NEWS: Document that GDB now supports DWARF-based fixed point types Joel Brobecker
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:56 UTC (permalink / raw)
  To: gdb-patches; +Cc: Pedro Alves, Joel Brobecker

gdb/ChangeLog:

        * NEWS: Document that building GDB now requires GMP.
---
 gdb/NEWS | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/gdb/NEWS b/gdb/NEWS
index d1f721c3953..792f4860975 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,9 @@
 
 *** Changes since GDB 10
 
+* Building GDB now requires GMP (The GNU Multiple Precision Arithmetic
+  Library).
+
 * MI changes
 
  ** '-break-insert --qualified' and '-dprintf-insert --qualified'
-- 
2.25.1


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA/doco 2/4] gdb/NEWS: Document that GDB now supports DWARF-based fixed point types
  2020-11-22 11:56   ` RFA/doco: Various changes related to GMP and fixed point type support Joel Brobecker
  2020-11-22 11:56     ` [RFA/doco 1/4] gdb/NEWS: Document that building GDB now requires GMP Joel Brobecker
@ 2020-11-22 11:56     ` Joel Brobecker
  2020-11-22 15:33       ` Eli Zaretskii
  2020-11-22 11:56     ` [RFA/doco 3/4] gdb/README: Document the --with-libgmp-prefix configure option Joel Brobecker
  2020-11-22 11:56     ` [RFA/doco 4/4] gdb/README: Fix the URL of the MPFR website (now https) Joel Brobecker
  3 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:56 UTC (permalink / raw)
  To: gdb-patches; +Cc: Pedro Alves, Joel Brobecker

gdb/ChangeLog:

        * NEWS: Add entry documenting support for DWARF-based fixed
        point types.
---
 gdb/NEWS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/gdb/NEWS b/gdb/NEWS
index 792f4860975..d75992e78ef 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -24,6 +24,15 @@
   $HOME/.gdbinit.  On Apple hosts the search order is instead:
   $HOME/Library/Preferences/gdb/gdbinit, $HOME/.gdbinit.
 
+* GDB now supports fixed point types which are described in DWARF
+  as base types with a fixed-point encoding.  Additionally, support
+  for the DW_AT_GNU_numerator and DW_AT_GNU_denominator has also
+  been added.
+
+  For Ada, this allows support for fixed point types without requiring
+  the use of the GNAT encoding (based on information added to the type's
+  name following a GNAT-specific format).
+
 * New commands
 
 set debug event-loop
-- 
2.25.1


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA/doco 3/4] gdb/README: Document the --with-libgmp-prefix configure option
  2020-11-22 11:56   ` RFA/doco: Various changes related to GMP and fixed point type support Joel Brobecker
  2020-11-22 11:56     ` [RFA/doco 1/4] gdb/NEWS: Document that building GDB now requires GMP Joel Brobecker
  2020-11-22 11:56     ` [RFA/doco 2/4] gdb/NEWS: Document that GDB now supports DWARF-based fixed point types Joel Brobecker
@ 2020-11-22 11:56     ` Joel Brobecker
  2020-11-22 15:32       ` Eli Zaretskii
  2020-11-22 11:56     ` [RFA/doco 4/4] gdb/README: Fix the URL of the MPFR website (now https) Joel Brobecker
  3 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:56 UTC (permalink / raw)
  To: gdb-patches; +Cc: Pedro Alves, Joel Brobecker

gdb/ChangeLog:

        * README: Document the --with-libgmp-prefix configure option.
---
 gdb/README | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/gdb/README b/gdb/README
index 0ec1605ce5a..a7908453ba7 100644
--- a/gdb/README
+++ b/gdb/README
@@ -484,6 +484,11 @@ more obscure GDB `configure' options are not listed here.
      not have liblzma installed, you can get the latest version from
      `https://tukaani.org/xz/'.
 
+`--with-libgmp-prefix=DIR'
+     Build GDB using the GMP library installed at the directory DIR.
+     If your host does not have GMP installed, you can get the latest
+     version at `https://gmplib.org/'.
+
 `--with-mpfr'
      Build GDB with GNU MPFR, a library for multiple-precision
      floating-point computation with correct rounding.  (Done by
-- 
2.25.1


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA/doco 4/4] gdb/README: Fix the URL of the MPFR website (now https).
  2020-11-22 11:56   ` RFA/doco: Various changes related to GMP and fixed point type support Joel Brobecker
                       ` (2 preceding siblings ...)
  2020-11-22 11:56     ` [RFA/doco 3/4] gdb/README: Document the --with-libgmp-prefix configure option Joel Brobecker
@ 2020-11-22 11:56     ` Joel Brobecker
  2020-11-22 15:33       ` Eli Zaretskii
  3 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 11:56 UTC (permalink / raw)
  To: gdb-patches; +Cc: Pedro Alves, Joel Brobecker

gdb/ChangeLog:

        * README: Fix the URL of the MPFR library.
---
 gdb/README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gdb/README b/gdb/README
index a7908453ba7..e65c5ea7ffa 100644
--- a/gdb/README
+++ b/gdb/README
@@ -498,7 +498,7 @@ more obscure GDB `configure' options are not listed here.
      floating-point formats than the host.  If GNU MPFR is not
      available, GDB will fall back to using host floating-point
      arithmetic.  If your host does not have GNU MPFR installed, you
-     can get the latest version from `http://www.mpfr.org'.
+     can get the latest version from `https://www.mpfr.org/'.
 
 `--with-python[=PYTHON]'
      Build GDB with Python scripting support.  (Done by default if
-- 
2.25.1


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA] Add TYPE_CODE_FIXED_POINT handling in print_type_scalar
  2020-11-18  3:47       ` Joel Brobecker
@ 2020-11-22 13:12         ` Joel Brobecker
  2020-11-22 14:35           ` Simon Marchi
  2020-11-22 14:00         ` pushed: Add support for DWARF-based fixed point types Joel Brobecker
  1 sibling, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 13:12 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

Hello,

This commit enhances print_type_scalar to include support for
TYPE_CODE_FIXED_POINT. This way, any language falling back to
this function for printing the description of some types
also gets basic ptype support for fixed point types as well.

This fixes a couple of XFAILs in gdb.dwarf2/dw2-fixed-point.exp.

gdb/ChangeLog:

        * typeprint.c (print_type_scalar): Add handling of
        TYPE_CODE_FIXED_POINT.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-fixed-point.exp: Fix the expected output of
        the "ptype pck__fp1_range_var" test for the module-2 and pascal
        languages.  Remove the associated setup_xfail.

The ptype output for range types in modula-2 and pascal is a little
odd (the type info is repeated twice around the ".." operator), but
I guess that's how they present range types in those languages.

Tested on x86_64-linux, with the 2 XFAILs replaced by PASSes and
no regression.

OK to push to master?

Thanks,
-- 
Joel

---
 gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp | 28 ++++++++++++++++++----------
 gdb/typeprint.c                              |  4 ++++
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
index a82a9af..67d1d34 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-fixed-point.exp
@@ -278,9 +278,6 @@ proc do_ptype_test {lang fp1_re fp2_re fp3_re fp1_range_re} {
 
         gdb_test "ptype pck__fp3_var" $fp3_re
 
-        if { $lang == "modula-2" || $lang == "pascal" } {
-            setup_xfail "*-*-*" "not supported by language"
-        }
         gdb_test "ptype pck__fp1_range_var" $fp1_range_re
     }
 }
@@ -299,10 +296,21 @@ foreach lang [list "c" "d" "go" "objective-c" "opencl" ] {
                   " = <range type>"
 }
 
-foreach lang [list "fortran" "modula-2" "pascal" ] {
-    do_ptype_test $lang \
-                  " = pck__fp1_type" \
-                  " = pck__fp2_type" \
-                  " = pck__fp3_type" \
-                  " = <range type>"
-}
+do_ptype_test "fortran" \
+          " = pck__fp1_type" \
+          " = pck__fp2_type" \
+          " = pck__fp3_type" \
+          " = <range type>"
+
+do_ptype_test "modula-2" \
+          " = pck__fp1_type" \
+          " = pck__fp2_type" \
+          " = pck__fp3_type" \
+          " = \\\[1-byte fixed point \\(small = 1/16\\)\\.\\.1-byte fixed point \\(small = 1/16\\)\\\]"
+
+do_ptype_test "pascal" \
+          " = pck__fp1_type" \
+          " = pck__fp2_type" \
+          " = pck__fp3_type" \
+          " = 1-byte fixed point \\(small = 1/16\\)\\.\\.1-byte fixed point \\(small = 1/16\\)"
+
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index a3fc9cc..47019a2 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -637,6 +637,10 @@ print_type_scalar (struct type *type, LONGEST val, struct ui_file *stream)
       print_type_scalar (TYPE_TARGET_TYPE (type), val, stream);
       return;
 
+    case TYPE_CODE_FIXED_POINT:
+      print_type_fixed_point (type, stream);
+      break;
+
     case TYPE_CODE_UNDEF:
     case TYPE_CODE_PTR:
     case TYPE_CODE_ARRAY:
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: pushed: Add support for DWARF-based fixed point types
  2020-11-18  3:47       ` Joel Brobecker
  2020-11-22 13:12         ` [RFA] Add TYPE_CODE_FIXED_POINT handling in print_type_scalar Joel Brobecker
@ 2020-11-22 14:00         ` Joel Brobecker
  2020-11-22 20:11           ` Simon Marchi
  1 sibling, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-22 14:00 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

> > I didn't see it in my -O0 compiled GDB, but I do see it in my -O2
> > compiled GDB.
> 
> Hmmm, I'm wondering if this might be indicative of a bug in GDB,
> rather than in GMP. I will take a look at it this weekend.

I've been able to reproduce the problem, including with a GDB
built at -O0. In order to do so, I had to use the system GCC,
though. Before that, I was using AdaCore's version of GCC and
couldn't reproduce with that.

I'm out of time for this weekend, unfortunately, so it's at the top
of my TODO for next weekend.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA] Add TYPE_CODE_FIXED_POINT handling in print_type_scalar
  2020-11-22 13:12         ` [RFA] Add TYPE_CODE_FIXED_POINT handling in print_type_scalar Joel Brobecker
@ 2020-11-22 14:35           ` Simon Marchi
  2020-11-24  3:04             ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-22 14:35 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches


On 2020-11-22 8:12 a.m., Joel Brobecker wrote:
> Hello,
>
> This commit enhances print_type_scalar to include support for
> TYPE_CODE_FIXED_POINT. This way, any language falling back to
> this function for printing the description of some types
> also gets basic ptype support for fixed point types as well.
>
> This fixes a couple of XFAILs in gdb.dwarf2/dw2-fixed-point.exp.
>
> gdb/ChangeLog:
>
>         * typeprint.c (print_type_scalar): Add handling of
>         TYPE_CODE_FIXED_POINT.
>
> gdb/testsuite/ChangeLog:
>
>         * gdb.dwarf2/dw2-fixed-point.exp: Fix the expected output of
>         the "ptype pck__fp1_range_var" test for the module-2 and pascal
>         languages.  Remove the associated setup_xfail.
>
> The ptype output for range types in modula-2 and pascal is a little
> odd (the type info is repeated twice around the ".." operator), but
> I guess that's how they present range types in those languages.

Yeah, it seems like it.  Thanks for doing this, the change to handle
fixed point in the generic print_type_scalar function looks good to me.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA/doco 1/4] gdb/NEWS: Document that building GDB now requires GMP
  2020-11-22 11:56     ` [RFA/doco 1/4] gdb/NEWS: Document that building GDB now requires GMP Joel Brobecker
@ 2020-11-22 15:31       ` Eli Zaretskii
  2020-11-24  3:11         ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Eli Zaretskii @ 2020-11-22 15:31 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

> From: Joel Brobecker <brobecker@adacore.com>
> Date: Sun, 22 Nov 2020 15:56:27 +0400
> Cc: Joel Brobecker <brobecker@adacore.com>
> 
> gdb/ChangeLog:
> 
>         * NEWS: Document that building GDB now requires GMP.

OK.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA/doco 3/4] gdb/README: Document the --with-libgmp-prefix configure option
  2020-11-22 11:56     ` [RFA/doco 3/4] gdb/README: Document the --with-libgmp-prefix configure option Joel Brobecker
@ 2020-11-22 15:32       ` Eli Zaretskii
  2020-11-24  3:11         ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Eli Zaretskii @ 2020-11-22 15:32 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

> From: Joel Brobecker <brobecker@adacore.com>
> Date: Sun, 22 Nov 2020 15:56:29 +0400
> Cc: Joel Brobecker <brobecker@adacore.com>
> 
> gdb/ChangeLog:
> 
>         * README: Document the --with-libgmp-prefix configure option.

OK, thanks.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA/doco 4/4] gdb/README: Fix the URL of the MPFR website (now https).
  2020-11-22 11:56     ` [RFA/doco 4/4] gdb/README: Fix the URL of the MPFR website (now https) Joel Brobecker
@ 2020-11-22 15:33       ` Eli Zaretskii
  2020-11-24  3:11         ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Eli Zaretskii @ 2020-11-22 15:33 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

> From: Joel Brobecker <brobecker@adacore.com>
> Date: Sun, 22 Nov 2020 15:56:30 +0400
> Cc: Joel Brobecker <brobecker@adacore.com>
> 
> gdb/ChangeLog:
> 
>         * README: Fix the URL of the MPFR library.

OK.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA/doco 2/4] gdb/NEWS: Document that GDB now supports DWARF-based fixed point types
  2020-11-22 11:56     ` [RFA/doco 2/4] gdb/NEWS: Document that GDB now supports DWARF-based fixed point types Joel Brobecker
@ 2020-11-22 15:33       ` Eli Zaretskii
  2020-11-24  3:12         ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Eli Zaretskii @ 2020-11-22 15:33 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

> From: Joel Brobecker <brobecker@adacore.com>
> Date: Sun, 22 Nov 2020 15:56:28 +0400
> Cc: Joel Brobecker <brobecker@adacore.com>
> 
> gdb/ChangeLog:
> 
>         * NEWS: Add entry documenting support for DWARF-based fixed
>         point types.

Thanks, this is OK.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: pushed: Add support for DWARF-based fixed point types
  2020-11-22 14:00         ` pushed: Add support for DWARF-based fixed point types Joel Brobecker
@ 2020-11-22 20:11           ` Simon Marchi
  2020-11-23  4:27             ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-22 20:11 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On 2020-11-22 9:00 a.m., Joel Brobecker wrote:
> I've been able to reproduce the problem, including with a GDB
> built at -O0. In order to do so, I had to use the system GCC,
> though. Before that, I was using AdaCore's version of GCC and
> couldn't reproduce with that.
>
> I'm out of time for this weekend, unfortunately, so it's at the top
> of my TODO for next weekend.

I didn't find the root cause (and whether GDB using GMP wrong or if it
is a bug in GMP (less likely)), but here's what I found.

Building both GDB and GMP with ASan makes the issue more obvious:

    Running selftest gdb_mpq_write_fixed_point.
    =================================================================
    ==3672064==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd6de06d08 at pc 0x7f185073086d bp 0x7ffd6de068a0 sp 0x7ffd6de06890
    WRITE of size 8 at 0x7ffd6de06d08 thread T0
        #0 0x7f185073086c in __gmpz_export /home/smarchi/src/gmp-6.2.0+dfsg/mpz/export.c:103
        #1 0x557c2db68395 in gdb_mpz::write(unsigned char*, int, bfd_endian, bool) const /home/smarchi/src/binutils-gdb/gdb/gmp-utils.c:80
        #2 0x557c2db68d02 in gdb_mpq::write_fixed_point(unsigned char*, int, bfd_endian, bool, gdb_mpq const&) const /home/smarchi/src/binutils-gdb/gdb/gmp-utils.c:144
        #3 0x557c2ed2f796 in write_fp_test /home/smarchi/src/binutils-gdb/gdb/unittests/gmp-utils-selftests.c:405
        #4 0x557c2ed2f949 in gdb_mpq_write_fixed_point /home/smarchi/src/binutils-gdb/gdb/unittests/gmp-utils-selftests.c:426
        #5 0x557c300b280c in selftests::simple_selftest::operator()() const /home/smarchi/src/binutils-gdb/gdbsupport/selftest.cc:43
        #6 0x557c300b22e2 in selftests::run_tests(gdb::array_view<char const* const>) /home/smarchi/src/binutils-gdb/gdbsupport/selftest.cc:99
        #7 0x557c2dfce6c2 in maintenance_selftest /home/smarchi/src/binutils-gdb/gdb/maint.c:1026
        #8 0x557c2d3dbe12 in do_const_cfunc /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:95
        #9 0x557c2d3eb02d in cmd_func(cmd_list_element*, char const*, int) /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:2181
        #10 0x557c2eb6e985 in execute_command(char const*, int) /home/smarchi/src/binutils-gdb/gdb/top.c:668
        #11 0x557c2dfaa4c9 in catch_command_errors /home/smarchi/src/binutils-gdb/gdb/main.c:448
        #12 0x557c2dfaacf0 in execute_cmdargs /home/smarchi/src/binutils-gdb/gdb/main.c:533
        #13 0x557c2dfae6b1 in captured_main_1 /home/smarchi/src/binutils-gdb/gdb/main.c:1203
        #14 0x557c2dfaebc5 in captured_main /home/smarchi/src/binutils-gdb/gdb/main.c:1224
        #15 0x557c2dfaecad in gdb_main(captured_main_args*) /home/smarchi/src/binutils-gdb/gdb/main.c:1249
        #16 0x557c2cdd0311 in main /home/smarchi/src/binutils-gdb/gdb/gdb.c:32
        #17 0x7f184f9850b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
        #18 0x557c2cdd00ed in _start (/home/smarchi/build/binutils-gdb-all-targets/gdb/gdb+0x4a2e0ed)

    Address 0x7ffd6de06d08 is located in stack of thread T0 at offset 104 in frame
        #0 0x557c2ed2f669 in write_fp_test /home/smarchi/src/binutils-gdb/gdb/unittests/gmp-utils-selftests.c:393

      This frame has 2 object(s):
        [32, 64) 'v' (line 402)
        [96, 104) 'buf' (line 399) <== Memory access at offset 104 overflows this variable
    HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
          (longjmp and C++ exceptions *are* supported)
    SUMMARY: AddressSanitizer: stack-buffer-overflow /home/smarchi/src/gmp-6.2.0+dfsg/mpz/export.c:103 in __gmpz_export

We pass mpz_export a buffer of 8 bytes (statically allocated in
write_fp_test), but GMP decides it needs to write 16 bytes, hence the
overflow.

I tried to read the GMP doc, but I am familiar with its concepts, so I
don't really understand if we are using the API correctly or not.

For reference this is how I configured libgmp:

  ./configure '--prefix=/tmp/gmp-install' 'CFLAGS=-g3 -O0 -fsanitize=address' 'CXXFLAGS=-g3 -O0 -fsanitize=address' 'LDFLAGS=-fsanitize=address'

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: pushed: Add support for DWARF-based fixed point types
  2020-11-22 20:11           ` Simon Marchi
@ 2020-11-23  4:27             ` Joel Brobecker
  2020-11-23 16:12               ` Simon Marchi
  2020-11-29 15:45               ` RFA: wrap mpz_export into gdb_mpz::safe_export Joel Brobecker
  0 siblings, 2 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-23  4:27 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1233 bytes --]

> We pass mpz_export a buffer of 8 bytes (statically allocated in
> write_fp_test), but GMP decides it needs to write 16 bytes, hence the
> overflow.
> 
> I tried to read the GMP doc, but I am familiar with its concepts, so I
> don't really understand if we are using the API correctly or not.

I found the source of the problem, which was in a way subtle-enough
that you really have to pay attention to these details (which,
luckily, are handled automatically thanks to our minor C++-ification
of GMP in gmp-utils), and yet so obvious once you find it.
Attached is the patch that I will push later today (need to run RSN,
and don't want to make a mistake because I'm rushing).

I think this error might be highlighting a weakness, though. I need
to investigate more, but I'm thinking it might be wise to add some
checks during export that the buffer size is large enough to fit
the value. In other words, I'm thinking of having our own
safe_mpz_export which double-checks the size of the buffer according
to the formula given by the documentation, and raises an error if
too small.

The fact that GMP happily goes beyond the end of the buffer is
a bit unexpected, still. Maybe something to report to the GMP team.

Later!

-- 
Joel

[-- Attachment #2: 0001-Fix-stack-smashing-error-during-gdb_mpq_write_fixed_.patch --]
[-- Type: text/x-diff, Size: 2944 bytes --]

From 1cb4f9e076dbd87808783e6f4f54b4b22c45d0e5 Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Mon, 23 Nov 2020 08:02:10 +0400
Subject: [PATCH] Fix stack smashing error during gdb_mpq_write_fixed_point
 selftest

When building GDB using Ubuntu 20.04's system libgmp and compiler,
running the "maintenance selftest" command triggers the following error:

    | Running selftest gdb_mpq_write_fixed_point.
    | *** stack smashing detected ***: terminated
    | [1]    1092790 abort (core dumped)  ./gdb gdb

This happens while trying to construct an mpq_t object (a rational)
from two integers representing the numerator and denominator.
In our test, the numerator is -8, and the denominator is 1.
The problem was that the rational was constructed using the wrong
function. This is what we were doing prior to this patch:

    mpq_set_ui (v.val, numerator, denominator);

The 'u' in "ui" stands for *unsigned*, which is wrong because
numerator and denominator's type is "int".

As a result of the above, instead of getting a rational value of -8,
we get a rational with a very large positive value (gmp_printf
says "18446744073709551608").

From there, the test performs an operation which is expected to
write this value into a buffer which was not dimensioned to fit
such a number, thus leading GMP into a buffer overflow.
This was verified by applying the formula that GMP's documentation
gives for the required memory buffer size needed during export:

    | When an application is allocating space itself the required size can
    | be determined with a calculation like the following. Since
    | mpz_sizeinbase always returns at least 1, count here will be at
    | least one, which avoids any portability problems with malloc(0),
    | though if z is zero no space at all is actually needed (or written).
    |
    |     numb = 8*size - nail;
    |     count = (mpz_sizeinbase (z, 2) + numb-1) / numb;
    |     p = malloc (count * size);

With the very large number, mpz_sizeinbase returns 66 and thus
the malloc size becomes 16 bytes instead of the 8 we allocated.

This patch fixes the issue by using the correct "set" function.

gdb/ChangeLog:

        * unittests/gmp-utils-selftests.c (write_fp_test): Use mpq_set_si
        instead of mpq_set_ui to initialize our GMP rational.
---
 gdb/unittests/gmp-utils-selftests.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gdb/unittests/gmp-utils-selftests.c b/gdb/unittests/gmp-utils-selftests.c
index af5bc65d2f9..175ab3f9827 100644
--- a/gdb/unittests/gmp-utils-selftests.c
+++ b/gdb/unittests/gmp-utils-selftests.c
@@ -400,7 +400,7 @@ write_fp_test (int numerator, unsigned int denominator,
   memset (buf, 0, len);
 
   gdb_mpq v;
-  mpq_set_ui (v.val, numerator, denominator);
+  mpq_set_si (v.val, numerator, denominator);
   mpq_canonicalize (v.val);
   v.write_fixed_point (buf, len, byte_order, 0, scaling_factor);
 
-- 
2.25.1


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: pushed: Add support for DWARF-based fixed point types
  2020-11-23  4:27             ` Joel Brobecker
@ 2020-11-23 16:12               ` Simon Marchi
  2020-11-24  2:39                 ` Joel Brobecker
  2020-11-29 15:45               ` RFA: wrap mpz_export into gdb_mpz::safe_export Joel Brobecker
  1 sibling, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-23 16:12 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On 2020-11-22 11:27 p.m., Joel Brobecker wrote:
>> We pass mpz_export a buffer of 8 bytes (statically allocated in
>> write_fp_test), but GMP decides it needs to write 16 bytes, hence the
>> overflow.
>>
>> I tried to read the GMP doc, but I am familiar with its concepts, so I
>> don't really understand if we are using the API correctly or not.
> 
> I found the source of the problem, which was in a way subtle-enough
> that you really have to pay attention to these details (which,
> luckily, are handled automatically thanks to our minor C++-ification
> of GMP in gmp-utils), and yet so obvious once you find it.
> Attached is the patch that I will push later today (need to run RSN,
> and don't want to make a mistake because I'm rushing).
> 
> I think this error might be highlighting a weakness, though. I need
> to investigate more, but I'm thinking it might be wise to add some
> checks during export that the buffer size is large enough to fit
> the value. In other words, I'm thinking of having our own
> safe_mpz_export which double-checks the size of the buffer according
> to the formula given by the documentation, and raises an error if
> too small.
> 
> The fact that GMP happily goes beyond the end of the buffer is
> a bit unexpected, still. Maybe something to report to the GMP team.

Ah, nice!  The explanation in the commit message makes sense, thanks.

And yes, please go wild adding assertions!

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: RFA v2: Various enhancements to the fixed-point support implementation
  2020-11-22 11:14   ` RFA v2: " Joel Brobecker
                       ` (5 preceding siblings ...)
  2020-11-22 11:14     ` [RFA v2 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by lambda Joel Brobecker
@ 2020-11-23 16:46     ` Simon Marchi
  2020-11-24  2:56       ` Joel Brobecker
  6 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-23 16:46 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

On 2020-11-22 6:14 a.m., Joel Brobecker wrote:
> Hello,
>
> This is v2 of the following patch series:
>
>   - [RFA v2 1/6] change and rename gmp_string_asprintf to return an
>   - [RFA v2 2/6] gmp-utils: Convert the read/write methods to using
>   - [RFA v2 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro
>   - [RFA v2 4/6] Make fixed_point_type_base_type a method of struct type
>   - [RFA v2 5/6] Make function fixed_point_scaling_factor a method of
>   - [RFA v2 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro
>
> The only changes I made were to patch #1 and patch #2, following
> the commends made by Simon and Pedro:
>
>   - [RFA v2 1/6] change and rename gmp_string_asprintf to return an
>
>         Rename the function to gmp_string_printf as recommended,
>         and use the suggestion to rely on gmp_vsnprintf to only
>         allocate the string buffer once.
>
>   - [RFA v2 2/6] gmp-utils: Convert the read/write methods to using
>
>         Improve the patch using either the form {ptr, len} to construct
>         the gdb_byte array, or else gdb::make_array_view.
>
> The other patches are just plain rebases.
>
> Each patch was individually tested on x86_64-linux, with no regression.
>
> There are still a number of comments which were made by Simon and
> Pedro (xfail for m2 and pascal, NEWS entries, selftest error
> using Ubuntu's GMP, etc), and I will address those next, in
> separate submissions.
>
> Note that I almost dropped patch #5 (turning fixed_point_scaling_factor
> from function to method), since Simon replied to the discussion
> about this topic that the the current form (a separate function) was fine.
> In particular, I tried to think about it in a possible future context
> where types are a tree of classes rather than one class with a type-code.
> In that situation, the fixed_point_scaling_factor method would logically
> be "attached" to the fixed point type class. This in turn means that
> ranges of fixed point types would not have this method, forcing users
> to have to call fixed_point_type_base_type first before they can query
> the fixed_point_scaling_factor method. In other words, because
> the functionality applies to two types where one is not the child of
> the other (in terms of class inheritance), a functioned did seem better.
>
> However, one could argue that the fixed_point_type_base_type method
> is in exactly the same boat: It applies to both range types and
> fixed point. So, in the name of being consistent, this patch series
> keeps them both. My thinking process is based on a hypothetical
> scenario, which I'm not even sure ever got discussed here anyways.
>
> That being said, now that I write my thoughts, for the case of
> fixed_point_type_base_type, if we did have a hierarchy of classes,
> I could perhaps see how all types would have a "base_type" method
> whose default implementation would simply return the type itself,
> and were range types would return the target type. In that scenario,
> the two methods are no longer in the same boat, and we can think
> of dropping the fixed_point_scaling_factor patch if we wanted to.
>
> I do not have a strong opinion and thus can easily drop any patch.
> The reason I kept the change in the end is that it just seemed
> more logical to act on what is today, rather than decide based on
> what the code might be tomorrow.

I also don't know how it would look if/when we convert this to a
hierarchy of classes, and I also prefer that we do what makes sense
today rather than act on speculations of what this could become.  We can
always change things later, it's not an API that we have to keep stable.

Following my changes, there are already methods in struct type that
apply to only some type codes, like bounds/set_gounds.  So I think it's
ok to make fixed_point_scaling_factor a method too, the same solution
will apply to all of them (deciding whether it's a virtual method only
implemented by some classes, or if it's a non-virtual method on some
specific classes).

In any case, I think the series looks good.  I let you decide if you
want to make fixed_point_scaling_factor a method or not, it doesn't
make a big difference in the end.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: pushed: Add support for DWARF-based fixed point types
  2020-11-23 16:12               ` Simon Marchi
@ 2020-11-24  2:39                 ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-24  2:39 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

> > I found the source of the problem, which was in a way subtle-enough
> > that you really have to pay attention to these details (which,
> > luckily, are handled automatically thanks to our minor C++-ification
> > of GMP in gmp-utils), and yet so obvious once you find it.
> > Attached is the patch that I will push later today (need to run RSN,
> > and don't want to make a mistake because I'm rushing).
> > 
> > I think this error might be highlighting a weakness, though. I need
> > to investigate more, but I'm thinking it might be wise to add some
> > checks during export that the buffer size is large enough to fit
> > the value. In other words, I'm thinking of having our own
> > safe_mpz_export which double-checks the size of the buffer according
> > to the formula given by the documentation, and raises an error if
> > too small.
> > 
> > The fact that GMP happily goes beyond the end of the buffer is
> > a bit unexpected, still. Maybe something to report to the GMP team.
> 
> Ah, nice!  The explanation in the commit message makes sense, thanks.

My pleasure. I was relieved to find that the main issue was in
the unittest itself! There's still the question of protecting
ourselves from this kind of issue, just in case, but at least
there we know what to be careful of.

I just pushed the patch to master, and will work on catching
those issues over the weekend.

gdb/ChangeLog:

        * unittests/gmp-utils-selftests.c (write_fp_test): Use mpq_set_si
        instead of mpq_set_ui to initialize our GMP rational.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: RFA v2: Various enhancements to the fixed-point support implementation
  2020-11-23 16:46     ` RFA v2: Various enhancements to the fixed-point support implementation Simon Marchi
@ 2020-11-24  2:56       ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-24  2:56 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

> In any case, I think the series looks good.  I let you decide if you
> want to make fixed_point_scaling_factor a method or not, it doesn't
> make a big difference in the end.

Thanks Simon. I pushed all 6 patches to master (including patch #5,
which I think brings better consistency).

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA] Add TYPE_CODE_FIXED_POINT handling in print_type_scalar
  2020-11-22 14:35           ` Simon Marchi
@ 2020-11-24  3:04             ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-24  3:04 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

> > gdb/ChangeLog:
> >
> >         * typeprint.c (print_type_scalar): Add handling of
> >         TYPE_CODE_FIXED_POINT.
> >
> > gdb/testsuite/ChangeLog:
> >
> >         * gdb.dwarf2/dw2-fixed-point.exp: Fix the expected output of
> >         the "ptype pck__fp1_range_var" test for the module-2 and pascal
> >         languages.  Remove the associated setup_xfail.
> >
> > The ptype output for range types in modula-2 and pascal is a little
> > odd (the type info is repeated twice around the ".." operator), but
> > I guess that's how they present range types in those languages.
> 
> Yeah, it seems like it.  Thanks for doing this, the change to handle
> fixed point in the generic print_type_scalar function looks good to me.

Thank you Simon. Patch pushed to master.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA/doco 1/4] gdb/NEWS: Document that building GDB now requires GMP
  2020-11-22 15:31       ` Eli Zaretskii
@ 2020-11-24  3:11         ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-24  3:11 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

> > From: Joel Brobecker <brobecker@adacore.com>
> > Date: Sun, 22 Nov 2020 15:56:27 +0400
> > Cc: Joel Brobecker <brobecker@adacore.com>
> > 
> > gdb/ChangeLog:
> > 
> >         * NEWS: Document that building GDB now requires GMP.
> 
> OK.

Thank you Eli. Pushed to master.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA/doco 3/4] gdb/README: Document the --with-libgmp-prefix configure option
  2020-11-22 15:32       ` Eli Zaretskii
@ 2020-11-24  3:11         ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-24  3:11 UTC (permalink / raw)
  To: gdb-patches

> > From: Joel Brobecker <brobecker@adacore.com>
> > Date: Sun, 22 Nov 2020 15:56:29 +0400
> > Cc: Joel Brobecker <brobecker@adacore.com>
> > 
> > gdb/ChangeLog:
> > 
> >         * README: Document the --with-libgmp-prefix configure option.
> 
> OK, thanks.

Thank you Eli. Pushed to master.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA/doco 4/4] gdb/README: Fix the URL of the MPFR website (now https).
  2020-11-22 15:33       ` Eli Zaretskii
@ 2020-11-24  3:11         ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-24  3:11 UTC (permalink / raw)
  To: gdb-patches

> > gdb/ChangeLog:
> > 
> >         * README: Fix the URL of the MPFR library.
> 
> OK.

Thank you Eli. Pushed to master.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA/doco 2/4] gdb/NEWS: Document that GDB now supports DWARF-based fixed point types
  2020-11-22 15:33       ` Eli Zaretskii
@ 2020-11-24  3:12         ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-24  3:12 UTC (permalink / raw)
  To: gdb-patches

> > gdb/ChangeLog:
> > 
> >         * NEWS: Add entry documenting support for DWARF-based fixed
> >         point types.
> 
> Thanks, this is OK.

Thank ou Eli. Pushed to master.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* RFA: wrap mpz_export into gdb_mpz::safe_export...
  2020-11-23  4:27             ` Joel Brobecker
  2020-11-23 16:12               ` Simon Marchi
@ 2020-11-29 15:45               ` Joel Brobecker
  2020-11-29 15:45                 ` [RFA 1/2] Fix TARGET_CHAR_BIT/HOST_CHAR_BIT confusion in gmp-utils.c Joel Brobecker
                                   ` (2 more replies)
  1 sibling, 3 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-29 15:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

Hello,

As discussed earlier this week when we discovered that we need to be
careful before calling mpz_export, the purpose of this patch series is
to introduce a new gdb_mpz method called safe_export that GDB can use
to make sure we don't have any buffer overrun. As it happens, you'll
see from patch #2 that I found a number of areas we could improve.

For the record, I didn't do the following, but I was thinking it would
be nice to poison mpz_export if we could.  We can do that as a followup
patch, if we'd like, although I will likely need a bit of help doing so,
because I am not sure how to poison it for the entire GDB except the one
place where it's OK to use it.  In the end, it sounds to me like Tom
wants to wrap GDB's usage of gmp into the gdb_mp[xxx] classes, and so,
once we have that, it seems unlikely that someone would unwittingly use
mpz_export directly.

Patch #1 is just something I noticed. Truth be told, I am kind of
second guessing myself on that one... Luckily, it's easy to just
drop it if it turns out I was wrong.

 * [RFA 1/2] Fix TARGET_CHAR_BIT/HOST_CHAR_BIT confusion in gmp-utils.c
 * [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range

The patches above were tested on x86_64-linux, with both the official
testsuite, as well as AdaCore's testsuite (just in case).

OK to push to master?

Thank you!
-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA 1/2] Fix TARGET_CHAR_BIT/HOST_CHAR_BIT confusion in gmp-utils.c
  2020-11-29 15:45               ` RFA: wrap mpz_export into gdb_mpz::safe_export Joel Brobecker
@ 2020-11-29 15:45                 ` Joel Brobecker
  2020-11-30 15:42                   ` Simon Marchi
  2020-11-29 15:45                 ` [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values Joel Brobecker
  2020-11-30 12:44                 ` RFA: wrap mpz_export into gdb_mpz::safe_export Christian Biesinger
  2 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-11-29 15:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

In a couple of gdb_mpz methods, we are computing the number of
bits in a gdb::array_view of gdb_byte. Since gdb_byte is defined
using a host-side type (see common-types.h), the number of bits
in a gdb_byte should be HOST_CHAR_BIT, not TARGET_CHAR_BIT.

gdb/ChangeLog:

        * gmp-utils.c (gdb_mpz::read): Use HOST_CHAR_BIT instead of
        TARGET_CHAR_BIT.
        (gdb_mpz::write): Likewise.
---
 gdb/gmp-utils.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index 7994108..e3a3333 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -56,7 +56,7 @@ gdb_mpz::read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
 	 was in fact negative, we need to adjust VAL accordingly.  */
       gdb_mpz max;
 
-      mpz_ui_pow_ui (max.val, 2, buf.size () * TARGET_CHAR_BIT - 1);
+      mpz_ui_pow_ui (max.val, 2, buf.size () * HOST_CHAR_BIT - 1);
       if (mpz_cmp (val, max.val) >= 0)
 	mpz_submul_ui (val, max.val, 2);
     }
@@ -77,7 +77,7 @@ gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
 	 would be the same as our negative value.  */
       gdb_mpz neg_offset;
 
-      mpz_ui_pow_ui (neg_offset.val, 2, buf.size () * TARGET_CHAR_BIT);
+      mpz_ui_pow_ui (neg_offset.val, 2, buf.size () * HOST_CHAR_BIT);
       mpz_add (exported_val.val, exported_val.val, neg_offset.val);
     }
 
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values
  2020-11-29 15:45               ` RFA: wrap mpz_export into gdb_mpz::safe_export Joel Brobecker
  2020-11-29 15:45                 ` [RFA 1/2] Fix TARGET_CHAR_BIT/HOST_CHAR_BIT confusion in gmp-utils.c Joel Brobecker
@ 2020-11-29 15:45                 ` Joel Brobecker
  2020-11-30 15:56                   ` Simon Marchi
  2020-12-05  8:10                   ` [RFAv2 " Joel Brobecker
  2020-11-30 12:44                 ` RFA: wrap mpz_export into gdb_mpz::safe_export Christian Biesinger
  2 siblings, 2 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-11-29 15:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

The gdb_mpz class currently provides a couple of methods which
essentially export an mpz_t value into either a buffer, or an integral
type. The export is based on using the mpz_export function which
we discovered can be a bit treacherous if used without caution.

In particular, the initial motivation for this patch was to catch
situations where the mpz_t value was so large that it would not fit
in the destination area. mpz_export does not know the size of
the buffer, and therefore can happily write past the end of our buffer.

While designing a solution to the above problem, I also discovered
that we also needed to be careful when exporting signed numbers.
In particular, numbers which are larger than the maximum value
for a given signed type size, but no so large as to fit in the
*unsigned* version with the same size, would end up being exported
incorrectly. This is related to the fact that mpz_export ignores
the sign of the value being exportd, and assumes an unsigned export.
Thus, for such large values, the appears as if mpz_export is able
to fit our value into our buffer, but in fact, it does not.

Also, I noticed that gdb_mpz::write wasn't taking its unsigned_p
parameter, which was a hole.

For all these reasons, a new low-level private method called
"safe_export" has been added to class gdb_mpz, whose goal is
to perform all necessary checks and manipulations for a safe
and correct export. As a bonus, this method allows us to factorize
the handling of negative value exports.

The gdb_mpz::as_integer and gdb_mpz::write methods are then simplified
to take advantage of this new safe_export method.

gdb/ChangeLog:

        * gmp-utils.h (gdb_mpz::safe_export): New private method.
        (gdb_mpz::as_integer): Reimplement using gdb_mpz::safe_export.
        * gmp-utils.c (gdb_mpz::write): Rewrite using gdb_mpz::safe_export.
        (gdb_mpz::safe_export): New method.
        * unittests/gmp-utils-selftests .c (gdb_mpz_as_integer):
        Update function description.
        (check_as_integer_raises_out_of_range_error): New function.
        (gdb_mpz_as_integer_out_of_range): New function.
        (_initialize_gmp_utils_selftests): Register
        gdb_mpz_as_integer_out_of_range as a selftest.
---
 gdb/gmp-utils.c                     | 79 ++++++++++++++++++++++++++++++++++---
 gdb/gmp-utils.h                     | 44 ++++++++++++---------
 gdb/unittests/gmp-utils-selftests.c | 71 +++++++++++++++++++++++++++++++--
 3 files changed, 167 insertions(+), 27 deletions(-)

diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index e3a3333..f94bdc5 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -68,9 +68,62 @@ void
 gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
 		bool unsigned_p) const
 {
+  this->safe_export
+    (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */, 0 /* nails */,
+     unsigned_p);
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
+		      int endian, size_t nails, bool unsigned_p) const
+{
+  gdb_assert (buf.size () > 0);
+
+  if (mpz_sgn (val) == 0)
+    {
+      /* Our value is zero, so no need to call mpz_export to do the work,
+	 especially since mpz_export's documentation explicitly says
+	 that the function is a noop in this case.  Just write zero to
+	 BUF ourselves.  */
+      memset (buf.data (), 0, buf.size ());
+      return;
+    }
+
+  /* Determine the maximum range of values that our buffer can hold,
+     and verify that VAL is within that range.  */
+
+  gdb_mpz lo, hi;
+  const size_t max_usable_bits = buf.size () * HOST_CHAR_BIT - nails;
+  if (unsigned_p)
+    {
+      lo = 0;
+
+      mpz_ui_pow_ui (hi.val, 2, max_usable_bits);
+      mpz_sub_ui (hi.val, hi.val, 1);
+    }
+  else
+    {
+      mpz_ui_pow_ui (lo.val, 2, max_usable_bits - 1);
+      mpz_neg (lo.val, lo.val);
+
+      mpz_ui_pow_ui (hi.val, 2, max_usable_bits - 1);
+      mpz_sub_ui (hi.val, hi.val, 1);
+    }
+
+  if (mpz_cmp (val, lo.val) < 0 || mpz_cmp (val, hi.val) > 0)
+    error (_("Cannot export value %s as %zubits %s integer"
+	     " (must be between %s and %s)"),
+	   this->str ().c_str (),
+	   max_usable_bits,
+	   unsigned_p ? _("unsigned") : _("signed"),
+	   lo.str ().c_str (),
+	   hi.str ().c_str ());
+
   gdb_mpz exported_val (val);
 
-  if (mpz_cmp_ui (val, 0) < 0)
+  if (mpz_cmp_ui (exported_val.val, 0) < 0)
     {
       /* mpz_export does not handle signed values, so create a positive
 	 value whose bit representation as an unsigned of the same length
@@ -81,13 +134,27 @@ gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
       mpz_add (exported_val.val, exported_val.val, neg_offset.val);
     }
 
+  /* Do the export into a buffer allocated by GMP itself; that way,
+     we can detect cases where BUF is not large enough to export
+     our value, and thus avoid a buffer overlow.  Normally, this should
+     never happen, since we verified earlier that the buffer is large
+     enough to accomodate our value, but doing this allows us to be
+     extra safe with the export.
+
+     After verification that the export behaved as expected, we will
+     copy the data over to BUF.  */
+
+  size_t word_countp;
+  gdb::unique_xmalloc_ptr<void> exported
+    (mpz_export (NULL, &word_countp, -1 /* order */, buf.size () /* size */,
+		 endian, nails, exported_val.val));
+
+  gdb_assert (word_countp == 1);
+
   /* Start by clearing the buffer, as mpz_export only writes as many
-     bytes as it needs (including none, if the value to export is zero.  */
+     bytes as it needs.  */
   memset (buf.data (), 0, buf.size ());
-  mpz_export (buf.data (), NULL /* count */, -1 /* order */,
-	      buf.size () /* size */,
-	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
-	      0 /* nails */, exported_val.val);
+  memcpy (buf.data (), exported.get (), buf.size ());
 }
 
 /* See gmp-utils.h.  */
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index 12e4f8e..c2e591c 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -121,6 +121,26 @@ struct gdb_mpz
 
   /* Helper template for constructor and operator=.  */
   template<typename T> void set (T src);
+
+  /* Low-level function to export VAL into BUF as a number whose byte size
+     is the size of BUF.
+
+     If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
+     Otherwise, export it as a signed value.
+
+     The API is inspired from GMP's mpz_export, hence the naming and types
+     of the following parameters:
+       - ENDIAN should be:
+           . 1 for most significant byte first; or
+	   . -1 for least significant byte first; or
+	   . 0 for native endianness.
+       - The most significant NAILS bits are unused and set to zero
+         (this can be 0 to use all bits).
+
+    An error is raised if BUF is not large enough to contain the value
+    being exported.  */
+  void safe_export (gdb::array_view<gdb_byte> buf,
+		    int endian, size_t nails, bool unsigned_p) const;
 };
 
 /* A class to make it easier to use GMP's mpq_t values within GDB.  */
@@ -258,26 +278,14 @@ template<typename T>
 T
 gdb_mpz::as_integer () const
 {
-  /* Initialize RESULT, because mpz_export only write the minimum
-     number of bytes, including none if our value is zero!  */
-  T result = 0;
+  T result;
 
-  gdb_mpz exported_val (val);
-  if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
-    {
-      /* We want to use mpz_export to set the return value, but
-	 this function does not handle the sign. So give exported_val
-	 a value which is at the same time positive, and has the same
-	 bit representation as our negative value.  */
-      gdb_mpz neg_offset;
+  this->safe_export (gdb::make_array_view ((gdb_byte *) &result,
+					   sizeof (result)),
+		     0 /* endian (0 = native) */,
+		     0 /* nails */,
+		     !std::is_signed<T>::value /* unsigned_p */);
 
-      mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
-      mpz_add (exported_val.val, exported_val.val, neg_offset.val);
-    }
-
-  mpz_export (&result, NULL /* count */, -1 /* order */,
-	      sizeof (T) /* size */, 0 /* endian (0 = native) */,
-	      0 /* nails */, exported_val.val);
   return result;
 }
 
diff --git a/gdb/unittests/gmp-utils-selftests.c b/gdb/unittests/gmp-utils-selftests.c
index 1365905..30c1902 100644
--- a/gdb/unittests/gmp-utils-selftests.c
+++ b/gdb/unittests/gmp-utils-selftests.c
@@ -26,9 +26,10 @@ namespace selftests {
 
 /* Perform a series of general tests of gdb_mpz's as_integer method.
 
-   This function tries to be reasonably exhaustive, by testing the edges,
-   as well as a resonable set of values including negative ones, zero,
-   and positive values.  */
+   This function limits itself to values which are in range (out-of-range
+   values will be tested separately).  In doing so, it tries to be reasonably
+   exhaustive, by testing the edges, as well as a resonable set of values
+   including negative ones, zero, and positive values.  */
 
 static void
 gdb_mpz_as_integer ()
@@ -80,6 +81,68 @@ gdb_mpz_as_integer ()
   SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
 }
 
+/* A helper function which calls the given gdb_mpz object's as_integer
+   method with the given type T, and verifies that this triggers
+   an error due to VAL's value being out of range for type T.  */
+
+template<typename T, typename = gdb::Requires<std::is_integral<T>>>
+static void
+check_as_integer_raises_out_of_range_error (const gdb_mpz &val)
+{
+  try
+    {
+      val.as_integer<T> ();
+    }
+  catch (const gdb_exception_error &ex)
+    {
+      SELF_CHECK (ex.reason == RETURN_ERROR);
+      SELF_CHECK (ex.error == GENERIC_ERROR);
+      SELF_CHECK (strstr (ex.what (), "Cannot export value") != nullptr);
+      return;
+    }
+  /* The expected exception did not get raised.  */
+  SELF_CHECK (false);
+}
+
+/* Perform out-of-range tests of gdb_mpz's as_integer method.
+
+   The goal of this function is to verify that gdb_mpz::as_integer
+   handles out-of-range values correctly.  */
+
+static void
+gdb_mpz_as_integer_out_of_range ()
+{
+  gdb_mpz v;
+
+  /* Try LONGEST_MIN minus 1.  */
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
+  mpz_neg (v.val, v.val);
+  mpz_sub_ui (v.val, v.val, 1);
+
+  check_as_integer_raises_out_of_range_error<ULONGEST> (v);
+  check_as_integer_raises_out_of_range_error<LONGEST> (v);
+
+  /* Try negative one (-1). */
+  v = -1;
+
+  check_as_integer_raises_out_of_range_error<ULONGEST> (v);
+  SELF_CHECK (v.as_integer<LONGEST> () == (LONGEST) -1);
+
+  /* Try LONGEST_MAX plus 1.  */
+  v = LONGEST_MAX;
+  mpz_add_ui (v.val, v.val, 1);
+
+  SELF_CHECK (v.as_integer<ULONGEST> () == (ULONGEST) LONGEST_MAX + 1);
+  check_as_integer_raises_out_of_range_error<LONGEST> (v);
+
+  /* Try ULONGEST_MAX plus 1.  */
+  v = ULONGEST_MAX;
+  mpz_add_ui (v.val, v.val, 1);
+
+  check_as_integer_raises_out_of_range_error<ULONGEST> (v);
+  check_as_integer_raises_out_of_range_error<LONGEST> (v);
+}
+
 /* A helper function to store the given integer value into a buffer,
    before reading it back into a gdb_mpz.  Sets ACTUAL to the value
    read back, while at the same time setting EXPECTED as the value
@@ -445,6 +508,8 @@ _initialize_gmp_utils_selftests ()
 {
   selftests::register_test ("gdb_mpz_as_integer",
 			    selftests::gdb_mpz_as_integer);
+  selftests::register_test ("gdb_mpz_as_integer_out_of_range",
+			    selftests::gdb_mpz_as_integer_out_of_range);
   selftests::register_test ("gdb_mpz_read_all_from_small",
 			    selftests::gdb_mpz_read_all_from_small);
   selftests::register_test ("gdb_mpz_read_min_max",
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: RFA: wrap mpz_export into gdb_mpz::safe_export...
  2020-11-29 15:45               ` RFA: wrap mpz_export into gdb_mpz::safe_export Joel Brobecker
  2020-11-29 15:45                 ` [RFA 1/2] Fix TARGET_CHAR_BIT/HOST_CHAR_BIT confusion in gmp-utils.c Joel Brobecker
  2020-11-29 15:45                 ` [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values Joel Brobecker
@ 2020-11-30 12:44                 ` Christian Biesinger
  2 siblings, 0 replies; 140+ messages in thread
From: Christian Biesinger @ 2020-11-30 12:44 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches, Simon Marchi

On Sun, Nov 29, 2020 at 4:46 PM Joel Brobecker <brobecker@adacore.com> wrote:
> For the record, I didn't do the following, but I was thinking it would
> be nice to poison mpz_export if we could.  We can do that as a followup
> patch, if we'd like, although I will likely need a bit of help doing so,
> because I am not sure how to poison it for the entire GDB except the one
> place where it's OK to use it.  In the end, it sounds to me like Tom
> wants to wrap GDB's usage of gmp into the gdb_mp[xxx] classes, and so,
> once we have that, it seems unlikely that someone would unwittingly use
> mpz_export directly.

Maybe #define mpz_export DO_NOT_USE and #undef it in the one spot?

Christian

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 1/2] Fix TARGET_CHAR_BIT/HOST_CHAR_BIT confusion in gmp-utils.c
  2020-11-29 15:45                 ` [RFA 1/2] Fix TARGET_CHAR_BIT/HOST_CHAR_BIT confusion in gmp-utils.c Joel Brobecker
@ 2020-11-30 15:42                   ` Simon Marchi
  2020-12-05  8:05                     ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-30 15:42 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches


On 2020-11-29 10:45 a.m., Joel Brobecker wrote:
> In a couple of gdb_mpz methods, we are computing the number of
> bits in a gdb::array_view of gdb_byte. Since gdb_byte is defined
> using a host-side type (see common-types.h), the number of bits
> in a gdb_byte should be HOST_CHAR_BIT, not TARGET_CHAR_BIT.

Right, and we are not supposed to use TARGET_CHAR_BIT anymore.  The same
GDB could be debugging targets with different target char bit values, so
a build-time constant like TARGET_CHAR_BIT can't work.  For those cases,
gdbarch_addressable_memory_unit_size should be used instead.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values
  2020-11-29 15:45                 ` [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values Joel Brobecker
@ 2020-11-30 15:56                   ` Simon Marchi
  2020-12-01  3:37                     ` Joel Brobecker
  2020-12-05  8:10                   ` [RFAv2 " Joel Brobecker
  1 sibling, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-11-30 15:56 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

On 2020-11-29 10:45 a.m., Joel Brobecker wrote:
> The gdb_mpz class currently provides a couple of methods which
> essentially export an mpz_t value into either a buffer, or an integral
> type. The export is based on using the mpz_export function which
> we discovered can be a bit treacherous if used without caution.
>
> In particular, the initial motivation for this patch was to catch
> situations where the mpz_t value was so large that it would not fit
> in the destination area. mpz_export does not know the size of
> the buffer, and therefore can happily write past the end of our buffer.
>
> While designing a solution to the above problem, I also discovered
> that we also needed to be careful when exporting signed numbers.
> In particular, numbers which are larger than the maximum value
> for a given signed type size, but no so large as to fit in the
> *unsigned* version with the same size, would end up being exported
> incorrectly. This is related to the fact that mpz_export ignores
> the sign of the value being exportd, and assumes an unsigned export.
> Thus, for such large values, the appears as if mpz_export is able
> to fit our value into our buffer, but in fact, it does not.
>
> Also, I noticed that gdb_mpz::write wasn't taking its unsigned_p
> parameter, which was a hole.
>
> For all these reasons, a new low-level private method called
> "safe_export" has been added to class gdb_mpz, whose goal is
> to perform all necessary checks and manipulations for a safe
> and correct export. As a bonus, this method allows us to factorize
> the handling of negative value exports.
>
> The gdb_mpz::as_integer and gdb_mpz::write methods are then simplified
> to take advantage of this new safe_export method.
>
> gdb/ChangeLog:
>
>         * gmp-utils.h (gdb_mpz::safe_export): New private method.
>         (gdb_mpz::as_integer): Reimplement using gdb_mpz::safe_export.
>         * gmp-utils.c (gdb_mpz::write): Rewrite using gdb_mpz::safe_export.
>         (gdb_mpz::safe_export): New method.
>         * unittests/gmp-utils-selftests .c (gdb_mpz_as_integer):
>         Update function description.
>         (check_as_integer_raises_out_of_range_error): New function.
>         (gdb_mpz_as_integer_out_of_range): New function.
>         (_initialize_gmp_utils_selftests): Register
>         gdb_mpz_as_integer_out_of_range as a selftest.
> ---
>  gdb/gmp-utils.c                     | 79 ++++++++++++++++++++++++++++++++++---
>  gdb/gmp-utils.h                     | 44 ++++++++++++---------
>  gdb/unittests/gmp-utils-selftests.c | 71 +++++++++++++++++++++++++++++++--
>  3 files changed, 167 insertions(+), 27 deletions(-)
>
> diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
> index e3a3333..f94bdc5 100644
> --- a/gdb/gmp-utils.c
> +++ b/gdb/gmp-utils.c
> @@ -68,9 +68,62 @@ void
>  gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
>  		bool unsigned_p) const
>  {
> +  this->safe_export
> +    (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */, 0 /* nails */,
> +     unsigned_p);
> +}
> +
> +/* See gmp-utils.h.  */
> +
> +void
> +gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
> +		      int endian, size_t nails, bool unsigned_p) const

Just wondering if you'll ever need to pass a non-zero value for nails.
If not, I think you could simplify the code by just removing it.

> +{
> +  gdb_assert (buf.size () > 0);
> +
> +  if (mpz_sgn (val) == 0)
> +    {
> +      /* Our value is zero, so no need to call mpz_export to do the work,
> +	 especially since mpz_export's documentation explicitly says
> +	 that the function is a noop in this case.  Just write zero to
> +	 BUF ourselves.  */
> +      memset (buf.data (), 0, buf.size ());
> +      return;
> +    }
> +
> +  /* Determine the maximum range of values that our buffer can hold,
> +     and verify that VAL is within that range.  */
> +
> +  gdb_mpz lo, hi;
> +  const size_t max_usable_bits = buf.size () * HOST_CHAR_BIT - nails;
> +  if (unsigned_p)
> +    {
> +      lo = 0;
> +
> +      mpz_ui_pow_ui (hi.val, 2, max_usable_bits);
> +      mpz_sub_ui (hi.val, hi.val, 1);
> +    }
> +  else
> +    {
> +      mpz_ui_pow_ui (lo.val, 2, max_usable_bits - 1);
> +      mpz_neg (lo.val, lo.val);
> +
> +      mpz_ui_pow_ui (hi.val, 2, max_usable_bits - 1);
> +      mpz_sub_ui (hi.val, hi.val, 1);
> +    }
> +
> +  if (mpz_cmp (val, lo.val) < 0 || mpz_cmp (val, hi.val) > 0)
> +    error (_("Cannot export value %s as %zubits %s integer"
> +	     " (must be between %s and %s)"),

You might be missing a space before "bits", or maybe it's on purpose.

> +	   this->str ().c_str (),
> +	   max_usable_bits,
> +	   unsigned_p ? _("unsigned") : _("signed"),
> +	   lo.str ().c_str (),
> +	   hi.str ().c_str ());
> +
>    gdb_mpz exported_val (val);
>
> -  if (mpz_cmp_ui (val, 0) < 0)
> +  if (mpz_cmp_ui (exported_val.val, 0) < 0)
>      {
>        /* mpz_export does not handle signed values, so create a positive
>  	 value whose bit representation as an unsigned of the same length
> @@ -81,13 +134,27 @@ gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
>        mpz_add (exported_val.val, exported_val.val, neg_offset.val);
>      }
>
> +  /* Do the export into a buffer allocated by GMP itself; that way,
> +     we can detect cases where BUF is not large enough to export
> +     our value, and thus avoid a buffer overlow.  Normally, this should
> +     never happen, since we verified earlier that the buffer is large
> +     enough to accomodate our value, but doing this allows us to be
> +     extra safe with the export.
> +
> +     After verification that the export behaved as expected, we will
> +     copy the data over to BUF.  */
> +
> +  size_t word_countp;
> +  gdb::unique_xmalloc_ptr<void> exported

I'd prefer if we didn't use heap allocation unnecessarily.  If we get
things right, that isn't necessary.  And if we can still assert after
the call that we did indeed get it right, then we'll catch any case
where we didn't.

> +    (mpz_export (NULL, &word_countp, -1 /* order */, buf.size () /* size */,
> +		 endian, nails, exported_val.val));
> +
> +  gdb_assert (word_countp == 1);
> +
>    /* Start by clearing the buffer, as mpz_export only writes as many
> -     bytes as it needs (including none, if the value to export is zero.  */
> +     bytes as it needs.  */
>    memset (buf.data (), 0, buf.size ());
> -  mpz_export (buf.data (), NULL /* count */, -1 /* order */,
> -	      buf.size () /* size */,
> -	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
> -	      0 /* nails */, exported_val.val);
> +  memcpy (buf.data (), exported.get (), buf.size ());

The memset just before the memcpy of the same size is useless, as all
the bytes will get overwritten by the memcpy.

> @@ -258,26 +278,14 @@ template<typename T>
>  T
>  gdb_mpz::as_integer () const
>  {
> -  /* Initialize RESULT, because mpz_export only write the minimum
> -     number of bytes, including none if our value is zero!  */
> -  T result = 0;
> +  T result;
>
> -  gdb_mpz exported_val (val);
> -  if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
> -    {
> -      /* We want to use mpz_export to set the return value, but
> -	 this function does not handle the sign. So give exported_val
> -	 a value which is at the same time positive, and has the same
> -	 bit representation as our negative value.  */
> -      gdb_mpz neg_offset;
> +  this->safe_export (gdb::make_array_view ((gdb_byte *) &result,
> +					   sizeof (result)),

I'd suggest using

  {(gdb_byte *) &result, sizeof (result)}

to make the array view, as suggested by Pedro earlier.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values
  2020-11-30 15:56                   ` Simon Marchi
@ 2020-12-01  3:37                     ` Joel Brobecker
  2020-12-01  4:02                       ` Simon Marchi
  0 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-12-01  3:37 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

Hi Simon,

Thanks for the review! My preliminary answers below..

> > +void
> > +gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
> > +		      int endian, size_t nails, bool unsigned_p) const
> 
> Just wondering if you'll ever need to pass a non-zero value for nails.
> If not, I think you could simplify the code by just removing it.

I don't know for sure. What about a scenario where we want to export
to a variable which is held in an area that's not a multiple number
of bytes?

The code isn't dramatically complexified because of it, so perhaps
just keep it by default, and remove it later, if we find that
we never used it?

> > +{
> > +  gdb_assert (buf.size () > 0);
> > +
> > +  if (mpz_sgn (val) == 0)
> > +    {
> > +      /* Our value is zero, so no need to call mpz_export to do the work,
> > +	 especially since mpz_export's documentation explicitly says
> > +	 that the function is a noop in this case.  Just write zero to
> > +	 BUF ourselves.  */
> > +      memset (buf.data (), 0, buf.size ());
> > +      return;
> > +    }
> > +
> > +  /* Determine the maximum range of values that our buffer can hold,
> > +     and verify that VAL is within that range.  */
> > +
> > +  gdb_mpz lo, hi;
> > +  const size_t max_usable_bits = buf.size () * HOST_CHAR_BIT - nails;
> > +  if (unsigned_p)
> > +    {
> > +      lo = 0;
> > +
> > +      mpz_ui_pow_ui (hi.val, 2, max_usable_bits);
> > +      mpz_sub_ui (hi.val, hi.val, 1);
> > +    }
> > +  else
> > +    {
> > +      mpz_ui_pow_ui (lo.val, 2, max_usable_bits - 1);
> > +      mpz_neg (lo.val, lo.val);
> > +
> > +      mpz_ui_pow_ui (hi.val, 2, max_usable_bits - 1);
> > +      mpz_sub_ui (hi.val, hi.val, 1);
> > +    }
> > +
> > +  if (mpz_cmp (val, lo.val) < 0 || mpz_cmp (val, hi.val) > 0)
> > +    error (_("Cannot export value %s as %zubits %s integer"
> > +	     " (must be between %s and %s)"),
> 
> You might be missing a space before "bits", or maybe it's on purpose.

It was on purpose, as I tend to write "32bit object" or "64bit object".
But if there is a standard way to write these things. A quick google
search indeed seems to indicate that there is large preference for
having a dash (as in "32-bit computing").

So, if people agree, I will change the above to add a dash.

> 
> > +	   this->str ().c_str (),
> > +	   max_usable_bits,
> > +	   unsigned_p ? _("unsigned") : _("signed"),
> > +	   lo.str ().c_str (),
> > +	   hi.str ().c_str ());
> > +
> >    gdb_mpz exported_val (val);
> >
> > -  if (mpz_cmp_ui (val, 0) < 0)
> > +  if (mpz_cmp_ui (exported_val.val, 0) < 0)
> >      {
> >        /* mpz_export does not handle signed values, so create a positive
> >  	 value whose bit representation as an unsigned of the same length
> > @@ -81,13 +134,27 @@ gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
> >        mpz_add (exported_val.val, exported_val.val, neg_offset.val);
> >      }
> >
> > +  /* Do the export into a buffer allocated by GMP itself; that way,
> > +     we can detect cases where BUF is not large enough to export
> > +     our value, and thus avoid a buffer overlow.  Normally, this should
> > +     never happen, since we verified earlier that the buffer is large
> > +     enough to accomodate our value, but doing this allows us to be
> > +     extra safe with the export.
> > +
> > +     After verification that the export behaved as expected, we will
> > +     copy the data over to BUF.  */
> > +
> > +  size_t word_countp;
> > +  gdb::unique_xmalloc_ptr<void> exported
> 
> I'd prefer if we didn't use heap allocation unnecessarily.  If we get
> things right, that isn't necessary.  And if we can still assert after
> the call that we did indeed get it right, then we'll catch any case
> where we didn't.

The problem with what you suggest is that, if we didn't do things right,
by the time we realize it, we'll have already gone through a buffer
overflow, with the associated random and uncontrolled damage. On Ubuntu,
we already know that the overflow causes an abort, so we wouldn't even
get to the point where we'd double-check. For me, this risk is bad enough
that it's well worth this (small) extra allocation.  I don't think
this function is going to be called very frequently.

> > +    (mpz_export (NULL, &word_countp, -1 /* order */, buf.size () /* size */,
> > +		 endian, nails, exported_val.val));
> > +
> > +  gdb_assert (word_countp == 1);
> > +
> >    /* Start by clearing the buffer, as mpz_export only writes as many
> > -     bytes as it needs (including none, if the value to export is zero.  */
> > +     bytes as it needs.  */
> >    memset (buf.data (), 0, buf.size ());
> > -  mpz_export (buf.data (), NULL /* count */, -1 /* order */,
> > -	      buf.size () /* size */,
> > -	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
> > -	      0 /* nails */, exported_val.val);
> > +  memcpy (buf.data (), exported.get (), buf.size ());
> 
> The memset just before the memcpy of the same size is useless, as all
> the bytes will get overwritten by the memcpy.

Indeed. The above comes from my belief that mpz_export only writes
the necessary number of *bytes*, but re-reading the documentation,
I belive it's the necessary number of *words*. I don't know how things
could possibly be working in the case where mpz_export does the memory
allocation otherwise.

Thanks for catching that. I'll remove the extra memset.

> > @@ -258,26 +278,14 @@ template<typename T>
> >  T
> >  gdb_mpz::as_integer () const
> >  {
> > -  /* Initialize RESULT, because mpz_export only write the minimum
> > -     number of bytes, including none if our value is zero!  */
> > -  T result = 0;
> > +  T result;
> >
> > -  gdb_mpz exported_val (val);
> > -  if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
> > -    {
> > -      /* We want to use mpz_export to set the return value, but
> > -	 this function does not handle the sign. So give exported_val
> > -	 a value which is at the same time positive, and has the same
> > -	 bit representation as our negative value.  */
> > -      gdb_mpz neg_offset;
> > +  this->safe_export (gdb::make_array_view ((gdb_byte *) &result,
> > +					   sizeof (result)),
> 
> I'd suggest using
> 
>   {(gdb_byte *) &result, sizeof (result)}
> 
> to make the array view, as suggested by Pedro earlier.

I thought I had tried that and got an error, but I will try again.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values
  2020-12-01  3:37                     ` Joel Brobecker
@ 2020-12-01  4:02                       ` Simon Marchi
  2020-12-01  7:11                         ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-12-01  4:02 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On 2020-11-30 10:37 p.m., Joel Brobecker wrote:
> Hi Simon,
>
> Thanks for the review! My preliminary answers below..
>
>>> +void
>>> +gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
>>> +		      int endian, size_t nails, bool unsigned_p) const
>>
>> Just wondering if you'll ever need to pass a non-zero value for nails.
>> If not, I think you could simplify the code by just removing it.
>
> I don't know for sure. What about a scenario where we want to export
> to a variable which is held in an area that's not a multiple number
> of bytes?
>
> The code isn't dramatically complexified because of it, so perhaps
> just keep it by default, and remove it later, if we find that
> we never used it?

Well, I find it more logical to do the other way around, add the
complexity when you need it.  Because I'm pretty sure you won't go set
an alarm clock for one year from now, to remember to come back and check
whether or not we are using that feature :).  Also, I'm usually not keen
on checking in things that aren't used, because we don't even know if
they work / do what they are intended to do.

If you know things are coming that are going to use it, I'm fine with
leaving it in, but otherwise I just don't see the point.  I'll let you
decide.

>>> +{
>>> +  gdb_assert (buf.size () > 0);
>>> +
>>> +  if (mpz_sgn (val) == 0)
>>> +    {
>>> +      /* Our value is zero, so no need to call mpz_export to do the work,
>>> +	 especially since mpz_export's documentation explicitly says
>>> +	 that the function is a noop in this case.  Just write zero to
>>> +	 BUF ourselves.  */
>>> +      memset (buf.data (), 0, buf.size ());
>>> +      return;
>>> +    }
>>> +
>>> +  /* Determine the maximum range of values that our buffer can hold,
>>> +     and verify that VAL is within that range.  */
>>> +
>>> +  gdb_mpz lo, hi;
>>> +  const size_t max_usable_bits = buf.size () * HOST_CHAR_BIT - nails;
>>> +  if (unsigned_p)
>>> +    {
>>> +      lo = 0;
>>> +
>>> +      mpz_ui_pow_ui (hi.val, 2, max_usable_bits);
>>> +      mpz_sub_ui (hi.val, hi.val, 1);
>>> +    }
>>> +  else
>>> +    {
>>> +      mpz_ui_pow_ui (lo.val, 2, max_usable_bits - 1);
>>> +      mpz_neg (lo.val, lo.val);
>>> +
>>> +      mpz_ui_pow_ui (hi.val, 2, max_usable_bits - 1);
>>> +      mpz_sub_ui (hi.val, hi.val, 1);
>>> +    }
>>> +
>>> +  if (mpz_cmp (val, lo.val) < 0 || mpz_cmp (val, hi.val) > 0)
>>> +    error (_("Cannot export value %s as %zubits %s integer"
>>> +	     " (must be between %s and %s)"),
>>
>> You might be missing a space before "bits", or maybe it's on purpose.
>
> It was on purpose, as I tend to write "32bit object" or "64bit object".
> But if there is a standard way to write these things. A quick google
> search indeed seems to indicate that there is large preference for
> having a dash (as in "32-bit computing").
>
> So, if people agree, I will change the above to add a dash.

I googled a bit and it turns out that this is a kind of compound
adjective, which requires a hyphen:

  https://www.gingersoftware.com/content/grammar-rules/adjectives/compound-adjectives/

Also, the name (bit) should be singular.  So I think we should
standardize on "%zu-bit".

>
>>
>>> +	   this->str ().c_str (),
>>> +	   max_usable_bits,
>>> +	   unsigned_p ? _("unsigned") : _("signed"),
>>> +	   lo.str ().c_str (),
>>> +	   hi.str ().c_str ());
>>> +
>>>    gdb_mpz exported_val (val);
>>>
>>> -  if (mpz_cmp_ui (val, 0) < 0)
>>> +  if (mpz_cmp_ui (exported_val.val, 0) < 0)
>>>      {
>>>        /* mpz_export does not handle signed values, so create a positive
>>>  	 value whose bit representation as an unsigned of the same length
>>> @@ -81,13 +134,27 @@ gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
>>>        mpz_add (exported_val.val, exported_val.val, neg_offset.val);
>>>      }
>>>
>>> +  /* Do the export into a buffer allocated by GMP itself; that way,
>>> +     we can detect cases where BUF is not large enough to export
>>> +     our value, and thus avoid a buffer overlow.  Normally, this should
>>> +     never happen, since we verified earlier that the buffer is large
>>> +     enough to accomodate our value, but doing this allows us to be
>>> +     extra safe with the export.
>>> +
>>> +     After verification that the export behaved as expected, we will
>>> +     copy the data over to BUF.  */
>>> +
>>> +  size_t word_countp;
>>> +  gdb::unique_xmalloc_ptr<void> exported
>>
>> I'd prefer if we didn't use heap allocation unnecessarily.  If we get
>> things right, that isn't necessary.  And if we can still assert after
>> the call that we did indeed get it right, then we'll catch any case
>> where we didn't.
>
> The problem with what you suggest is that, if we didn't do things right,
> by the time we realize it, we'll have already gone through a buffer
> overflow, with the associated random and uncontrolled damage. On Ubuntu,
> we already know that the overflow causes an abort, so we wouldn't even
> get to the point where we'd double-check. For me, this risk is bad enough
> that it's well worth this (small) extra allocation.  I don't think
> this function is going to be called very frequently.

The way I see it is that if we check after the fact, it would be a
gdb_assert.  So if we get it wrong, it results in either in a crash or a
failed assertion.  Both equally result in a bug report.

But you're right, using the heap allocation makes it so we can't get it
wrong, so that's an advantage.  I just thought that we'd get it right
for good now :).

>>> @@ -258,26 +278,14 @@ template<typename T>
>>>  T
>>>  gdb_mpz::as_integer () const
>>>  {
>>> -  /* Initialize RESULT, because mpz_export only write the minimum
>>> -     number of bytes, including none if our value is zero!  */
>>> -  T result = 0;
>>> +  T result;
>>>
>>> -  gdb_mpz exported_val (val);
>>> -  if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
>>> -    {
>>> -      /* We want to use mpz_export to set the return value, but
>>> -	 this function does not handle the sign. So give exported_val
>>> -	 a value which is at the same time positive, and has the same
>>> -	 bit representation as our negative value.  */
>>> -      gdb_mpz neg_offset;
>>> +  this->safe_export (gdb::make_array_view ((gdb_byte *) &result,
>>> +					   sizeof (result)),
>>
>> I'd suggest using
>>
>>   {(gdb_byte *) &result, sizeof (result)}
>>
>> to make the array view, as suggested by Pedro earlier.
>
> I thought I had tried that and got an error, but I will try again.

I tried it before making that suggestion and it worked, so if you have
troubles let me know.

Simon


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values
  2020-12-01  4:02                       ` Simon Marchi
@ 2020-12-01  7:11                         ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-12-01  7:11 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

> >>> +void
> >>> +gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
> >>> +		      int endian, size_t nails, bool unsigned_p) const
> >>
> >> Just wondering if you'll ever need to pass a non-zero value for nails.
> >> If not, I think you could simplify the code by just removing it.
> >
> > I don't know for sure. What about a scenario where we want to export
> > to a variable which is held in an area that's not a multiple number
> > of bytes?
> >
> > The code isn't dramatically complexified because of it, so perhaps
> > just keep it by default, and remove it later, if we find that
> > we never used it?
> 
> Well, I find it more logical to do the other way around, add the
> complexity when you need it.  Because I'm pretty sure you won't go set
> an alarm clock for one year from now, to remember to come back and check
> whether or not we are using that feature :).  Also, I'm usually not keen
> on checking in things that aren't used, because we don't even know if
> they work / do what they are intended to do.
> 
> If you know things are coming that are going to use it, I'm fine with
> leaving it in, but otherwise I just don't see the point.  I'll let you
> decide.

That's no problem. I will remove it.

> Also, the name (bit) should be singular.  So I think we should
> standardize on "%zu-bit".

Agreed.

> >>> +  /* Do the export into a buffer allocated by GMP itself; that way,
> >>> +     we can detect cases where BUF is not large enough to export
> >>> +     our value, and thus avoid a buffer overlow.  Normally, this should
> >>> +     never happen, since we verified earlier that the buffer is large
> >>> +     enough to accomodate our value, but doing this allows us to be
> >>> +     extra safe with the export.
> >>> +
> >>> +     After verification that the export behaved as expected, we will
> >>> +     copy the data over to BUF.  */
> >>> +
> >>> +  size_t word_countp;
> >>> +  gdb::unique_xmalloc_ptr<void> exported
> >>
> >> I'd prefer if we didn't use heap allocation unnecessarily.  If we get
> >> things right, that isn't necessary.  And if we can still assert after
> >> the call that we did indeed get it right, then we'll catch any case
> >> where we didn't.
> >
> > The problem with what you suggest is that, if we didn't do things right,
> > by the time we realize it, we'll have already gone through a buffer
> > overflow, with the associated random and uncontrolled damage. On Ubuntu,
> > we already know that the overflow causes an abort, so we wouldn't even
> > get to the point where we'd double-check. For me, this risk is bad enough
> > that it's well worth this (small) extra allocation.  I don't think
> > this function is going to be called very frequently.
> 
> The way I see it is that if we check after the fact, it would be a
> gdb_assert.  So if we get it wrong, it results in either in a crash or a
> failed assertion.  Both equally result in a bug report.
> 
> But you're right, using the heap allocation makes it so we can't get it
> wrong, so that's an advantage.  I just thought that we'd get it right
> for good now :).

Me too. If GMP had a routine that gave us that information prior to
calling mpz_export, we could use it and verify that we can confidently
call mpz_export without risking a buffer overflow. Right now, we have
a formula provided by the manual, but but given in a way that does not
instill great confidence ("a calculation like the following"). I'm also
concerned with future versions changing the formula and us not noticing.

> >>> @@ -258,26 +278,14 @@ template<typename T>
> >>>  T
> >>>  gdb_mpz::as_integer () const
> >>>  {
> >>> -  /* Initialize RESULT, because mpz_export only write the minimum
> >>> -     number of bytes, including none if our value is zero!  */
> >>> -  T result = 0;
> >>> +  T result;
> >>>
> >>> -  gdb_mpz exported_val (val);
> >>> -  if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
> >>> -    {
> >>> -      /* We want to use mpz_export to set the return value, but
> >>> -	 this function does not handle the sign. So give exported_val
> >>> -	 a value which is at the same time positive, and has the same
> >>> -	 bit representation as our negative value.  */
> >>> -      gdb_mpz neg_offset;
> >>> +  this->safe_export (gdb::make_array_view ((gdb_byte *) &result,
> >>> +					   sizeof (result)),
> >>
> >> I'd suggest using
> >>
> >>   {(gdb_byte *) &result, sizeof (result)}
> >>
> >> to make the array view, as suggested by Pedro earlier.
> >
> > I thought I had tried that and got an error, but I will try again.
> 
> I tried it before making that suggestion and it worked, so if you have
> troubles let me know.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH] Enable GDB build with in-tree GMP and MPFR
  2020-11-18  8:14               ` Bernd Edlinger
@ 2020-12-01 19:29                 ` Bernd Edlinger
  2020-12-01 19:32                   ` Simon Marchi
  0 siblings, 1 reply; 140+ messages in thread
From: Bernd Edlinger @ 2020-12-01 19:29 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Simon Marchi, gdb-patches

On 11/18/20 9:14 AM, Bernd Edlinger wrote:
> On 11/18/20 4:44 AM, Joel Brobecker wrote:
>>> this enables GDB build with in-tree GMP and MPFR.
>>>
>>> This updated version of my patch added support for in-tree MPFR.
>>>
>>> While there is no preexisting --with-gmp configure option in gdb,
>>> this leaves the current --with-mpfr=yes/no/auto as it is, since it seems
>>> to work by accident.  The top level config script thinks "no" is
>>> a DIR, and skips the detection of in-tree MPFR in that case, while
>>> gdb honors --with-mpfr=no, so that is what's expected.
>>>
>>> The in-tree build works only when no --with-mpfr and no
>>> --with-gmp is given.  While it does not advertise --with-gmp-prefix=DIR
>>> and/or --with-mpfr-prefix=DIR with "./configure --help", I'll leave that
>>> for another patch.
>>
>> I think we better sort the discrepancy between GCC and GDB
>> if we can, but this is going to take time. From what you were
>> explaining before, I believe you can separate this part of
>> your patch (adding the above to GDB's configury) from the part
>> where you're adding support for in-tree building?
>>
> 
> 
> 99% of the top-level configury is already there, but it needs
> still a dependency between gdb and (in-tree) gmp / mpfr,
> and pass the options where to find gmp and mpfr to gdb,
> I don't know how to actually resolve the differences ATM.
> If the top-level configure script advertises GDB-style options
> It will at least have to translate them for in-tree MPFR,
> MPC, and ISL.
> 
> I believe this change is just the bare minimum and will not
> cause additional incompatibilities with GCC.
> 
> 
>>> Tested on x86_64-pc-linux-gnu and cross-build for arm.
>>> Is it OK for the trunk?
>>
>> These are changes in areas I am not familiar with, and wouldn't
>> have very much time to look into. I talked to Tom yesterday,
>> and he kindly agreed to take a look.
>>
>>> From 503435680f463cf5ed060ce32b902051cb19e801 Mon Sep 17 00:00:00 2001
>>> From: Bernd Edlinger <bernd.edlinger@hotmail.de>
>>> Date: Sun, 15 Nov 2020 15:37:22 +0100
>>> Subject: [PATCH] Enable GDB build with in-tree GMP and MPFR
>>>
>>> With this patch GDB can be built with in-tree GMP and/or
>>> MPFR.  This works also for cross-builds.
>>>
>>> All that is needed, is a sym-link in the source tree,
>>> like this:
>>>
>>> gmp -> ../gmp-6.1.0
>>> mpfr -> ../mpfr-3.1.4
>>>
>>> 2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>
>>>
>>> 	* Makefile.def: Prepare for GDB build with intree GMP.
>>> 	* Makefile.in: Regenerate.
>>
>> I got the answer about approval for toplevel tree changes; we're still
>> keeping in sync with GCC. However, Tom said that these kinds of changes
>> are OK to discuss and eventually push locally, before we bring them
>> to GCC next. It's better the other way around, but discussing them
>> here is also an option, because it's a minor change taking advantage
>> of infrastructure that's already in place.
>>
>> In this particular instance, I would indeed _not_ rush discussing
>> with GCC, in case the tie with GDB affects the changes we would need
>> in toplevel.
>>
> 
> Yep, agreed.
> 

So, can this patch be applied ?

I would really like to be able to build gdb with in-tree gmp / mpfr,
just as it works for gcc.


Thanks
Bernd.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH] Enable GDB build with in-tree GMP and MPFR
  2020-12-01 19:29                 ` Bernd Edlinger
@ 2020-12-01 19:32                   ` Simon Marchi
  2020-12-01 19:38                     ` Bernd Edlinger
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-12-01 19:32 UTC (permalink / raw)
  To: Bernd Edlinger, Joel Brobecker; +Cc: gdb-patches


On 2020-12-01 2:29 p.m., Bernd Edlinger wrote:
> I would really like to be able to build gdb with in-tree gmp / mpfr,
> just as it works for gcc.

Pardon my ignorance, but I don't see the gmp nor the mpfr source code in
the binutils-gdb repository.  Should it be checked in too?

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH] Enable GDB build with in-tree GMP and MPFR
  2020-12-01 19:32                   ` Simon Marchi
@ 2020-12-01 19:38                     ` Bernd Edlinger
  2020-12-01 20:29                       ` Bernd Edlinger
  0 siblings, 1 reply; 140+ messages in thread
From: Bernd Edlinger @ 2020-12-01 19:38 UTC (permalink / raw)
  To: Simon Marchi, Joel Brobecker; +Cc: gdb-patches

On 12/1/20 8:32 PM, Simon Marchi wrote:
> 
> On 2020-12-01 2:29 p.m., Bernd Edlinger wrote:
>> I would really like to be able to build gdb with in-tree gmp / mpfr,
>> just as it works for gcc.
> 
> Pardon my ignorance, but I don't see the gmp nor the mpfr source code in
> the binutils-gdb repository.  Should it be checked in too?
> 


Aehm, good question.
gcc uses a script ./contrib/download_prerequisites
that *can* be used to download gmp/mpfr and some more.

Maybe I should add a stripped down version of that one?


Bernd.




^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH] Enable GDB build with in-tree GMP and MPFR
  2020-12-01 19:38                     ` Bernd Edlinger
@ 2020-12-01 20:29                       ` Bernd Edlinger
  2020-12-01 20:30                         ` Simon Marchi
  2020-12-14 17:40                         ` [PATCH v2] " Bernd Edlinger
  0 siblings, 2 replies; 140+ messages in thread
From: Bernd Edlinger @ 2020-12-01 20:29 UTC (permalink / raw)
  To: Simon Marchi, Joel Brobecker; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 829 bytes --]

Hi Simon,

On 12/1/20 8:38 PM, Bernd Edlinger wrote:
> On 12/1/20 8:32 PM, Simon Marchi wrote:
>>
>> On 2020-12-01 2:29 p.m., Bernd Edlinger wrote:
>>> I would really like to be able to build gdb with in-tree gmp / mpfr,
>>> just as it works for gcc.
>>
>> Pardon my ignorance, but I don't see the gmp nor the mpfr source code in
>> the binutils-gdb repository.  Should it be checked in too?
>>
> 
> 
> Aehm, good question.
> gcc uses a script ./contrib/download_prerequisites
> that *can* be used to download gmp/mpfr and some more.
> 
> Maybe I should add a stripped down version of that one?
> 

So, this adds the contrib/download_prerequisites script.

It is taken from gcc but does not download mpc and isl,
just gmp and mpfr.

It should work also when building gdb from the release tar.


Is it OK to push?


Thanks
Bernd.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR.patch --]
[-- Type: text/x-patch; name="0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR.patch", Size: 16414 bytes --]

From 41fdfbe1633009d2395b4714a6b3bfabb74691ef Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Sun, 15 Nov 2020 15:37:22 +0100
Subject: [PATCH] Enable GDB build with in-tree GMP and MPFR

With this patch GDB can be built with in-tree GMP and/or
MPFR.  This works also for cross-builds.

All that is needed, is a sym-link in the source tree,
like this:

gmp -> ../gmp-6.1.0
mpfr -> ../mpfr-3.1.4

2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* Makefile.def: Prepare for GDB build with intree GMP.
	* Makefile.in: Regenerate.

gdb:
2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* configure.ac: Add --with-gmp=DIR, --with-gmp-include=DIR
	and --with-gmp-lib=DIR
	as well as --with-mpfr-include=DIR and --with-mpfr-lib=DIR
	for compatibility with top level configure script.
	* configure: Regenerate.

contrib:
2020-11-15  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* download_prerequisites: New helper script.
	* prerequisites.md5: checksums.
	* prerequisites.sha512: checksums.
---
 Makefile.def                   |   5 +-
 Makefile.in                    |   4 +-
 contrib/download_prerequisites | 263 +++++++++++++++++++++++++++++++++++++++++
 contrib/prerequisites.md5      |   2 +
 contrib/prerequisites.sha512   |   2 +
 gdb/configure                  |  52 ++++++++
 gdb/configure.ac               |  25 ++++
 7 files changed, 351 insertions(+), 2 deletions(-)
 create mode 100755 contrib/download_prerequisites
 create mode 100644 contrib/prerequisites.md5
 create mode 100644 contrib/prerequisites.sha512

diff --git a/Makefile.def b/Makefile.def
index 089e70a..1b99b42 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -115,7 +115,8 @@ host_modules= { module= zlib; no_install=true; no_check=true;
 host_modules= { module= gnulib; };
 host_modules= { module= gdbsupport; };
 host_modules= { module= gdbserver; };
-host_modules= { module= gdb; };
+host_modules= { module= gdb;
+		extra_configure_flags='@extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@';};
 host_modules= { module= expect; };
 host_modules= { module= guile; };
 host_modules= { module= tk; };
@@ -391,6 +392,8 @@ dependencies = { module=all-intl; on=all-libiconv; };
 
 // Host modules specific to gdb.
 dependencies = { module=configure-gdb; on=all-intl; };
+dependencies = { module=configure-gdb; on=all-gmp; };
+dependencies = { module=configure-gdb; on=all-mpfr; };
 dependencies = { module=configure-gdb; on=configure-sim; };
 dependencies = { module=configure-gdb; on=all-bfd; };
 dependencies = { module=configure-gdb; on=all-gnulib; };
diff --git a/Makefile.in b/Makefile.in
index fe34132..738fd32 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -29491,7 +29491,7 @@ configure-gdb:
 	  $$s/$$module_srcdir/configure \
 	  --srcdir=$${topdir}/$$module_srcdir \
 	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
-	  --target=${target_alias}  \
+	  --target=${target_alias} @extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@ \
 	  || exit 1
 @endif gdb
 
@@ -52449,6 +52449,8 @@ configure-libcc1: maybe-configure-gcc
 all-libcc1: maybe-all-gcc
 all-utils: maybe-all-libiberty
 configure-gdb: maybe-all-intl
+configure-gdb: maybe-all-gmp
+configure-gdb: maybe-all-mpfr
 configure-gdb: maybe-all-bfd
 configure-gdb: maybe-all-libiconv
 all-gdb: maybe-all-libiberty
diff --git a/contrib/download_prerequisites b/contrib/download_prerequisites
new file mode 100755
index 0000000..a8b78da
--- /dev/null
+++ b/contrib/download_prerequisites
@@ -0,0 +1,263 @@
+#! /bin/sh
+#! -*- coding:utf-8; mode:shell-script; -*-
+
+# Download some prerequisites needed by GDB.
+# Run this from the top level of the GDB source tree and the GDB build will do
+# the right thing.  Run it with the `--help` option for more information.
+#
+# (C) 2010-2020 Free Software Foundation
+#
+# 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/.
+
+program='download_prerequisites'
+version='(unversioned)'
+
+# MAINTAINERS: If you update the package versions below, please
+# remember to also update the files `contrib/prerequisites.sha512` and
+# `contrib/prerequisites.md5` with the new checksums.
+
+gmp='gmp-6.1.0.tar.bz2'
+mpfr='mpfr-3.1.4.tar.bz2'
+
+base_url='http://gcc.gnu.org/pub/gcc/infrastructure/'
+
+echo_archives() {
+    echo "${gmp}"
+    echo "${mpfr}"
+}
+
+verify=1
+force=0
+OS=$(uname)
+
+case $OS in
+  "Darwin"|"FreeBSD"|"DragonFly"|"AIX")
+    chksum='shasum -a 512 --check'
+  ;;
+  "OpenBSD")
+    chksum='sha512 -c'
+  ;;
+  *)
+    chksum='sha512sum -c'
+  ;;
+esac
+
+if type wget > /dev/null ; then
+  fetch='wget'
+else
+  fetch='curl -LO'
+fi
+chksum_extension='sha512'
+directory='.'
+
+helptext="usage: ${program} [OPTION...]
+
+Downloads some prerequisites needed by GDB.  Run this from the top level of the
+GDB source tree and the GDB build will do the right thing.
+
+The following options are available:
+
+ --directory=DIR  download and unpack packages into DIR instead of '.'
+ --force          download again overwriting existing packages
+ --no-force       do not download existing packages again (default)
+ --verify         verify package integrity after download (default)
+ --no-verify      don't verify package integrity
+ --sha512         use SHA512 checksum to verify package integrity (default)
+ --md5            use MD5 checksum to verify package integrity
+ --help           show this text and exit
+ --version        show version information and exit
+"
+
+versiontext="${program} ${version}
+Copyright (C) 2020 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+die() {
+    echo "error: $@" >&2
+    exit 1
+}
+
+for arg in "$@"
+do
+    case "${arg}" in
+        --help)
+            echo "${helptext}"
+            exit
+            ;;
+        --version)
+            echo "${versiontext}"
+            exit
+            ;;
+    esac
+done
+unset arg
+
+# Emulate Linux's 'md5 --check' on macOS
+md5_check() {
+  # Store the standard input: a line from contrib/prerequisites.md5:
+  md5_checksum_line=$(cat -)
+  # Grab the text before the first space
+  md5_checksum_expected="${md5_checksum_line%% *}"
+  # Grab the text after the first space
+  file_to_check="${md5_checksum_line##* }"
+  # Calculate the md5 checksum for the downloaded file
+  md5_checksum_output=$(md5 -r "${file_to_check}")
+  # Grab the text before the first space
+  md5_checksum_detected="${md5_checksum_output%% *}"
+  [ "${md5_checksum_expected}" == "${md5_checksum_detected}" ] \
+    || die "Cannot verify integrity of possibly corrupted file ${file_to_check}"
+  echo "${file_to_check}: OK"
+}
+
+
+argnext=
+for arg in "$@"
+do
+    if [ "x${argnext}" = x ]
+    then
+        case "${arg}" in
+            --directory)
+                argnext='directory'
+                ;;
+            --directory=*)
+                directory="${arg#--directory=}"
+                ;;
+            --force)
+                force=1
+                ;;
+            --no-force)
+                force=0
+                ;;
+            --verify)
+                verify=1
+                ;;
+            --no-verify)
+                verify=0
+                ;;
+            --sha512)
+                case $OS in
+                  "Darwin")
+                    chksum='shasum -a 512 --check'
+                  ;;
+                  *)
+                    chksum='sha512sum --check'
+                  ;;
+                esac
+                chksum_extension='sha512'
+                verify=1
+                ;;
+            --md5)
+                case $OS in
+                  "Darwin")
+                    chksum='md5_check'
+                  ;;
+                  *)
+                    chksum='md5 --check'
+                  ;;
+                esac
+                chksum_extension='md5'
+                verify=1
+                ;;
+            -*)
+                die "unknown option: ${arg}"
+                ;;
+            *)
+                die "too many arguments"
+                ;;
+        esac
+    else
+        case "${arg}" in
+            -*)
+                die "Missing argument for option --${argnext}"
+                ;;
+        esac
+        case "${argnext}" in
+            directory)
+                directory="${arg}"
+                ;;
+            *)
+                die "The impossible has happened"
+                ;;
+        esac
+        argnext=
+    fi
+done
+[ "x${argnext}" = x ] || die "Missing argument for option --${argnext}"
+unset arg argnext
+
+[ -e ./gdb/version.in ]                                                       \
+    || die "You must run this script in the top-level GDB source directory"
+
+[ -d "${directory}" ]                                                         \
+    || die "No such directory: ${directory}"
+
+for ar in $(echo_archives)
+do
+    if [ ${force} -gt 0 ]; then rm -f "${directory}/${ar}"; fi
+    [ -e "${directory}/${ar}" ]                                               \
+        || ( cd "${directory}" && ${fetch} --no-verbose "${base_url}${ar}" )  \
+        || die "Cannot download ${ar} from ${base_url}"
+done
+unset ar
+
+if [ ${verify} -gt 0 ]
+then
+    chksumfile="contrib/prerequisites.${chksum_extension}"
+    [ -r "${chksumfile}" ] || die "No checksums available"
+    for ar in $(echo_archives)
+    do
+        grep "${ar}" "${chksumfile}"                                          \
+            | ( cd "${directory}" && ${chksum} )                              \
+            || die "Cannot verify integrity of possibly corrupted file ${ar}"
+    done
+    unset chksumfile
+fi
+unset ar
+
+for ar in $(echo_archives)
+do
+    package="${ar%.tar*}"
+    if [ ${force} -gt 0 ]; then rm -rf "${directory}/${package}"; fi
+    case $ar in
+    *.gz)
+	uncompress='gzip -d'
+	;;
+    *.bz2)
+	uncompress='bzip2 -d'
+	;;
+    *)
+	uncompress='cat'
+	;;
+    esac
+    [ -e "${directory}/${package}" ]                                          \
+        || ( cd "${directory}" && $uncompress <"${ar}" | tar -xf - )          \
+        || die "Cannot extract package from ${ar}"
+    unset package
+done
+unset ar
+
+for ar in $(echo_archives)
+do
+    target="${directory}/${ar%.tar*}/"
+    linkname="${ar%-*}"
+    if [ ${force} -gt 0 ]; then rm -f "${linkname}"; fi
+    [ -e "${linkname}" ]                                                      \
+        || ln -s "${target}" "${linkname}"                                    \
+        || die "Cannot create symbolic link ${linkname} --> ${target}"
+    unset target linkname
+done
+unset ar
+
+echo "All prerequisites downloaded successfully."
diff --git a/contrib/prerequisites.md5 b/contrib/prerequisites.md5
new file mode 100644
index 0000000..cf7be0d
--- /dev/null
+++ b/contrib/prerequisites.md5
@@ -0,0 +1,2 @@
+86ee6e54ebfc4a90b643a65e402c4048  gmp-6.1.0.tar.bz2
+b8a2f6b0e68bef46e53da2ac439e1cf4  mpfr-3.1.4.tar.bz2
diff --git a/contrib/prerequisites.sha512 b/contrib/prerequisites.sha512
new file mode 100644
index 0000000..8f05aff
--- /dev/null
+++ b/contrib/prerequisites.sha512
@@ -0,0 +1,2 @@
+3c82aeab9c1596d4da8afac2eec38e429e84f3211e1a572cf8fd2b546493c44c039b922a1133eaaa48bd7f3e11dbe795a384e21ed95cbe3ecc58d7ac02246117  gmp-6.1.0.tar.bz2
+51066066ff2c12ed2198605ecf68846b0c96b548adafa5b80e0c786d0df488411a5e8973358fce7192dc977ad4e68414cf14500e3c39746de62465eb145bb819  mpfr-3.1.4.tar.bz2
diff --git a/gdb/configure b/gdb/configure
index a3e73b4..034485d 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -899,8 +899,13 @@ with_jit_reader_dir
 with_expat
 with_libexpat_prefix
 with_libexpat_type
+with_gmp_include
+with_gmp_lib
+with_gmp
 with_libgmp_prefix
 with_libgmp_type
+with_mpfr_include
+with_mpfr_lib
 with_mpfr
 with_libmpfr_prefix
 with_libmpfr_type
@@ -1644,9 +1649,14 @@ Optional Packages:
   --with-libexpat-prefix[=DIR]  search for libexpat in DIR/include and DIR/lib
   --without-libexpat-prefix     don't search for libexpat in includedir and libdir
   --with-libexpat-type=TYPE     type of library to search for (auto/static/shared)
+  --with-gmp-include=DIR  GMP include directory
+  --with-gmp-lib=DIR      GMP lib directory
+  --with-gmp=DIR          GMP install directory
   --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
   --without-libgmp-prefix     don't search for libgmp in includedir and libdir
   --with-libgmp-type=TYPE     type of library to search for (auto/static/shared)
+  --with-mpfr-include=DIR MPFR include directory
+  --with-mpfr-lib=DIR     MPFR lib directory
   --with-mpfr             include MPFR support (auto/yes/no)
   --with-libmpfr-prefix[=DIR]  search for libmpfr in DIR/include and DIR/lib
   --without-libmpfr-prefix     don't search for libmpfr in includedir and libdir
@@ -9990,6 +10000,35 @@ done
   fi
 fi
 
+
+# Check whether --with-gmp_include was given.
+if test "${with_gmp_include+set}" = set; then :
+  withval=$with_gmp_include; CPPFLAGS="$CPPFLAGS -I$withval"
+fi
+
+
+# Check whether --with-gmp_lib was given.
+if test "${with_gmp_lib+set}" = set; then :
+  withval=$with_gmp_lib; LDFLAGS="$LDFLAGS -L$withval"
+fi
+
+
+# Check whether --with-gmp was given.
+if test "${with_gmp+set}" = set; then :
+  withval=$with_gmp;
+   if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
+      CPPFLAGS="$CPPFLAGS -I$withval/include"
+      LDFLAGS="$LDFLAGS -L$withval/lib"
+   else
+      { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.
+See \`config.log' for more details" "$LINENO" 5; }
+   fi
+
+fi
+
+
 # Verify that we have a usable GMP library.
 
 
@@ -10474,6 +10513,19 @@ if test "$HAVE_LIBGMP" != yes; then
 fi
 
 
+# Check whether --with-mpfr_include was given.
+if test "${with_mpfr_include+set}" = set; then :
+  withval=$with_mpfr_include; CPPFLAGS="-I$withval $CPPFLAGS"
+fi
+
+
+# Check whether --with-mpfr_lib was given.
+if test "${with_mpfr_lib+set}" = set; then :
+  withval=$with_mpfr_lib; LDFLAGS="-L$withval $LDFLAGS"
+fi
+
+
+
 # Check whether --with-mpfr was given.
 if test "${with_mpfr+set}" = set; then :
   withval=$with_mpfr;
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 32f25d9..97f43ce 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -683,6 +683,22 @@ else
   fi
 fi
 
+AC_ARG_WITH(gmp_include,
+   [  --with-gmp-include=DIR  GMP include directory ],
+   CPPFLAGS="$CPPFLAGS -I$withval")
+AC_ARG_WITH(gmp_lib,
+   [  --with-gmp-lib=DIR      GMP lib directory ],
+   LDFLAGS="$LDFLAGS -L$withval")
+AC_ARG_WITH(gmp,
+   [  --with-gmp=DIR          GMP install directory ], [
+   if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
+      CPPFLAGS="$CPPFLAGS -I$withval/include"
+      LDFLAGS="$LDFLAGS -L$withval/lib"
+   else
+      AC_MSG_FAILURE([Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.])
+   fi
+  ])
+
 # Verify that we have a usable GMP library.
 AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
                       [mpz_t n;
@@ -691,6 +707,15 @@ if test "$HAVE_LIBGMP" != yes; then
   AC_MSG_ERROR([GMP is missing or unusable])
 fi
 
+AC_ARG_WITH([mpfr_include],
+            [AC_HELP_STRING([--with-mpfr-include=DIR],
+                            [MPFR include directory])],
+            [CPPFLAGS="-I$withval $CPPFLAGS"])
+AC_ARG_WITH([mpfr_lib],
+            [AC_HELP_STRING([--with-mpfr-lib=DIR],
+                            [MPFR lib directory])],
+            [LDFLAGS="-L$withval $LDFLAGS"])
+
 AC_ARG_WITH(mpfr,
   AS_HELP_STRING([--with-mpfr], [include MPFR support (auto/yes/no)]),
   [], [with_mpfr=auto])
-- 
1.9.1


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH] Enable GDB build with in-tree GMP and MPFR
  2020-12-01 20:29                       ` Bernd Edlinger
@ 2020-12-01 20:30                         ` Simon Marchi
  2020-12-02  3:21                           ` Joel Brobecker
  2020-12-14 17:40                         ` [PATCH v2] " Bernd Edlinger
  1 sibling, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-12-01 20:30 UTC (permalink / raw)
  To: Bernd Edlinger, Joel Brobecker; +Cc: gdb-patches

On 2020-12-01 3:29 p.m., Bernd Edlinger wrote:
> Hi Simon,
>
> On 12/1/20 8:38 PM, Bernd Edlinger wrote:
>> On 12/1/20 8:32 PM, Simon Marchi wrote:
>>>
>>> On 2020-12-01 2:29 p.m., Bernd Edlinger wrote:
>>>> I would really like to be able to build gdb with in-tree gmp / mpfr,
>>>> just as it works for gcc.
>>>
>>> Pardon my ignorance, but I don't see the gmp nor the mpfr source code in
>>> the binutils-gdb repository.  Should it be checked in too?
>>>
>>
>>
>> Aehm, good question.
>> gcc uses a script ./contrib/download_prerequisites
>> that *can* be used to download gmp/mpfr and some more.
>>
>> Maybe I should add a stripped down version of that one?
>>
>
> So, this adds the contrib/download_prerequisites script.
>
> It is taken from gcc but does not download mpc and isl,
> just gmp and mpfr.
>
> It should work also when building gdb from the release tar.
>
>
> Is it OK to push?

I don't really know how it works, so I am not really the right person to
review it.

Simon


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH] Enable GDB build with in-tree GMP and MPFR
  2020-12-01 20:30                         ` Simon Marchi
@ 2020-12-02  3:21                           ` Joel Brobecker
  2020-12-08 20:39                             ` [PING] " Bernd Edlinger
  0 siblings, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-12-02  3:21 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Bernd Edlinger, gdb-patches

> I don't really know how it works, so I am not really the right person to
> review it.

That's unfortunately my case as well :-(.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFA 1/2] Fix TARGET_CHAR_BIT/HOST_CHAR_BIT confusion in gmp-utils.c
  2020-11-30 15:42                   ` Simon Marchi
@ 2020-12-05  8:05                     ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-12-05  8:05 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

> > In a couple of gdb_mpz methods, we are computing the number of
> > bits in a gdb::array_view of gdb_byte. Since gdb_byte is defined
> > using a host-side type (see common-types.h), the number of bits
> > in a gdb_byte should be HOST_CHAR_BIT, not TARGET_CHAR_BIT.
> 
> Right, and we are not supposed to use TARGET_CHAR_BIT anymore.  The same
> GDB could be debugging targets with different target char bit values, so
> a build-time constant like TARGET_CHAR_BIT can't work.  For those cases,
> gdbarch_addressable_memory_unit_size should be used instead.

Thanks for the review and the explanation, Simon.

I just pushed this patch to master.

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* [RFAv2 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values
  2020-11-29 15:45                 ` [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values Joel Brobecker
  2020-11-30 15:56                   ` Simon Marchi
@ 2020-12-05  8:10                   ` Joel Brobecker
  2020-12-05 23:26                     ` Simon Marchi
  1 sibling, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-12-05  8:10 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

Hi Simon,

Here is v2 of this patch, taking into account your comments and
suggestions. More precisely:

  - Parameter "nails" in gdb_mpz::safe_export has been removed;
  - I changed the error message to use "[nnn]-bits" instead of
    "[nnn]bits";
  - I removed a useless memset in gdb_mpz::safe_export;
  - I used the {buf, size} idiom to construct a a gdb::array view
    instead of using gdb::make_array_view.

The series was re-tested on x86_64-linux.

OK to push?

---------------------------------------------------------------------------

The gdb_mpz class currently provides a couple of methods which
essentially export an mpz_t value into either a buffer, or an integral
type. The export is based on using the mpz_export function which
we discovered can be a bit treacherous if used without caution.

In particular, the initial motivation for this patch was to catch
situations where the mpz_t value was so large that it would not fit
in the destination area. mpz_export does not know the size of
the buffer, and therefore can happily write past the end of our buffer.

While designing a solution to the above problem, I also discovered
that we also needed to be careful when exporting signed numbers.
In particular, numbers which are larger than the maximum value
for a given signed type size, but no so large as to fit in the
*unsigned* version with the same size, would end up being exported
incorrectly. This is related to the fact that mpz_export ignores
the sign of the value being exportd, and assumes an unsigned export.
Thus, for such large values, the appears as if mpz_export is able
to fit our value into our buffer, but in fact, it does not.

Also, I noticed that gdb_mpz::write wasn't taking its unsigned_p
parameter, which was a hole.

For all these reasons, a new low-level private method called
"safe_export" has been added to class gdb_mpz, whose goal is
to perform all necessary checks and manipulations for a safe
and correct export. As a bonus, this method allows us to factorize
the handling of negative value exports.

The gdb_mpz::as_integer and gdb_mpz::write methods are then simplified
to take advantage of this new safe_export method.

gdb/ChangeLog:

        * gmp-utils.h (gdb_mpz::safe_export): New private method.
        (gdb_mpz::as_integer): Reimplement using gdb_mpz::safe_export.
        * gmp-utils.c (gdb_mpz::write): Rewrite using gdb_mpz::safe_export.
        (gdb_mpz::safe_export): New method.
        * unittests/gmp-utils-selftests .c (gdb_mpz_as_integer):
        Update function description.
        (check_as_integer_raises_out_of_range_error): New function.
        (gdb_mpz_as_integer_out_of_range): New function.
        (_initialize_gmp_utils_selftests): Register
        gdb_mpz_as_integer_out_of_range as a selftest.
---
 gdb/gmp-utils.c                     | 79 +++++++++++++++++++++++++++++++++----
 gdb/gmp-utils.h                     | 40 ++++++++++---------
 gdb/unittests/gmp-utils-selftests.c | 71 +++++++++++++++++++++++++++++++--
 3 files changed, 162 insertions(+), 28 deletions(-)

diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index e3a3333..6b5c820 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -68,9 +68,61 @@ void
 gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
 		bool unsigned_p) const
 {
+  this->safe_export
+    (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */, unsigned_p);
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
+		      int endian, bool unsigned_p) const
+{
+  gdb_assert (buf.size () > 0);
+
+  if (mpz_sgn (val) == 0)
+    {
+      /* Our value is zero, so no need to call mpz_export to do the work,
+	 especially since mpz_export's documentation explicitly says
+	 that the function is a noop in this case.  Just write zero to
+	 BUF ourselves.  */
+      memset (buf.data (), 0, buf.size ());
+      return;
+    }
+
+  /* Determine the maximum range of values that our buffer can hold,
+     and verify that VAL is within that range.  */
+
+  gdb_mpz lo, hi;
+  const size_t max_usable_bits = buf.size () * HOST_CHAR_BIT;
+  if (unsigned_p)
+    {
+      lo = 0;
+
+      mpz_ui_pow_ui (hi.val, 2, max_usable_bits);
+      mpz_sub_ui (hi.val, hi.val, 1);
+    }
+  else
+    {
+      mpz_ui_pow_ui (lo.val, 2, max_usable_bits - 1);
+      mpz_neg (lo.val, lo.val);
+
+      mpz_ui_pow_ui (hi.val, 2, max_usable_bits - 1);
+      mpz_sub_ui (hi.val, hi.val, 1);
+    }
+
+  if (mpz_cmp (val, lo.val) < 0 || mpz_cmp (val, hi.val) > 0)
+    error (_("Cannot export value %s as %zu-bits %s integer"
+	     " (must be between %s and %s)"),
+	   this->str ().c_str (),
+	   max_usable_bits,
+	   unsigned_p ? _("unsigned") : _("signed"),
+	   lo.str ().c_str (),
+	   hi.str ().c_str ());
+
   gdb_mpz exported_val (val);
 
-  if (mpz_cmp_ui (val, 0) < 0)
+  if (mpz_cmp_ui (exported_val.val, 0) < 0)
     {
       /* mpz_export does not handle signed values, so create a positive
 	 value whose bit representation as an unsigned of the same length
@@ -81,13 +133,26 @@ gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
       mpz_add (exported_val.val, exported_val.val, neg_offset.val);
     }
 
+  /* Do the export into a buffer allocated by GMP itself; that way,
+     we can detect cases where BUF is not large enough to export
+     our value, and thus avoid a buffer overlow.  Normally, this should
+     never happen, since we verified earlier that the buffer is large
+     enough to accomodate our value, but doing this allows us to be
+     extra safe with the export.
+
+     After verification that the export behaved as expected, we will
+     copy the data over to BUF.  */
+
+  size_t word_countp;
+  gdb::unique_xmalloc_ptr<void> exported
+    (mpz_export (NULL, &word_countp, -1 /* order */, buf.size () /* size */,
+		 endian, 0 /* nails */, exported_val.val));
+
+  gdb_assert (word_countp == 1);
+
   /* Start by clearing the buffer, as mpz_export only writes as many
-     bytes as it needs (including none, if the value to export is zero.  */
-  memset (buf.data (), 0, buf.size ());
-  mpz_export (buf.data (), NULL /* count */, -1 /* order */,
-	      buf.size () /* size */,
-	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
-	      0 /* nails */, exported_val.val);
+     bytes as it needs.  */
+  memcpy (buf.data (), exported.get (), buf.size ());
 }
 
 /* See gmp-utils.h.  */
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index 12e4f8e..dae62cf 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -121,6 +121,24 @@ struct gdb_mpz
 
   /* Helper template for constructor and operator=.  */
   template<typename T> void set (T src);
+
+  /* Low-level function to export VAL into BUF as a number whose byte size
+     is the size of BUF.
+
+     If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
+     Otherwise, export it as a signed value.
+
+     The API is inspired from GMP's mpz_export, hence the naming and types
+     of the following parameter:
+       - ENDIAN should be:
+           . 1 for most significant byte first; or
+	   . -1 for least significant byte first; or
+	   . 0 for native endianness.
+
+    An error is raised if BUF is not large enough to contain the value
+    being exported.  */
+  void safe_export (gdb::array_view<gdb_byte> buf,
+		    int endian, bool unsigned_p) const;
 };
 
 /* A class to make it easier to use GMP's mpq_t values within GDB.  */
@@ -258,26 +276,12 @@ template<typename T>
 T
 gdb_mpz::as_integer () const
 {
-  /* Initialize RESULT, because mpz_export only write the minimum
-     number of bytes, including none if our value is zero!  */
-  T result = 0;
-
-  gdb_mpz exported_val (val);
-  if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
-    {
-      /* We want to use mpz_export to set the return value, but
-	 this function does not handle the sign. So give exported_val
-	 a value which is at the same time positive, and has the same
-	 bit representation as our negative value.  */
-      gdb_mpz neg_offset;
+  T result;
 
-      mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
-      mpz_add (exported_val.val, exported_val.val, neg_offset.val);
-    }
+  this->safe_export ({(gdb_byte *) &result, sizeof (result)},
+		     0 /* endian (0 = native) */,
+		     !std::is_signed<T>::value /* unsigned_p */);
 
-  mpz_export (&result, NULL /* count */, -1 /* order */,
-	      sizeof (T) /* size */, 0 /* endian (0 = native) */,
-	      0 /* nails */, exported_val.val);
   return result;
 }
 
diff --git a/gdb/unittests/gmp-utils-selftests.c b/gdb/unittests/gmp-utils-selftests.c
index 1365905..30c1902 100644
--- a/gdb/unittests/gmp-utils-selftests.c
+++ b/gdb/unittests/gmp-utils-selftests.c
@@ -26,9 +26,10 @@ namespace selftests {
 
 /* Perform a series of general tests of gdb_mpz's as_integer method.
 
-   This function tries to be reasonably exhaustive, by testing the edges,
-   as well as a resonable set of values including negative ones, zero,
-   and positive values.  */
+   This function limits itself to values which are in range (out-of-range
+   values will be tested separately).  In doing so, it tries to be reasonably
+   exhaustive, by testing the edges, as well as a resonable set of values
+   including negative ones, zero, and positive values.  */
 
 static void
 gdb_mpz_as_integer ()
@@ -80,6 +81,68 @@ gdb_mpz_as_integer ()
   SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
 }
 
+/* A helper function which calls the given gdb_mpz object's as_integer
+   method with the given type T, and verifies that this triggers
+   an error due to VAL's value being out of range for type T.  */
+
+template<typename T, typename = gdb::Requires<std::is_integral<T>>>
+static void
+check_as_integer_raises_out_of_range_error (const gdb_mpz &val)
+{
+  try
+    {
+      val.as_integer<T> ();
+    }
+  catch (const gdb_exception_error &ex)
+    {
+      SELF_CHECK (ex.reason == RETURN_ERROR);
+      SELF_CHECK (ex.error == GENERIC_ERROR);
+      SELF_CHECK (strstr (ex.what (), "Cannot export value") != nullptr);
+      return;
+    }
+  /* The expected exception did not get raised.  */
+  SELF_CHECK (false);
+}
+
+/* Perform out-of-range tests of gdb_mpz's as_integer method.
+
+   The goal of this function is to verify that gdb_mpz::as_integer
+   handles out-of-range values correctly.  */
+
+static void
+gdb_mpz_as_integer_out_of_range ()
+{
+  gdb_mpz v;
+
+  /* Try LONGEST_MIN minus 1.  */
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
+  mpz_neg (v.val, v.val);
+  mpz_sub_ui (v.val, v.val, 1);
+
+  check_as_integer_raises_out_of_range_error<ULONGEST> (v);
+  check_as_integer_raises_out_of_range_error<LONGEST> (v);
+
+  /* Try negative one (-1). */
+  v = -1;
+
+  check_as_integer_raises_out_of_range_error<ULONGEST> (v);
+  SELF_CHECK (v.as_integer<LONGEST> () == (LONGEST) -1);
+
+  /* Try LONGEST_MAX plus 1.  */
+  v = LONGEST_MAX;
+  mpz_add_ui (v.val, v.val, 1);
+
+  SELF_CHECK (v.as_integer<ULONGEST> () == (ULONGEST) LONGEST_MAX + 1);
+  check_as_integer_raises_out_of_range_error<LONGEST> (v);
+
+  /* Try ULONGEST_MAX plus 1.  */
+  v = ULONGEST_MAX;
+  mpz_add_ui (v.val, v.val, 1);
+
+  check_as_integer_raises_out_of_range_error<ULONGEST> (v);
+  check_as_integer_raises_out_of_range_error<LONGEST> (v);
+}
+
 /* A helper function to store the given integer value into a buffer,
    before reading it back into a gdb_mpz.  Sets ACTUAL to the value
    read back, while at the same time setting EXPECTED as the value
@@ -445,6 +508,8 @@ _initialize_gmp_utils_selftests ()
 {
   selftests::register_test ("gdb_mpz_as_integer",
 			    selftests::gdb_mpz_as_integer);
+  selftests::register_test ("gdb_mpz_as_integer_out_of_range",
+			    selftests::gdb_mpz_as_integer_out_of_range);
   selftests::register_test ("gdb_mpz_read_all_from_small",
 			    selftests::gdb_mpz_read_all_from_small);
   selftests::register_test ("gdb_mpz_read_min_max",
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFAv2 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values
  2020-12-05  8:10                   ` [RFAv2 " Joel Brobecker
@ 2020-12-05 23:26                     ` Simon Marchi
  2020-12-06  4:58                       ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-12-05 23:26 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

On 2020-12-05 3:10 a.m., Joel Brobecker wrote:
> @@ -81,13 +133,26 @@ gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
>        mpz_add (exported_val.val, exported_val.val, neg_offset.val);
>      }
>
> +  /* Do the export into a buffer allocated by GMP itself; that way,
> +     we can detect cases where BUF is not large enough to export
> +     our value, and thus avoid a buffer overlow.  Normally, this should
> +     never happen, since we verified earlier that the buffer is large
> +     enough to accomodate our value, but doing this allows us to be
> +     extra safe with the export.
> +
> +     After verification that the export behaved as expected, we will
> +     copy the data over to BUF.  */
> +
> +  size_t word_countp;
> +  gdb::unique_xmalloc_ptr<void> exported
> +    (mpz_export (NULL, &word_countp, -1 /* order */, buf.size () /* size */,
> +		 endian, 0 /* nails */, exported_val.val));
> +
> +  gdb_assert (word_countp == 1);
> +
>    /* Start by clearing the buffer, as mpz_export only writes as many
> -     bytes as it needs (including none, if the value to export is zero.  */

That comment is now stale.

Otherwise, that LGTM.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [RFAv2 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values
  2020-12-05 23:26                     ` Simon Marchi
@ 2020-12-06  4:58                       ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-12-06  4:58 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1396 bytes --]

> On 2020-12-05 3:10 a.m., Joel Brobecker wrote:
> > @@ -81,13 +133,26 @@ gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
> >        mpz_add (exported_val.val, exported_val.val, neg_offset.val);
> >      }
> >
> > +  /* Do the export into a buffer allocated by GMP itself; that way,
> > +     we can detect cases where BUF is not large enough to export
> > +     our value, and thus avoid a buffer overlow.  Normally, this should
> > +     never happen, since we verified earlier that the buffer is large
> > +     enough to accomodate our value, but doing this allows us to be
> > +     extra safe with the export.
> > +
> > +     After verification that the export behaved as expected, we will
> > +     copy the data over to BUF.  */
> > +
> > +  size_t word_countp;
> > +  gdb::unique_xmalloc_ptr<void> exported
> > +    (mpz_export (NULL, &word_countp, -1 /* order */, buf.size () /* size */,
> > +		 endian, 0 /* nails */, exported_val.val));
> > +
> > +  gdb_assert (word_countp == 1);
> > +
> >    /* Start by clearing the buffer, as mpz_export only writes as many
> > -     bytes as it needs (including none, if the value to export is zero.  */
> 
> That comment is now stale.

Indeed. Thanks for catching that.

> Otherwise, that LGTM.

Thanks Simon. The patch is now in, with the correction above (a copy
of the patch is attached, for the record).

-- 
Joel

[-- Attachment #2: 0001-gmp-utils-protect-gdb_mpz-exports-against-out-of-ran.patch --]
[-- Type: text/x-diff, Size: 12521 bytes --]

From 63c457b911043aa6ebf3558e2d2050ee53d28a8e Mon Sep 17 00:00:00 2001
From: Joel Brobecker <brobecker@adacore.com>
Date: Sat, 5 Dec 2020 23:56:59 -0500
Subject: [PATCH] gmp-utils: protect gdb_mpz exports against out-of-range
 values

The gdb_mpz class currently provides a couple of methods which
essentially export an mpz_t value into either a buffer, or an integral
type. The export is based on using the mpz_export function which
we discovered can be a bit treacherous if used without caution.

In particular, the initial motivation for this patch was to catch
situations where the mpz_t value was so large that it would not fit
in the destination area. mpz_export does not know the size of
the buffer, and therefore can happily write past the end of our buffer.

While designing a solution to the above problem, I also discovered
that we also needed to be careful when exporting signed numbers.
In particular, numbers which are larger than the maximum value
for a given signed type size, but no so large as to fit in the
*unsigned* version with the same size, would end up being exported
incorrectly. This is related to the fact that mpz_export ignores
the sign of the value being exportd, and assumes an unsigned export.
Thus, for such large values, the appears as if mpz_export is able
to fit our value into our buffer, but in fact, it does not.

Also, I noticed that gdb_mpz::write wasn't taking its unsigned_p
parameter, which was a hole.

For all these reasons, a new low-level private method called
"safe_export" has been added to class gdb_mpz, whose goal is
to perform all necessary checks and manipulations for a safe
and correct export. As a bonus, this method allows us to factorize
the handling of negative value exports.

The gdb_mpz::as_integer and gdb_mpz::write methods are then simplified
to take advantage of this new safe_export method.

gdb/ChangeLog:

        * gmp-utils.h (gdb_mpz::safe_export): New private method.
        (gdb_mpz::as_integer): Reimplement using gdb_mpz::safe_export.
        * gmp-utils.c (gdb_mpz::write): Rewrite using gdb_mpz::safe_export.
        (gdb_mpz::safe_export): New method.
        * unittests/gmp-utils-selftests .c (gdb_mpz_as_integer):
        Update function description.
        (check_as_integer_raises_out_of_range_error): New function.
        (gdb_mpz_as_integer_out_of_range): New function.
        (_initialize_gmp_utils_selftests): Register
        gdb_mpz_as_integer_out_of_range as a selftest.
---
 gdb/ChangeLog                       | 13 ++++++
 gdb/gmp-utils.c                     | 79 +++++++++++++++++++++++++++++++++----
 gdb/gmp-utils.h                     | 40 ++++++++++---------
 gdb/unittests/gmp-utils-selftests.c | 71 +++++++++++++++++++++++++++++++--
 4 files changed, 174 insertions(+), 29 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index fd95992..d8b67c6 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,16 @@
+2020-12-06  Joel Brobecker  <brobecker@adacore.com>
+
+	* gmp-utils.h (gdb_mpz::safe_export): New private method.
+	(gdb_mpz::as_integer): Reimplement using gdb_mpz::safe_export.
+	* gmp-utils.c (gdb_mpz::write): Rewrite using gdb_mpz::safe_export.
+	(gdb_mpz::safe_export): New method.
+	* unittests/gmp-utils-selftests .c (gdb_mpz_as_integer):
+	Update function description.
+	(check_as_integer_raises_out_of_range_error): New function.
+	(gdb_mpz_as_integer_out_of_range): New function.
+	(_initialize_gmp_utils_selftests): Register
+	gdb_mpz_as_integer_out_of_range as a selftest.
+
 2020-12-05  Joel Brobecker  <brobecker@adacore.com>
 
 	* gmp-utils.c (gdb_mpz::read): Use HOST_CHAR_BIT instead of
diff --git a/gdb/gmp-utils.c b/gdb/gmp-utils.c
index e3a3333..60c915c 100644
--- a/gdb/gmp-utils.c
+++ b/gdb/gmp-utils.c
@@ -68,9 +68,61 @@ void
 gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
 		bool unsigned_p) const
 {
+  this->safe_export
+    (buf, byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */, unsigned_p);
+}
+
+/* See gmp-utils.h.  */
+
+void
+gdb_mpz::safe_export (gdb::array_view<gdb_byte> buf,
+		      int endian, bool unsigned_p) const
+{
+  gdb_assert (buf.size () > 0);
+
+  if (mpz_sgn (val) == 0)
+    {
+      /* Our value is zero, so no need to call mpz_export to do the work,
+	 especially since mpz_export's documentation explicitly says
+	 that the function is a noop in this case.  Just write zero to
+	 BUF ourselves.  */
+      memset (buf.data (), 0, buf.size ());
+      return;
+    }
+
+  /* Determine the maximum range of values that our buffer can hold,
+     and verify that VAL is within that range.  */
+
+  gdb_mpz lo, hi;
+  const size_t max_usable_bits = buf.size () * HOST_CHAR_BIT;
+  if (unsigned_p)
+    {
+      lo = 0;
+
+      mpz_ui_pow_ui (hi.val, 2, max_usable_bits);
+      mpz_sub_ui (hi.val, hi.val, 1);
+    }
+  else
+    {
+      mpz_ui_pow_ui (lo.val, 2, max_usable_bits - 1);
+      mpz_neg (lo.val, lo.val);
+
+      mpz_ui_pow_ui (hi.val, 2, max_usable_bits - 1);
+      mpz_sub_ui (hi.val, hi.val, 1);
+    }
+
+  if (mpz_cmp (val, lo.val) < 0 || mpz_cmp (val, hi.val) > 0)
+    error (_("Cannot export value %s as %zu-bits %s integer"
+	     " (must be between %s and %s)"),
+	   this->str ().c_str (),
+	   max_usable_bits,
+	   unsigned_p ? _("unsigned") : _("signed"),
+	   lo.str ().c_str (),
+	   hi.str ().c_str ());
+
   gdb_mpz exported_val (val);
 
-  if (mpz_cmp_ui (val, 0) < 0)
+  if (mpz_cmp_ui (exported_val.val, 0) < 0)
     {
       /* mpz_export does not handle signed values, so create a positive
 	 value whose bit representation as an unsigned of the same length
@@ -81,13 +133,24 @@ gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
       mpz_add (exported_val.val, exported_val.val, neg_offset.val);
     }
 
-  /* Start by clearing the buffer, as mpz_export only writes as many
-     bytes as it needs (including none, if the value to export is zero.  */
-  memset (buf.data (), 0, buf.size ());
-  mpz_export (buf.data (), NULL /* count */, -1 /* order */,
-	      buf.size () /* size */,
-	      byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
-	      0 /* nails */, exported_val.val);
+  /* Do the export into a buffer allocated by GMP itself; that way,
+     we can detect cases where BUF is not large enough to export
+     our value, and thus avoid a buffer overlow.  Normally, this should
+     never happen, since we verified earlier that the buffer is large
+     enough to accomodate our value, but doing this allows us to be
+     extra safe with the export.
+
+     After verification that the export behaved as expected, we will
+     copy the data over to BUF.  */
+
+  size_t word_countp;
+  gdb::unique_xmalloc_ptr<void> exported
+    (mpz_export (NULL, &word_countp, -1 /* order */, buf.size () /* size */,
+		 endian, 0 /* nails */, exported_val.val));
+
+  gdb_assert (word_countp == 1);
+
+  memcpy (buf.data (), exported.get (), buf.size ());
 }
 
 /* See gmp-utils.h.  */
diff --git a/gdb/gmp-utils.h b/gdb/gmp-utils.h
index 12e4f8e..dae62cf 100644
--- a/gdb/gmp-utils.h
+++ b/gdb/gmp-utils.h
@@ -121,6 +121,24 @@ struct gdb_mpz
 
   /* Helper template for constructor and operator=.  */
   template<typename T> void set (T src);
+
+  /* Low-level function to export VAL into BUF as a number whose byte size
+     is the size of BUF.
+
+     If UNSIGNED_P is true, then export VAL into BUF as an unsigned value.
+     Otherwise, export it as a signed value.
+
+     The API is inspired from GMP's mpz_export, hence the naming and types
+     of the following parameter:
+       - ENDIAN should be:
+           . 1 for most significant byte first; or
+	   . -1 for least significant byte first; or
+	   . 0 for native endianness.
+
+    An error is raised if BUF is not large enough to contain the value
+    being exported.  */
+  void safe_export (gdb::array_view<gdb_byte> buf,
+		    int endian, bool unsigned_p) const;
 };
 
 /* A class to make it easier to use GMP's mpq_t values within GDB.  */
@@ -258,26 +276,12 @@ template<typename T>
 T
 gdb_mpz::as_integer () const
 {
-  /* Initialize RESULT, because mpz_export only write the minimum
-     number of bytes, including none if our value is zero!  */
-  T result = 0;
-
-  gdb_mpz exported_val (val);
-  if (std::is_signed<T>::value && mpz_cmp_ui (val, 0) < 0)
-    {
-      /* We want to use mpz_export to set the return value, but
-	 this function does not handle the sign. So give exported_val
-	 a value which is at the same time positive, and has the same
-	 bit representation as our negative value.  */
-      gdb_mpz neg_offset;
+  T result;
 
-      mpz_ui_pow_ui (neg_offset.val, 2, sizeof (T) * HOST_CHAR_BIT);
-      mpz_add (exported_val.val, exported_val.val, neg_offset.val);
-    }
+  this->safe_export ({(gdb_byte *) &result, sizeof (result)},
+		     0 /* endian (0 = native) */,
+		     !std::is_signed<T>::value /* unsigned_p */);
 
-  mpz_export (&result, NULL /* count */, -1 /* order */,
-	      sizeof (T) /* size */, 0 /* endian (0 = native) */,
-	      0 /* nails */, exported_val.val);
   return result;
 }
 
diff --git a/gdb/unittests/gmp-utils-selftests.c b/gdb/unittests/gmp-utils-selftests.c
index 1365905..30c1902 100644
--- a/gdb/unittests/gmp-utils-selftests.c
+++ b/gdb/unittests/gmp-utils-selftests.c
@@ -26,9 +26,10 @@ namespace selftests {
 
 /* Perform a series of general tests of gdb_mpz's as_integer method.
 
-   This function tries to be reasonably exhaustive, by testing the edges,
-   as well as a resonable set of values including negative ones, zero,
-   and positive values.  */
+   This function limits itself to values which are in range (out-of-range
+   values will be tested separately).  In doing so, it tries to be reasonably
+   exhaustive, by testing the edges, as well as a resonable set of values
+   including negative ones, zero, and positive values.  */
 
 static void
 gdb_mpz_as_integer ()
@@ -80,6 +81,68 @@ gdb_mpz_as_integer ()
   SELF_CHECK (v.as_integer<ULONGEST> () == ul_expected);
 }
 
+/* A helper function which calls the given gdb_mpz object's as_integer
+   method with the given type T, and verifies that this triggers
+   an error due to VAL's value being out of range for type T.  */
+
+template<typename T, typename = gdb::Requires<std::is_integral<T>>>
+static void
+check_as_integer_raises_out_of_range_error (const gdb_mpz &val)
+{
+  try
+    {
+      val.as_integer<T> ();
+    }
+  catch (const gdb_exception_error &ex)
+    {
+      SELF_CHECK (ex.reason == RETURN_ERROR);
+      SELF_CHECK (ex.error == GENERIC_ERROR);
+      SELF_CHECK (strstr (ex.what (), "Cannot export value") != nullptr);
+      return;
+    }
+  /* The expected exception did not get raised.  */
+  SELF_CHECK (false);
+}
+
+/* Perform out-of-range tests of gdb_mpz's as_integer method.
+
+   The goal of this function is to verify that gdb_mpz::as_integer
+   handles out-of-range values correctly.  */
+
+static void
+gdb_mpz_as_integer_out_of_range ()
+{
+  gdb_mpz v;
+
+  /* Try LONGEST_MIN minus 1.  */
+  mpz_ui_pow_ui (v.val, 2, sizeof (LONGEST) * 8 - 1);
+  mpz_neg (v.val, v.val);
+  mpz_sub_ui (v.val, v.val, 1);
+
+  check_as_integer_raises_out_of_range_error<ULONGEST> (v);
+  check_as_integer_raises_out_of_range_error<LONGEST> (v);
+
+  /* Try negative one (-1). */
+  v = -1;
+
+  check_as_integer_raises_out_of_range_error<ULONGEST> (v);
+  SELF_CHECK (v.as_integer<LONGEST> () == (LONGEST) -1);
+
+  /* Try LONGEST_MAX plus 1.  */
+  v = LONGEST_MAX;
+  mpz_add_ui (v.val, v.val, 1);
+
+  SELF_CHECK (v.as_integer<ULONGEST> () == (ULONGEST) LONGEST_MAX + 1);
+  check_as_integer_raises_out_of_range_error<LONGEST> (v);
+
+  /* Try ULONGEST_MAX plus 1.  */
+  v = ULONGEST_MAX;
+  mpz_add_ui (v.val, v.val, 1);
+
+  check_as_integer_raises_out_of_range_error<ULONGEST> (v);
+  check_as_integer_raises_out_of_range_error<LONGEST> (v);
+}
+
 /* A helper function to store the given integer value into a buffer,
    before reading it back into a gdb_mpz.  Sets ACTUAL to the value
    read back, while at the same time setting EXPECTED as the value
@@ -445,6 +508,8 @@ _initialize_gmp_utils_selftests ()
 {
   selftests::register_test ("gdb_mpz_as_integer",
 			    selftests::gdb_mpz_as_integer);
+  selftests::register_test ("gdb_mpz_as_integer_out_of_range",
+			    selftests::gdb_mpz_as_integer_out_of_range);
   selftests::register_test ("gdb_mpz_read_all_from_small",
 			    selftests::gdb_mpz_read_all_from_small);
   selftests::register_test ("gdb_mpz_read_min_max",
-- 
2.1.4


^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PING] [PATCH] Enable GDB build with in-tree GMP and MPFR
  2020-12-02  3:21                           ` Joel Brobecker
@ 2020-12-08 20:39                             ` Bernd Edlinger
  0 siblings, 0 replies; 140+ messages in thread
From: Bernd Edlinger @ 2020-12-08 20:39 UTC (permalink / raw)
  To: Joel Brobecker, Simon Marchi
  Cc: gdb-patches, Pedro Alves, Eli Zaretskii, Andrew Burgess,
	Tom Tromey, Tom de Vries

Hi,
On 12/2/20 4:21 AM, Joel Brobecker wrote:
>> I don't really know how it works, so I am not really the right person to
>> review it.
> 
> That's unfortunately my case as well :-(.
> 

this is the latest version of the patch:
https://sourceware.org/pipermail/gdb-patches/2020-December/173668.html

So who can review it?


Thanks
Bernd.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-01 20:29                       ` Bernd Edlinger
  2020-12-01 20:30                         ` Simon Marchi
@ 2020-12-14 17:40                         ` Bernd Edlinger
  2020-12-14 18:47                           ` Simon Marchi
  1 sibling, 1 reply; 140+ messages in thread
From: Bernd Edlinger @ 2020-12-14 17:40 UTC (permalink / raw)
  To: Simon Marchi, Joel Brobecker, Pedro Alves, Eli Zaretskii,
	Andrew Burgess, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1323 bytes --]

Well, 

I thought, I should add a few words in the README
about this feature:

diff --git a/gdb/README b/gdb/README
index e65c5ea..db0a774 100644
--- a/gdb/README
+++ b/gdb/README
@@ -488,6 +488,9 @@ more obscure GDB `configure' options are not listed here.
      Build GDB using the GMP library installed at the directory DIR.
      If your host does not have GMP installed, you can get the latest
      version at `https://gmplib.org/'.
+     You can also build GMP in-tree when you use the script
+     ./contrib/download_prerequisites.  Note however, that this
+     does only work with a separate build directory.
 
 `--with-mpfr'
      Build GDB with GNU MPFR, a library for multiple-precision
@@ -499,6 +502,9 @@ more obscure GDB `configure' options are not listed here.
      available, GDB will fall back to using host floating-point
      arithmetic.  If your host does not have GNU MPFR installed, you
      can get the latest version from `https://www.mpfr.org/'.
+     You can also build MPFR in-tree when you use the script
+     ./contrib/download_prerequisites.  Note however, that this
+     does only work with a separate build directory.
 
 `--with-python[=PYTHON]'
      Build GDB with Python scripting support.  (Done by default if


Tested on x86_64-pc-linux-gnu.
Is it OK for trunk?


Thanks
Bernd.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR.patch --]
[-- Type: text/x-patch; name="0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR.patch", Size: 17679 bytes --]

From 367fae972e90370540468786f59856cb7581f6b2 Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Sun, 15 Nov 2020 15:37:22 +0100
Subject: [PATCH] Enable GDB build with in-tree GMP and MPFR

With this patch GDB can be built with in-tree GMP and/or
MPFR.  This works also for cross-builds.

All that is needed, is a sym-link in the source tree,
like this:

gmp -> ../gmp-6.1.0
mpfr -> ../mpfr-3.1.4

2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* Makefile.def: Prepare for GDB build with intree GMP.
	* Makefile.in: Regenerate.

gdb:
2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* configure.ac: Add --with-gmp=DIR, --with-gmp-include=DIR
	and --with-gmp-lib=DIR
	as well as --with-mpfr-include=DIR and --with-mpfr-lib=DIR
	for compatibility with top level configure script.
	* configure: Regenerate.
	* README: Mention ./contrib/download_prerequisites.

contrib:
2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* download_prerequisites: New helper script.
	* prerequisites.md5: checksums.
	* prerequisites.sha512: checksums.
---
 Makefile.def                   |   5 +-
 Makefile.in                    |   4 +-
 contrib/download_prerequisites | 263 +++++++++++++++++++++++++++++++++++++++++
 contrib/prerequisites.md5      |   2 +
 contrib/prerequisites.sha512   |   2 +
 gdb/README                     |   6 +
 gdb/configure                  |  52 ++++++++
 gdb/configure.ac               |  25 ++++
 8 files changed, 357 insertions(+), 2 deletions(-)
 create mode 100755 contrib/download_prerequisites
 create mode 100644 contrib/prerequisites.md5
 create mode 100644 contrib/prerequisites.sha512

diff --git a/Makefile.def b/Makefile.def
index 089e70a..1b99b42 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -115,7 +115,8 @@ host_modules= { module= zlib; no_install=true; no_check=true;
 host_modules= { module= gnulib; };
 host_modules= { module= gdbsupport; };
 host_modules= { module= gdbserver; };
-host_modules= { module= gdb; };
+host_modules= { module= gdb;
+		extra_configure_flags='@extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@';};
 host_modules= { module= expect; };
 host_modules= { module= guile; };
 host_modules= { module= tk; };
@@ -391,6 +392,8 @@ dependencies = { module=all-intl; on=all-libiconv; };
 
 // Host modules specific to gdb.
 dependencies = { module=configure-gdb; on=all-intl; };
+dependencies = { module=configure-gdb; on=all-gmp; };
+dependencies = { module=configure-gdb; on=all-mpfr; };
 dependencies = { module=configure-gdb; on=configure-sim; };
 dependencies = { module=configure-gdb; on=all-bfd; };
 dependencies = { module=configure-gdb; on=all-gnulib; };
diff --git a/Makefile.in b/Makefile.in
index fe34132..738fd32 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -29491,7 +29491,7 @@ configure-gdb:
 	  $$s/$$module_srcdir/configure \
 	  --srcdir=$${topdir}/$$module_srcdir \
 	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
-	  --target=${target_alias}  \
+	  --target=${target_alias} @extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@ \
 	  || exit 1
 @endif gdb
 
@@ -52449,6 +52449,8 @@ configure-libcc1: maybe-configure-gcc
 all-libcc1: maybe-all-gcc
 all-utils: maybe-all-libiberty
 configure-gdb: maybe-all-intl
+configure-gdb: maybe-all-gmp
+configure-gdb: maybe-all-mpfr
 configure-gdb: maybe-all-bfd
 configure-gdb: maybe-all-libiconv
 all-gdb: maybe-all-libiberty
diff --git a/contrib/download_prerequisites b/contrib/download_prerequisites
new file mode 100755
index 0000000..0d04030
--- /dev/null
+++ b/contrib/download_prerequisites
@@ -0,0 +1,263 @@
+#! /bin/sh
+#! -*- coding:utf-8; mode:shell-script; -*-
+
+# Download some prerequisites needed by GDB.
+# Run this from the top level of the GDB source tree and the GDB build will do
+# the right thing.  Run it with the `--help` option for more information.
+#
+# (C) 2010-2020 Free Software Foundation
+#
+# 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/.
+
+program='download_prerequisites'
+version='(unversioned)'
+
+# MAINTAINERS: If you update the package versions below, please
+# remember to also update the files `contrib/prerequisites.sha512` and
+# `contrib/prerequisites.md5` with the new checksums.
+
+gmp='gmp-6.1.0.tar.bz2'
+mpfr='mpfr-3.1.4.tar.bz2'
+
+base_url='http://gcc.gnu.org/pub/gcc/infrastructure/'
+
+echo_archives() {
+    echo "${gmp}"
+    echo "${mpfr}"
+}
+
+verify=1
+force=0
+OS=$(uname)
+
+case $OS in
+  "Darwin"|"FreeBSD"|"DragonFly"|"AIX")
+    chksum='shasum -a 512 --check'
+  ;;
+  "OpenBSD")
+    chksum='sha512 -c'
+  ;;
+  *)
+    chksum='sha512sum -c'
+  ;;
+esac
+
+if type wget > /dev/null ; then
+  fetch='wget'
+else
+  fetch='curl -LO'
+fi
+chksum_extension='sha512'
+directory='.'
+
+helptext="usage: ${program} [OPTION...]
+
+Downloads some prerequisites needed by GDB.  Run this from the top level of the
+GDB source tree and the GDB build will do the right thing.
+
+The following options are available:
+
+ --directory=DIR  download and unpack packages into DIR instead of '.'
+ --force          download again overwriting existing packages
+ --no-force       do not download existing packages again (default)
+ --verify         verify package integrity after download (default)
+ --no-verify      don't verify package integrity
+ --sha512         use SHA512 checksum to verify package integrity (default)
+ --md5            use MD5 checksum to verify package integrity
+ --help           show this text and exit
+ --version        show version information and exit
+"
+
+versiontext="${program} ${version}
+Copyright (C) 2020 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+die() {
+    echo "error: $@" >&2
+    exit 1
+}
+
+for arg in "$@"
+do
+    case "${arg}" in
+        --help)
+            echo "${helptext}"
+            exit
+            ;;
+        --version)
+            echo "${versiontext}"
+            exit
+            ;;
+    esac
+done
+unset arg
+
+# Emulate Linux's 'md5 --check' on macOS
+md5_check() {
+  # Store the standard input: a line from contrib/prerequisites.md5:
+  md5_checksum_line=$(cat -)
+  # Grab the text before the first space
+  md5_checksum_expected="${md5_checksum_line%% *}"
+  # Grab the text after the first space
+  file_to_check="${md5_checksum_line##* }"
+  # Calculate the md5 checksum for the downloaded file
+  md5_checksum_output=$(md5 -r "${file_to_check}")
+  # Grab the text before the first space
+  md5_checksum_detected="${md5_checksum_output%% *}"
+  [ "${md5_checksum_expected}" == "${md5_checksum_detected}" ] \
+    || die "Cannot verify integrity of possibly corrupted file ${file_to_check}"
+  echo "${file_to_check}: OK"
+}
+
+
+argnext=
+for arg in "$@"
+do
+    if [ "x${argnext}" = x ]
+    then
+        case "${arg}" in
+            --directory)
+                argnext='directory'
+                ;;
+            --directory=*)
+                directory="${arg#--directory=}"
+                ;;
+            --force)
+                force=1
+                ;;
+            --no-force)
+                force=0
+                ;;
+            --verify)
+                verify=1
+                ;;
+            --no-verify)
+                verify=0
+                ;;
+            --sha512)
+                case $OS in
+                  "Darwin")
+                    chksum='shasum -a 512 --check'
+                  ;;
+                  *)
+                    chksum='sha512sum --check'
+                  ;;
+                esac
+                chksum_extension='sha512'
+                verify=1
+                ;;
+            --md5)
+                case $OS in
+                  "Darwin")
+                    chksum='md5_check'
+                  ;;
+                  *)
+                    chksum='md5 --check'
+                  ;;
+                esac
+                chksum_extension='md5'
+                verify=1
+                ;;
+            -*)
+                die "unknown option: ${arg}"
+                ;;
+            *)
+                die "too many arguments"
+                ;;
+        esac
+    else
+        case "${arg}" in
+            -*)
+                die "Missing argument for option --${argnext}"
+                ;;
+        esac
+        case "${argnext}" in
+            directory)
+                directory="${arg}"
+                ;;
+            *)
+                die "The impossible has happened"
+                ;;
+        esac
+        argnext=
+    fi
+done
+[ "x${argnext}" = x ] || die "Missing argument for option --${argnext}"
+unset arg argnext
+
+[ -e ./gdb/version.in ]                                                       \
+    || die "You must run this script in the top-level GDB source directory"
+
+[ -d "${directory}" ]                                                         \
+    || die "No such directory: ${directory}"
+
+for ar in $(echo_archives)
+do
+    if [ ${force} -gt 0 ]; then rm -f "${directory}/${ar}"; fi
+    [ -e "${directory}/${ar}" ]                                               \
+        || ( cd "${directory}" && ${fetch} --no-verbose "${base_url}${ar}" )  \
+        || die "Cannot download ${ar} from ${base_url}"
+done
+unset ar
+
+if [ ${verify} -gt 0 ]
+then
+    chksumfile="contrib/prerequisites.${chksum_extension}"
+    [ -r "${chksumfile}" ] || die "No checksums available"
+    for ar in $(echo_archives)
+    do
+        grep "${ar}" "${chksumfile}"                                          \
+            | ( cd "${directory}" && ${chksum} )                              \
+            || die "Cannot verify integrity of possibly corrupted file ${ar}"
+    done
+    unset chksumfile
+fi
+unset ar
+
+for ar in $(echo_archives)
+do
+    package="${ar%.tar*}"
+    if [ ${force} -gt 0 ]; then rm -rf "${directory}/${package}"; fi
+    case $ar in
+    *.gz)
+	uncompress='gzip -d'
+	;;
+    *.bz2)
+	uncompress='bzip2 -d'
+	;;
+    *)
+	uncompress='cat'
+	;;
+    esac
+    [ -e "${directory}/${package}" ]                                          \
+        || ( cd "${directory}" && $uncompress <"${ar}" | tar -xf - )          \
+        || die "Cannot extract package from ${ar}"
+    unset package
+done
+unset ar
+
+for ar in $(echo_archives)
+do
+    target="${directory}/${ar%.tar*}/"
+    linkname="${ar%-*}"
+    if [ ${force} -gt 0 ]; then rm -f "${linkname}"; fi
+    [ -e "${linkname}" ]                                                      \
+        || ln -s "${target}" "${linkname}"                                    \
+        || die "Cannot create symbolic link ${linkname} --> ${target}"
+    unset target linkname
+done
+unset ar
+
+echo "All prerequisites downloaded successfully."
diff --git a/contrib/prerequisites.md5 b/contrib/prerequisites.md5
new file mode 100644
index 0000000..cf7be0d
--- /dev/null
+++ b/contrib/prerequisites.md5
@@ -0,0 +1,2 @@
+86ee6e54ebfc4a90b643a65e402c4048  gmp-6.1.0.tar.bz2
+b8a2f6b0e68bef46e53da2ac439e1cf4  mpfr-3.1.4.tar.bz2
diff --git a/contrib/prerequisites.sha512 b/contrib/prerequisites.sha512
new file mode 100644
index 0000000..8f05aff
--- /dev/null
+++ b/contrib/prerequisites.sha512
@@ -0,0 +1,2 @@
+3c82aeab9c1596d4da8afac2eec38e429e84f3211e1a572cf8fd2b546493c44c039b922a1133eaaa48bd7f3e11dbe795a384e21ed95cbe3ecc58d7ac02246117  gmp-6.1.0.tar.bz2
+51066066ff2c12ed2198605ecf68846b0c96b548adafa5b80e0c786d0df488411a5e8973358fce7192dc977ad4e68414cf14500e3c39746de62465eb145bb819  mpfr-3.1.4.tar.bz2
diff --git a/gdb/README b/gdb/README
index e65c5ea..db0a774 100644
--- a/gdb/README
+++ b/gdb/README
@@ -488,6 +488,9 @@ more obscure GDB `configure' options are not listed here.
      Build GDB using the GMP library installed at the directory DIR.
      If your host does not have GMP installed, you can get the latest
      version at `https://gmplib.org/'.
+     You can also build GMP in-tree when you use the script
+     ./contrib/download_prerequisites.  Note however, that this
+     does only work with a separate build directory.
 
 `--with-mpfr'
      Build GDB with GNU MPFR, a library for multiple-precision
@@ -499,6 +502,9 @@ more obscure GDB `configure' options are not listed here.
      available, GDB will fall back to using host floating-point
      arithmetic.  If your host does not have GNU MPFR installed, you
      can get the latest version from `https://www.mpfr.org/'.
+     You can also build MPFR in-tree when you use the script
+     ./contrib/download_prerequisites.  Note however, that this
+     does only work with a separate build directory.
 
 `--with-python[=PYTHON]'
      Build GDB with Python scripting support.  (Done by default if
diff --git a/gdb/configure b/gdb/configure
index 24e6fbc..67747b3 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -899,8 +899,13 @@ with_jit_reader_dir
 with_expat
 with_libexpat_prefix
 with_libexpat_type
+with_gmp_include
+with_gmp_lib
+with_gmp
 with_libgmp_prefix
 with_libgmp_type
+with_mpfr_include
+with_mpfr_lib
 with_mpfr
 with_libmpfr_prefix
 with_libmpfr_type
@@ -1644,9 +1649,14 @@ Optional Packages:
   --with-libexpat-prefix[=DIR]  search for libexpat in DIR/include and DIR/lib
   --without-libexpat-prefix     don't search for libexpat in includedir and libdir
   --with-libexpat-type=TYPE     type of library to search for (auto/static/shared)
+  --with-gmp-include=DIR  GMP include directory
+  --with-gmp-lib=DIR      GMP lib directory
+  --with-gmp=DIR          GMP install directory
   --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
   --without-libgmp-prefix     don't search for libgmp in includedir and libdir
   --with-libgmp-type=TYPE     type of library to search for (auto/static/shared)
+  --with-mpfr-include=DIR MPFR include directory
+  --with-mpfr-lib=DIR     MPFR lib directory
   --with-mpfr             include MPFR support (auto/yes/no)
   --with-libmpfr-prefix[=DIR]  search for libmpfr in DIR/include and DIR/lib
   --without-libmpfr-prefix     don't search for libmpfr in includedir and libdir
@@ -9990,6 +10000,35 @@ done
   fi
 fi
 
+
+# Check whether --with-gmp_include was given.
+if test "${with_gmp_include+set}" = set; then :
+  withval=$with_gmp_include; CPPFLAGS="$CPPFLAGS -I$withval"
+fi
+
+
+# Check whether --with-gmp_lib was given.
+if test "${with_gmp_lib+set}" = set; then :
+  withval=$with_gmp_lib; LDFLAGS="$LDFLAGS -L$withval"
+fi
+
+
+# Check whether --with-gmp was given.
+if test "${with_gmp+set}" = set; then :
+  withval=$with_gmp;
+   if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
+      CPPFLAGS="$CPPFLAGS -I$withval/include"
+      LDFLAGS="$LDFLAGS -L$withval/lib"
+   else
+      { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.
+See \`config.log' for more details" "$LINENO" 5; }
+   fi
+
+fi
+
+
 # Verify that we have a usable GMP library.
 
 
@@ -10474,6 +10513,19 @@ if test "$HAVE_LIBGMP" != yes; then
 fi
 
 
+# Check whether --with-mpfr_include was given.
+if test "${with_mpfr_include+set}" = set; then :
+  withval=$with_mpfr_include; CPPFLAGS="-I$withval $CPPFLAGS"
+fi
+
+
+# Check whether --with-mpfr_lib was given.
+if test "${with_mpfr_lib+set}" = set; then :
+  withval=$with_mpfr_lib; LDFLAGS="-L$withval $LDFLAGS"
+fi
+
+
+
 # Check whether --with-mpfr was given.
 if test "${with_mpfr+set}" = set; then :
   withval=$with_mpfr;
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 32f25d9..97f43ce 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -683,6 +683,22 @@ else
   fi
 fi
 
+AC_ARG_WITH(gmp_include,
+   [  --with-gmp-include=DIR  GMP include directory ],
+   CPPFLAGS="$CPPFLAGS -I$withval")
+AC_ARG_WITH(gmp_lib,
+   [  --with-gmp-lib=DIR      GMP lib directory ],
+   LDFLAGS="$LDFLAGS -L$withval")
+AC_ARG_WITH(gmp,
+   [  --with-gmp=DIR          GMP install directory ], [
+   if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
+      CPPFLAGS="$CPPFLAGS -I$withval/include"
+      LDFLAGS="$LDFLAGS -L$withval/lib"
+   else
+      AC_MSG_FAILURE([Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.])
+   fi
+  ])
+
 # Verify that we have a usable GMP library.
 AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
                       [mpz_t n;
@@ -691,6 +707,15 @@ if test "$HAVE_LIBGMP" != yes; then
   AC_MSG_ERROR([GMP is missing or unusable])
 fi
 
+AC_ARG_WITH([mpfr_include],
+            [AC_HELP_STRING([--with-mpfr-include=DIR],
+                            [MPFR include directory])],
+            [CPPFLAGS="-I$withval $CPPFLAGS"])
+AC_ARG_WITH([mpfr_lib],
+            [AC_HELP_STRING([--with-mpfr-lib=DIR],
+                            [MPFR lib directory])],
+            [LDFLAGS="-L$withval $LDFLAGS"])
+
 AC_ARG_WITH(mpfr,
   AS_HELP_STRING([--with-mpfr], [include MPFR support (auto/yes/no)]),
   [], [with_mpfr=auto])
-- 
1.9.1


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-14 17:40                         ` [PATCH v2] " Bernd Edlinger
@ 2020-12-14 18:47                           ` Simon Marchi
  2020-12-14 21:35                             ` Tom Tromey
  2020-12-15 15:10                             ` Bernd Edlinger
  0 siblings, 2 replies; 140+ messages in thread
From: Simon Marchi @ 2020-12-14 18:47 UTC (permalink / raw)
  To: Bernd Edlinger, Joel Brobecker, Pedro Alves, Eli Zaretskii,
	Andrew Burgess, gdb-patches

I'll give a shot at reviewing this, to make it progress.

Joel, there's a question for you below.

On 2020-12-14 12:40 p.m., Bernd Edlinger wrote:
> Well,
>
> I thought, I should add a few words in the README
> about this feature:
>
> diff --git a/gdb/README b/gdb/README
> index e65c5ea..db0a774 100644
> --- a/gdb/README
> +++ b/gdb/README
> @@ -488,6 +488,9 @@ more obscure GDB `configure' options are not listed here.
>       Build GDB using the GMP library installed at the directory DIR.
>       If your host does not have GMP installed, you can get the latest
>       version at `https://gmplib.org/'.
> +     You can also build GMP in-tree when you use the script
> +     ./contrib/download_prerequisites.  Note however, that this
> +     does only work with a separate build directory.
>
>  `--with-mpfr'
>       Build GDB with GNU MPFR, a library for multiple-precision
> @@ -499,6 +502,9 @@ more obscure GDB `configure' options are not listed here.
>       available, GDB will fall back to using host floating-point
>       arithmetic.  If your host does not have GNU MPFR installed, you
>       can get the latest version from `https://www.mpfr.org/'.
> +     You can also build MPFR in-tree when you use the script
> +     ./contrib/download_prerequisites.  Note however, that this
> +     does only work with a separate build directory.
>
>  `--with-python[=PYTHON]'
>       Build GDB with Python scripting support.  (Done by default if
>
>
> Tested on x86_64-pc-linux-gnu.
> Is it OK for trunk?
>
>
> Thanks
> Bernd.
>

There is already --with-libgmp-prefix / --without-libgmp-prefix,
provided (I think by):

    # Verify that we have a usable GMP library.
    AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
                          [mpz_t n;
                           mpz_init (n);])

So with this patch, we now have:

  --with-gmp-include=DIR  GMP include directory
  --with-gmp-lib=DIR      GMP lib directory
  --with-gmp=DIR          GMP install directory
  --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
  --without-libgmp-prefix     don't search for libgmp in includedir and libdir

I think that's getting a bit confusing.  That's too many ways to set gmp
paths, with -with-libgmp-prefix and --with-gmp doing the same thing.

If the rest of the binutils/gcc ecosystem already uses --with-gmp,
--with-gmp-include and --with-gmp-lib, I think we should align with
those.  Fortunately, we haven't yet shipped a GDB with
--with-libgmp-prefix, so I think it's safe to remove it.  It might mean
that we have to stop using AC_LIB_HAVE_LINKFLAGS though, or customize
it.  Joel, do you agree?

In this line, in top-level Makefile.def, do you need to also add
something about gmp, and why pass flags about mpc_mpfr (I sincerely
don't know what it is/does)?

  host_modules= { module= gdb;
                  extra_configure_flags='@extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@';};

In the README, you say:

     You can also build GMP in-tree when you use the script
     ./contrib/download_prerequisites.  Note however, that this
     does only work with a separate build directory.

That leaves me with some questions:

 - do I need to run this script myself before configure?
 - if I do, does that mean the build will use the downloaded version,
   even if there is a working version on my system?

It would be good to answer those questions in the README text.

An alternative to downloading the pre-requisites would be to check them
in the repo.  We do it for readline already: there is a copy in the
repo, which is used by default, but you can specify
--with-system-readline if you want to use the system's readline.  We
could do the same with gmp and mpfr.  The downside is that we deviate a
bit from how gcc does, the the upside is that it's simpler, IMO.

Note that any change to the files outside GDB will have to be approved
by the binutils folks too.  And changes to the top-level Makefile will
have to be replicated to the gcc repo.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-14 18:47                           ` Simon Marchi
@ 2020-12-14 21:35                             ` Tom Tromey
  2020-12-14 22:17                               ` Simon Marchi
  2020-12-15 15:10                             ` Bernd Edlinger
  1 sibling, 1 reply; 140+ messages in thread
From: Tom Tromey @ 2020-12-14 21:35 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Bernd Edlinger, Joel Brobecker, Pedro Alves, Eli Zaretskii,
	Andrew Burgess, gdb-patches

>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:

Simon> So with this patch, we now have:

Simon>   --with-gmp-include=DIR  GMP include directory
Simon>   --with-gmp-lib=DIR      GMP lib directory
Simon>   --with-gmp=DIR          GMP install directory
Simon>   --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
Simon>   --without-libgmp-prefix     don't search for libgmp in includedir and libdir

Simon> I think that's getting a bit confusing.  That's too many ways to set gmp
Simon> paths, with -with-libgmp-prefix and --with-gmp doing the same thing.

FWIW we have the same situation with MPFR.

Simon> It might mean that we have to stop using AC_LIB_HAVE_LINKFLAGS
Simon> though, or customize it.

Yes.  Perhaps alternatively we could promote its use to the top level.
It's maybe a pain to do that.

Simon> An alternative to downloading the pre-requisites would be to check them
Simon> in the repo.  We do it for readline already: there is a copy in the
Simon> repo, which is used by default, but you can specify
Simon> --with-system-readline if you want to use the system's readline.  We
Simon> could do the same with gmp and mpfr.  The downside is that we deviate a
Simon> bit from how gcc does, the the upside is that it's simpler, IMO.

For me the main difference here is that, historically, we've had to
patch readline.  In cases where GDB has never needed to patch a
dependency (libiconv comes to mind), we've haven't bothered.

Tom

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-14 21:35                             ` Tom Tromey
@ 2020-12-14 22:17                               ` Simon Marchi
  2020-12-15  2:33                                 ` Joel Brobecker
  2020-12-15 15:33                                 ` Bernd Edlinger
  0 siblings, 2 replies; 140+ messages in thread
From: Simon Marchi @ 2020-12-14 22:17 UTC (permalink / raw)
  To: Tom Tromey
  Cc: Bernd Edlinger, Joel Brobecker, Pedro Alves, Eli Zaretskii,
	Andrew Burgess, gdb-patches

On 2020-12-14 4:35 p.m., Tom Tromey wrote:
>>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:
>
> Simon> So with this patch, we now have:
>
> Simon>   --with-gmp-include=DIR  GMP include directory
> Simon>   --with-gmp-lib=DIR      GMP lib directory
> Simon>   --with-gmp=DIR          GMP install directory
> Simon>   --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
> Simon>   --without-libgmp-prefix     don't search for libgmp in includedir and libdir
>
> Simon> I think that's getting a bit confusing.  That's too many ways to set gmp
> Simon> paths, with -with-libgmp-prefix and --with-gmp doing the same thing.
>
> FWIW we have the same situation with MPFR.

:(
> Simon> It might mean that we have to stop using AC_LIB_HAVE_LINKFLAGS
> Simon> though, or customize it.
>
> Yes.  Perhaps alternatively we could promote its use to the top level.
> It's maybe a pain to do that.

Perhaps, but --with-{gmp,mpfr} would need to be kept as backwards
compatibility.  I think it would be hard to convince the gcc people of
the benefits of such a change.

> Simon> An alternative to downloading the pre-requisites would be to check them
> Simon> in the repo.  We do it for readline already: there is a copy in the
> Simon> repo, which is used by default, but you can specify
> Simon> --with-system-readline if you want to use the system's readline.  We
> Simon> could do the same with gmp and mpfr.  The downside is that we deviate a
> Simon> bit from how gcc does, the the upside is that it's simpler, IMO.
>
> For me the main difference here is that, historically, we've had to
> patch readline.  In cases where GDB has never needed to patch a
> dependency (libiconv comes to mind), we've haven't bothered.

Ok, when you put it like that then it doesn't make as much sense to
check the code in the repo.

Thinking about it a bit more, I don't see why gmp and mpfr get this
treatment, what is it that makes them different from other dependencies?
If you want to build GDB with XML support, you download and build expat,
or install it using your package manager.  Why can't you do the same
with mpfr/gmp?  The only reason for us I can see is "because gcc does
it" and we share the build system with gcc.  But otherwise, I'd just
tell people to build/install mpfr and gmp themselves.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-14 22:17                               ` Simon Marchi
@ 2020-12-15  2:33                                 ` Joel Brobecker
  2020-12-15 14:39                                   ` Simon Marchi
  2020-12-15 15:33                                 ` Bernd Edlinger
  1 sibling, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-12-15  2:33 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Tom Tromey, Bernd Edlinger, Pedro Alves, Eli Zaretskii,
	Andrew Burgess, gdb-patches

> >>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:
> >
> > Simon> So with this patch, we now have:
> >
> > Simon>   --with-gmp-include=DIR  GMP include directory
> > Simon>   --with-gmp-lib=DIR      GMP lib directory
> > Simon>   --with-gmp=DIR          GMP install directory
> > Simon>   --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
> > Simon>   --without-libgmp-prefix     don't search for libgmp in includedir and libdir
> >
> > Simon> I think that's getting a bit confusing.  That's too many ways to set gmp
> > Simon> paths, with -with-libgmp-prefix and --with-gmp doing the same thing.
> >
> > FWIW we have the same situation with MPFR.
> 
> :(

Yeah, my reaction exactly when Bernd made me discover this problem.
There might be other options in the same category; we should
double-check (busy this week, but I can have a look during the weekend
if noone beats me to it).

> > Simon> It might mean that we have to stop using AC_LIB_HAVE_LINKFLAGS
> > Simon> though, or customize it.
> >
> > Yes.  Perhaps alternatively we could promote its use to the top level.
> > It's maybe a pain to do that.
> 
> Perhaps, but --with-{gmp,mpfr} would need to be kept as backwards
> compatibility.  I think it would be hard to convince the gcc people of
> the benefits of such a change.

Here's a radical question: Do we really need to stay in sync with GCC,
at this point? What are the benefits and requirements of doing so?
Because GCC doesn't coordinate with us when they make changes to
the toplevel configury, we're only going to get into these problems
more.

In fact, how much does the toplevel configure really need to do?
Intuitively, it doesn't really need to do very much, if we ignore
all the stuff that's GCC-specific.

A more relevant conundrum, for me, might be to look at keeping
binutils and GDB in sync in terms of the options being used.

And then we have the question of how to provide users who want to
configure parts or all of binutils-gdb what options they can use,
and what they do. I don't know how easy we can do that via the
toplevel configure's --help. One interesting question is: Would
doing so help us avoid inconsistencies with binutils?

So, as you can see, the question is much larger than just GMP/MPFR.

> > Simon> An alternative to downloading the pre-requisites would be to check them
> > Simon> in the repo.  We do it for readline already: there is a copy in the
> > Simon> repo, which is used by default, but you can specify
> > Simon> --with-system-readline if you want to use the system's readline.  We
> > Simon> could do the same with gmp and mpfr.  The downside is that we deviate a
> > Simon> bit from how gcc does, the the upside is that it's simpler, IMO.
> >
> > For me the main difference here is that, historically, we've had to
> > patch readline.  In cases where GDB has never needed to patch a
> > dependency (libiconv comes to mind), we've haven't bothered.
> 
> Ok, when you put it like that then it doesn't make as much sense to
> check the code in the repo.
> 
> Thinking about it a bit more, I don't see why gmp and mpfr get this
> treatment, what is it that makes them different from other dependencies?
> If you want to build GDB with XML support, you download and build expat,
> or install it using your package manager.  Why can't you do the same
> with mpfr/gmp?  The only reason for us I can see is "because gcc does
> it" and we share the build system with gcc.  But otherwise, I'd just
> tell people to build/install mpfr and gmp themselves.
> 
> Simon

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 2/9] gdb: Make GMP a required dependency for building GDB
  2020-11-08  6:30 ` [PATCH 2/9] gdb: Make GMP a required dependency for building GDB Joel Brobecker
@ 2020-12-15  6:55   ` Sebastian Huber
  2020-12-15  8:57     ` Joel Brobecker
  0 siblings, 1 reply; 140+ messages in thread
From: Sebastian Huber @ 2020-12-15  6:55 UTC (permalink / raw)
  To: Joel Brobecker, gdb-patches

Hello Joel,

On 08/11/2020 07:30, Joel Brobecker wrote:
> This commit modifies gdb's configure script to trigger an error
> if we cannot find a usable libgmp.
>
> For the record, making this a requirement was discussed in March 2018:
> https://sourceware.org/pipermail/gdb-patches/2018-March/147373.html
>
> gdb/ChangeLog:
>
>          * configure.ac: Generate an error if a usable GMP library
>          could not be found.
>          * configure: Regenerate.

this new build requirement is not documented here:

https://sourceware.org/gdb/download/onlinedocs/gdb/Requirements.html#Requirements

-- 
embedded brains GmbH
Herr Sebastian HUBER
Dornierstr. 4
82178 Puchheim
Germany
email: sebastian.huber@embedded-brains.de
phone: +49-89-18 94 741 - 16
fax:   +49-89-18 94 741 - 08

Registergericht: Amtsgericht München
Registernummer: HRB 157899
Vertretungsberechtigte Geschäftsführer: Peter Rasmussen, Thomas Dörfler
Unsere Datenschutzerklärung finden Sie hier:
https://embedded-brains.de/datenschutzerklaerung/


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH 2/9] gdb: Make GMP a required dependency for building GDB
  2020-12-15  6:55   ` Sebastian Huber
@ 2020-12-15  8:57     ` Joel Brobecker
  0 siblings, 0 replies; 140+ messages in thread
From: Joel Brobecker @ 2020-12-15  8:57 UTC (permalink / raw)
  To: Sebastian Huber; +Cc: gdb-patches

> On 08/11/2020 07:30, Joel Brobecker wrote:
> > This commit modifies gdb's configure script to trigger an error
> > if we cannot find a usable libgmp.
> > 
> > For the record, making this a requirement was discussed in March 2018:
> > https://sourceware.org/pipermail/gdb-patches/2018-March/147373.html
> > 
> > gdb/ChangeLog:
> > 
> >          * configure.ac: Generate an error if a usable GMP library
> >          could not be found.
> >          * configure: Regenerate.
> 
> this new build requirement is not documented here:
> 
> https://sourceware.org/gdb/download/onlinedocs/gdb/Requirements.html#Requirements

Indeed. I will fix that over the weekend.

Thank you,

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-15  2:33                                 ` Joel Brobecker
@ 2020-12-15 14:39                                   ` Simon Marchi
  2020-12-15 16:24                                     ` Bernd Edlinger
  2020-12-16  7:33                                     ` Joel Brobecker
  0 siblings, 2 replies; 140+ messages in thread
From: Simon Marchi @ 2020-12-15 14:39 UTC (permalink / raw)
  To: Joel Brobecker, Simon Marchi
  Cc: Tom Tromey, Bernd Edlinger, Pedro Alves, Eli Zaretskii,
	Andrew Burgess, gdb-patches

On 2020-12-14 9:33 p.m., Joel Brobecker wrote:
>>> Simon> It might mean that we have to stop using AC_LIB_HAVE_LINKFLAGS
>>> Simon> though, or customize it.
>>>
>>> Yes.  Perhaps alternatively we could promote its use to the top level.
>>> It's maybe a pain to do that.
>>
>> Perhaps, but --with-{gmp,mpfr} would need to be kept as backwards
>> compatibility.  I think it would be hard to convince the gcc people of
>> the benefits of such a change.
> 
> Here's a radical question: Do we really need to stay in sync with GCC,
> at this point? What are the benefits and requirements of doing so?
> Because GCC doesn't coordinate with us when they make changes to
> the toplevel configury, we're only going to get into these problems
> more.

Indeed, it's a bit annoying that the burden of syncing is only on one
side.

What are the original reasons for staying in sync with gcc?

Instead of manually syncing files, I know Pedro already mentioned the
idea of having a single repo with binutils + gcc + gdb, a bit like
LLVM have moved to a big mono repo.  Especially with gcc being a C++
program as well, we want to share more.  So desyncing from gcc would
make such a move more difficult.  But it's just an idea at this point,
so maybe it's not that important.

Otherwise, just for convenience reasons, it would be nice to think more
of gcc + binutils + gdb (an maybe others) as a single toolchain, and
having consistency and no suprises in how you build them is a good thing
for those build and integrate them.
 
> In fact, how much does the toplevel configure really need to do?
> Intuitively, it doesn't really need to do very much, if we ignore
> all the stuff that's GCC-specific.

I know next to nothing about the top-level configure, because I never
needed to dig into it.

> A more relevant conundrum, for me, might be to look at keeping
> binutils and GDB in sync in terms of the options being used.
> 
> And then we have the question of how to provide users who want to
> configure parts or all of binutils-gdb what options they can use,
> and what they do. I don't know how easy we can do that via the
> toplevel configure's --help. One interesting question is: Would
> doing so help us avoid inconsistencies with binutils?

I'm not sure I understand.  Do you mean, how do users get to learn about
the configure switches of all projects?

All I know is that you can do "./configure --help=recursive" from the
top-level, but that's not particularly convenient, it just dumps all
the helps from all the configure scripts.  It's good if you want to
find / grep.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-14 18:47                           ` Simon Marchi
  2020-12-14 21:35                             ` Tom Tromey
@ 2020-12-15 15:10                             ` Bernd Edlinger
  1 sibling, 0 replies; 140+ messages in thread
From: Bernd Edlinger @ 2020-12-15 15:10 UTC (permalink / raw)
  To: Simon Marchi, Joel Brobecker, Pedro Alves, Eli Zaretskii,
	Andrew Burgess, gdb-patches

On 12/14/20 7:47 PM, Simon Marchi wrote:
> I'll give a shot at reviewing this, to make it progress.
> 
> Joel, there's a question for you below.
> 
> On 2020-12-14 12:40 p.m., Bernd Edlinger wrote:
>> Well,
>>
>> I thought, I should add a few words in the README
>> about this feature:
>>
>> diff --git a/gdb/README b/gdb/README
>> index e65c5ea..db0a774 100644
>> --- a/gdb/README
>> +++ b/gdb/README
>> @@ -488,6 +488,9 @@ more obscure GDB `configure' options are not listed here.
>>       Build GDB using the GMP library installed at the directory DIR.
>>       If your host does not have GMP installed, you can get the latest
>>       version at `https://gmplib.org/'.
>> +     You can also build GMP in-tree when you use the script
>> +     ./contrib/download_prerequisites.  Note however, that this
>> +     does only work with a separate build directory.
>>
>>  `--with-mpfr'
>>       Build GDB with GNU MPFR, a library for multiple-precision
>> @@ -499,6 +502,9 @@ more obscure GDB `configure' options are not listed here.
>>       available, GDB will fall back to using host floating-point
>>       arithmetic.  If your host does not have GNU MPFR installed, you
>>       can get the latest version from `https://www.mpfr.org/'.
>> +     You can also build MPFR in-tree when you use the script
>> +     ./contrib/download_prerequisites.  Note however, that this
>> +     does only work with a separate build directory.
>>
>>  `--with-python[=PYTHON]'
>>       Build GDB with Python scripting support.  (Done by default if
>>
>>
>> Tested on x86_64-pc-linux-gnu.
>> Is it OK for trunk?
>>
>>
>> Thanks
>> Bernd.
>>
> 
> There is already --with-libgmp-prefix / --without-libgmp-prefix,
> provided (I think by):
> 
>     # Verify that we have a usable GMP library.
>     AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
>                           [mpz_t n;
>                            mpz_init (n);])
> 
> So with this patch, we now have:
> 
>   --with-gmp-include=DIR  GMP include directory
>   --with-gmp-lib=DIR      GMP lib directory
>   --with-gmp=DIR          GMP install directory
>   --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
>   --without-libgmp-prefix     don't search for libgmp in includedir and libdir
> 
> I think that's getting a bit confusing.  That's too many ways to set gmp
> paths, with -with-libgmp-prefix and --with-gmp doing the same thing.
> 
> If the rest of the binutils/gcc ecosystem already uses --with-gmp,
> --with-gmp-include and --with-gmp-lib, I think we should align with
> those.  Fortunately, we haven't yet shipped a GDB with
> --with-libgmp-prefix, so I think it's safe to remove it.  It might mean
> that we have to stop using AC_LIB_HAVE_LINKFLAGS though, or customize
> it.  Joel, do you agree?
> 
> In this line, in top-level Makefile.def, do you need to also add
> something about gmp, and why pass flags about mpc_mpfr (I sincerely
> don't know what it is/does)?
> 
>   host_modules= { module= gdb;
>                   extra_configure_flags='@extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@';};
> 

Yes, the names for those macros are a bit funny :-)

I just used existing macros to make the delta smaller in the top level config.
extra_mpfr_configure_flags, are in fact the --with-gmp-include/lib parameters,
that are passed to in-tree mpfr, and

extra_mpc_mpfr_configure_flags, are the --with-mpfr-include/lib parameters,
that are passed to in-tree mpc.

I would like to rename those after merging this change and probably other
changes to the gcc repository, and finally merge the gcc changes
again to the binutils-gdb repository.

The binutils toplevel configure files are 2 years behind gcc.
But I think it is straight forward to make gdb/binutils/gcc build from
the same source tree.  I just tried this the other day, and just
had a problem with --disable-source-highlight, but 

> In the README, you say:
> 
>      You can also build GMP in-tree when you use the script
>      ./contrib/download_prerequisites.  Note however, that this
>      does only work with a separate build directory.
> 
> That leaves me with some questions:
> 
>  - do I need to run this script myself before configure?
>  - if I do, does that mean the build will use the downloaded version,
>    even if there is a working version on my system?
> 
> It would be good to answer those questions in the README text.
> 

Yes.  It is intended as a convenience, when you do not like to install
the libraries on your system, or when you build for a cross-target,
You should do that manually before configure when you would otherwise
run into a build error.  I will clarify that README text.


Bernd.

> An alternative to downloading the pre-requisites would be to check them
> in the repo.  We do it for readline already: there is a copy in the
> repo, which is used by default, but you can specify
> --with-system-readline if you want to use the system's readline.  We
> could do the same with gmp and mpfr.  The downside is that we deviate a
> bit from how gcc does, the the upside is that it's simpler, IMO.
> 
> Note that any change to the files outside GDB will have to be approved
> by the binutils folks too.  And changes to the top-level Makefile will
> have to be replicated to the gcc repo.
> 
> Simon
> 

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-14 22:17                               ` Simon Marchi
  2020-12-15  2:33                                 ` Joel Brobecker
@ 2020-12-15 15:33                                 ` Bernd Edlinger
  1 sibling, 0 replies; 140+ messages in thread
From: Bernd Edlinger @ 2020-12-15 15:33 UTC (permalink / raw)
  To: Simon Marchi, Tom Tromey
  Cc: Joel Brobecker, Pedro Alves, Eli Zaretskii, Andrew Burgess, gdb-patches

On 12/14/20 11:17 PM, Simon Marchi wrote:
> On 2020-12-14 4:35 p.m., Tom Tromey wrote:
>>>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:
>>
>> Simon> So with this patch, we now have:
>>
>> Simon>   --with-gmp-include=DIR  GMP include directory
>> Simon>   --with-gmp-lib=DIR      GMP lib directory
>> Simon>   --with-gmp=DIR          GMP install directory
>> Simon>   --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
>> Simon>   --without-libgmp-prefix     don't search for libgmp in includedir and libdir
>>
>> Simon> I think that's getting a bit confusing.  That's too many ways to set gmp
>> Simon> paths, with -with-libgmp-prefix and --with-gmp doing the same thing.
>>
>> FWIW we have the same situation with MPFR.
> 
> :(
>> Simon> It might mean that we have to stop using AC_LIB_HAVE_LINKFLAGS
>> Simon> though, or customize it.
>>
>> Yes.  Perhaps alternatively we could promote its use to the top level.
>> It's maybe a pain to do that.
> 
> Perhaps, but --with-{gmp,mpfr} would need to be kept as backwards
> compatibility.  I think it would be hard to convince the gcc people of
> the benefits of such a change.
> 
>> Simon> An alternative to downloading the pre-requisites would be to check them
>> Simon> in the repo.  We do it for readline already: there is a copy in the
>> Simon> repo, which is used by default, but you can specify
>> Simon> --with-system-readline if you want to use the system's readline.  We
>> Simon> could do the same with gmp and mpfr.  The downside is that we deviate a
>> Simon> bit from how gcc does, the the upside is that it's simpler, IMO.
>>
>> For me the main difference here is that, historically, we've had to
>> patch readline.  In cases where GDB has never needed to patch a
>> dependency (libiconv comes to mind), we've haven't bothered.
> 
> Ok, when you put it like that then it doesn't make as much sense to
> check the code in the repo.
> 
> Thinking about it a bit more, I don't see why gmp and mpfr get this
> treatment, what is it that makes them different from other dependencies?
> If you want to build GDB with XML support, you download and build expat,
> or install it using your package manager.  Why can't you do the same
> with mpfr/gmp?  The only reason for us I can see is "because gcc does
> it" and we share the build system with gcc.  But otherwise, I'd just
> tell people to build/install mpfr and gmp themselves.
> 

I think the difference, is other libraries may be missing,
but there is still a reasonable default in that case, just
when the build starts to fail completely without them, that
makes it inconvenient.


Bernd.

> Simon
> 

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-15 14:39                                   ` Simon Marchi
@ 2020-12-15 16:24                                     ` Bernd Edlinger
  2020-12-16  7:33                                     ` Joel Brobecker
  1 sibling, 0 replies; 140+ messages in thread
From: Bernd Edlinger @ 2020-12-15 16:24 UTC (permalink / raw)
  To: Simon Marchi, Joel Brobecker, Simon Marchi
  Cc: Tom Tromey, Pedro Alves, Eli Zaretskii, Andrew Burgess, gdb-patches

On 12/15/20 3:39 PM, Simon Marchi wrote:
> On 2020-12-14 9:33 p.m., Joel Brobecker wrote:
>>>> Simon> It might mean that we have to stop using AC_LIB_HAVE_LINKFLAGS
>>>> Simon> though, or customize it.
>>>>
>>>> Yes.  Perhaps alternatively we could promote its use to the top level.
>>>> It's maybe a pain to do that.
>>>
>>> Perhaps, but --with-{gmp,mpfr} would need to be kept as backwards
>>> compatibility.  I think it would be hard to convince the gcc people of
>>> the benefits of such a change.
>>
>> Here's a radical question: Do we really need to stay in sync with GCC,
>> at this point? What are the benefits and requirements of doing so?
>> Because GCC doesn't coordinate with us when they make changes to
>> the toplevel configury, we're only going to get into these problems
>> more.
> 
> Indeed, it's a bit annoying that the burden of syncing is only on one
> side.
> 
> What are the original reasons for staying in sync with gcc?
> 
> Instead of manually syncing files, I know Pedro already mentioned the
> idea of having a single repo with binutils + gcc + gdb, a bit like
> LLVM have moved to a big mono repo.  Especially with gcc being a C++
> program as well, we want to share more.  So desyncing from gcc would
> make such a move more difficult.  But it's just an idea at this point,
> so maybe it's not that important.
> 
> Otherwise, just for convenience reasons, it would be nice to think more
> of gcc + binutils + gdb (an maybe others) as a single toolchain, and
> having consistency and no suprises in how you build them is a good thing
> for those build and integrate them.
>  
>> In fact, how much does the toplevel configure really need to do?
>> Intuitively, it doesn't really need to do very much, if we ignore
>> all the stuff that's GCC-specific.
> 
> I know next to nothing about the top-level configure, because I never
> needed to dig into it.
> 

One thing, that might be useful here, is making the toplevel
configure script print an error, when GMP is not available,
instead of having the error later when gdb/configure runs.

For instance when the toplevel configure detects gcc needs
to be built, it checks the availability and correct versions if
GMP/MPFR/MPC/ISL while it does nothing when gdb is built.

My patch does not yet touch that logic, but it is probably
a next logical step.

>> A more relevant conundrum, for me, might be to look at keeping
>> binutils and GDB in sync in terms of the options being used.
>>
>> And then we have the question of how to provide users who want to
>> configure parts or all of binutils-gdb what options they can use,
>> and what they do. I don't know how easy we can do that via the
>> toplevel configure's --help. One interesting question is: Would
>> doing so help us avoid inconsistencies with binutils?
> 
> I'm not sure I understand.  Do you mean, how do users get to learn about
> the configure switches of all projects?
> 
> All I know is that you can do "./configure --help=recursive" from the
> top-level, but that's not particularly convenient, it just dumps all
> the helps from all the configure scripts.  It's good if you want to
> find / grep.
> 
> Simon
> 

Bernd.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-15 14:39                                   ` Simon Marchi
  2020-12-15 16:24                                     ` Bernd Edlinger
@ 2020-12-16  7:33                                     ` Joel Brobecker
  2020-12-16 18:16                                       ` Bernd Edlinger
  1 sibling, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2020-12-16  7:33 UTC (permalink / raw)
  To: Simon Marchi
  Cc: Simon Marchi, Tom Tromey, Bernd Edlinger, Pedro Alves,
	Eli Zaretskii, Andrew Burgess, gdb-patches

Hi Simon,

> > Here's a radical question: Do we really need to stay in sync with GCC,
> > at this point? What are the benefits and requirements of doing so?
> > Because GCC doesn't coordinate with us when they make changes to
> > the toplevel configury, we're only going to get into these problems
> > more.
> 
> Indeed, it's a bit annoying that the burden of syncing is only on one
> side.
> 
> What are the original reasons for staying in sync with gcc?

I don't know. It was like that when I first joined the project
20 years ago. I assumed it was convenient in the CVS days to
have everything under the same "roof", especially for those
who want to rebuild the works, knowing that CVS allowed partial
checkouts for those who diddn't.

> Instead of manually syncing files, I know Pedro already mentioned the
> idea of having a single repo with binutils + gcc + gdb, a bit like
> LLVM have moved to a big mono repo.  Especially with gcc being a C++
> program as well, we want to share more.  So desyncing from gcc would
> make such a move more difficult.  But it's just an idea at this point,
> so maybe it's not that important.

It'd be interesting in knowing more about what it is that we would
be sharing. GCC is absolutely huge (4.5GB), and GDB isn't bad either
(1.2GB). Both GCC and GDB move very fast, so reuniting them would be
causing a large burden both ways for everyone. If we do, I feel
it has to be for strong reasons.

> Otherwise, just for convenience reasons, it would be nice to think more
> of gcc + binutils + gdb (an maybe others) as a single toolchain, and
> having consistency and no suprises in how you build them is a good thing
> for those build and integrate them.

It would be nice, but is that a sufficiently strong reason to break
with the past?

> > In fact, how much does the toplevel configure really need to do?
> > Intuitively, it doesn't really need to do very much, if we ignore
> > all the stuff that's GCC-specific.
> 
> I know next to nothing about the top-level configure, because I never
> needed to dig into it.
> 
> > A more relevant conundrum, for me, might be to look at keeping
> > binutils and GDB in sync in terms of the options being used.
> > 
> > And then we have the question of how to provide users who want to
> > configure parts or all of binutils-gdb what options they can use,
> > and what they do. I don't know how easy we can do that via the
> > toplevel configure's --help. One interesting question is: Would
> > doing so help us avoid inconsistencies with binutils?
> 
> I'm not sure I understand.  Do you mean, how do users get to learn about
> the configure switches of all projects?
> 
> All I know is that you can do "./configure --help=recursive" from the
> top-level, but that's not particularly convenient, it just dumps all
> the helps from all the configure scripts.  It's good if you want to
> find / grep.

I didn't know that! This answers my question.

To recap where I am on this discussion: First, I need to be honest
and upfront in saying that I can't seem to be able to summon the energy
to motivate myself towards discussing reunification or even just making
GCC and binutils-gdb more consistent in the naming of the configure
options.

In fact, pending more info, I would still prefer we break the minimal
tie we have left in terms of synchronization with GCC, and use that
to help ourselves simplify and clarify, without breaking the existing
option.

In the meantime, if the group decides after discussion that the name
of the configure options in GDB for GMP are wrong, and must be changed
to follow GCC's lead, then so be it, I will change it. It'll be a bit
of a heartbreaker for me because:
  - It breaks consistency with the way we have been handling dependencies
    in GDB;
  - We won't be able to use this nice macro to implement those options,
    and will end up hand-writing them the same way toplevel configure
    does (it seems like a lot of code, although I would hope I can
    do this better and shorter).
Note that no one has complained about MPFR in the years we've had it...

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-16  7:33                                     ` Joel Brobecker
@ 2020-12-16 18:16                                       ` Bernd Edlinger
  2020-12-25 12:05                                         ` Bernd Edlinger
  0 siblings, 1 reply; 140+ messages in thread
From: Bernd Edlinger @ 2020-12-16 18:16 UTC (permalink / raw)
  To: Joel Brobecker, Simon Marchi
  Cc: Simon Marchi, Tom Tromey, Pedro Alves, Eli Zaretskii,
	Andrew Burgess, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 5450 bytes --]

On 12/16/20 8:33 AM, Joel Brobecker wrote:
> Hi Simon,
> 
>>> Here's a radical question: Do we really need to stay in sync with GCC,
>>> at this point? What are the benefits and requirements of doing so?
>>> Because GCC doesn't coordinate with us when they make changes to
>>> the toplevel configury, we're only going to get into these problems
>>> more.
>>
>> Indeed, it's a bit annoying that the burden of syncing is only on one
>> side.
>>
>> What are the original reasons for staying in sync with gcc?
> 
> I don't know. It was like that when I first joined the project
> 20 years ago. I assumed it was convenient in the CVS days to
> have everything under the same "roof", especially for those
> who want to rebuild the works, knowing that CVS allowed partial
> checkouts for those who diddn't.
> 
>> Instead of manually syncing files, I know Pedro already mentioned the
>> idea of having a single repo with binutils + gcc + gdb, a bit like
>> LLVM have moved to a big mono repo.  Especially with gcc being a C++
>> program as well, we want to share more.  So desyncing from gcc would
>> make such a move more difficult.  But it's just an idea at this point,
>> so maybe it's not that important.
> 
> It'd be interesting in knowing more about what it is that we would
> be sharing. GCC is absolutely huge (4.5GB), and GDB isn't bad either
> (1.2GB). Both GCC and GDB move very fast, so reuniting them would be
> causing a large burden both ways for everyone. If we do, I feel
> it has to be for strong reasons.
> 
>> Otherwise, just for convenience reasons, it would be nice to think more
>> of gcc + binutils + gdb (an maybe others) as a single toolchain, and
>> having consistency and no suprises in how you build them is a good thing
>> for those build and integrate them.
> 
> It would be nice, but is that a sufficiently strong reason to break
> with the past?
> 
>>> In fact, how much does the toplevel configure really need to do?
>>> Intuitively, it doesn't really need to do very much, if we ignore
>>> all the stuff that's GCC-specific.
>>
>> I know next to nothing about the top-level configure, because I never
>> needed to dig into it.
>>
>>> A more relevant conundrum, for me, might be to look at keeping
>>> binutils and GDB in sync in terms of the options being used.
>>>
>>> And then we have the question of how to provide users who want to
>>> configure parts or all of binutils-gdb what options they can use,
>>> and what they do. I don't know how easy we can do that via the
>>> toplevel configure's --help. One interesting question is: Would
>>> doing so help us avoid inconsistencies with binutils?
>>
>> I'm not sure I understand.  Do you mean, how do users get to learn about
>> the configure switches of all projects?
>>
>> All I know is that you can do "./configure --help=recursive" from the
>> top-level, but that's not particularly convenient, it just dumps all
>> the helps from all the configure scripts.  It's good if you want to
>> find / grep.
> 
> I didn't know that! This answers my question.
> 
> To recap where I am on this discussion: First, I need to be honest
> and upfront in saying that I can't seem to be able to summon the energy
> to motivate myself towards discussing reunification or even just making
> GCC and binutils-gdb more consistent in the naming of the configure
> options.
> 
> In fact, pending more info, I would still prefer we break the minimal
> tie we have left in terms of synchronization with GCC, and use that
> to help ourselves simplify and clarify, without breaking the existing
> option.
> 
> In the meantime, if the group decides after discussion that the name
> of the configure options in GDB for GMP are wrong, and must be changed
> to follow GCC's lead, then so be it, I will change it. It'll be a bit
> of a heartbreaker for me because:
>   - It breaks consistency with the way we have been handling dependencies
>     in GDB;
>   - We won't be able to use this nice macro to implement those options,
>     and will end up hand-writing them the same way toplevel configure
>     does (it seems like a lot of code, although I would hope I can
>     do this better and shorter).
> Note that no one has complained about MPFR in the years we've had it...
> 

That may be because this does not break anything if it is not available.
I for one did not notice anything before I knew that mpfr could be missing...

I looked at AC_LIB_HAVE_LINKFLAGS and I am surprised that it considers
to look for *.la/*.a/*.so at $prefix/lib directory instead of for instance
simply using pkg-config.

Using prefix/lib and prefix/include is also a bit unexpected, because that
is where I would normally expect the generated libraries from gdb to be
installed, instead of used from to build the gdb package.
And, it is also not clear if the user uses make install DESTDIR=X to install
everyting in X/prefix/..., for instance when prefix=/

So I think the configure flags for GMP can still be changed if we want, but the
AC_LIB_HAVE_LINKFLAGS-style configure flags for MPFR have already been there
for too long to simply remove them now.  But I still think that it would
be nice to be more compatible with other configures, maybe at least
understand the --with-gmp-include --with-gmp-lib where there is no equivalent
for at the moment.

However I think I found a way to fix the in-tree build issue without adding
now configure options at all.

How would you like this new patch?


Thanks
Bernd.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR.patch --]
[-- Type: text/x-patch; name="0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR.patch", Size: 15197 bytes --]

From f165e60dab1d677fe27915bb49bc897525d22a70 Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Sun, 15 Nov 2020 15:37:22 +0100
Subject: [PATCH] Enable GDB build with in-tree GMP and MPFR

With this patch GDB can be built with in-tree GMP and/or
MPFR.  This works also for cross-builds.

All that is needed, is a sym-link in the source tree,
like this:

gmp -> ../gmp-6.1.0
mpfr -> ../mpfr-3.1.4

2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* Makefile.def: Prepare for GDB build with intree GMP.
	* Makefile.in: Regenerate.

gdb:
2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* configure.ac: Detect in-tree GMP and MPFR.
	* configure: Regenerate.
	* README: Mention ./contrib/download_prerequisites.

contrib:
2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* download_prerequisites: New helper script.
	* prerequisites.md5: checksums.
	* prerequisites.sha512: checksums.
---
 Makefile.def                   |   2 +
 Makefile.in                    |   2 +
 contrib/download_prerequisites | 263 +++++++++++++++++++++++++++++++++++++++++
 contrib/prerequisites.md5      |   2 +
 contrib/prerequisites.sha512   |   2 +
 gdb/README                     |  12 ++
 gdb/configure                  |  20 +++-
 gdb/configure.ac               |  20 +++-
 8 files changed, 315 insertions(+), 8 deletions(-)
 create mode 100755 contrib/download_prerequisites
 create mode 100644 contrib/prerequisites.md5
 create mode 100644 contrib/prerequisites.sha512

diff --git a/Makefile.def b/Makefile.def
index 089e70a..b6872c9 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -391,6 +391,8 @@ dependencies = { module=all-intl; on=all-libiconv; };
 
 // Host modules specific to gdb.
 dependencies = { module=configure-gdb; on=all-intl; };
+dependencies = { module=configure-gdb; on=all-gmp; };
+dependencies = { module=configure-gdb; on=all-mpfr; };
 dependencies = { module=configure-gdb; on=configure-sim; };
 dependencies = { module=configure-gdb; on=all-bfd; };
 dependencies = { module=configure-gdb; on=all-gnulib; };
diff --git a/Makefile.in b/Makefile.in
index fe34132..ead9430 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -52449,6 +52449,8 @@ configure-libcc1: maybe-configure-gcc
 all-libcc1: maybe-all-gcc
 all-utils: maybe-all-libiberty
 configure-gdb: maybe-all-intl
+configure-gdb: maybe-all-gmp
+configure-gdb: maybe-all-mpfr
 configure-gdb: maybe-all-bfd
 configure-gdb: maybe-all-libiconv
 all-gdb: maybe-all-libiberty
diff --git a/contrib/download_prerequisites b/contrib/download_prerequisites
new file mode 100755
index 0000000..0d04030
--- /dev/null
+++ b/contrib/download_prerequisites
@@ -0,0 +1,263 @@
+#! /bin/sh
+#! -*- coding:utf-8; mode:shell-script; -*-
+
+# Download some prerequisites needed by GDB.
+# Run this from the top level of the GDB source tree and the GDB build will do
+# the right thing.  Run it with the `--help` option for more information.
+#
+# (C) 2010-2020 Free Software Foundation
+#
+# 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/.
+
+program='download_prerequisites'
+version='(unversioned)'
+
+# MAINTAINERS: If you update the package versions below, please
+# remember to also update the files `contrib/prerequisites.sha512` and
+# `contrib/prerequisites.md5` with the new checksums.
+
+gmp='gmp-6.1.0.tar.bz2'
+mpfr='mpfr-3.1.4.tar.bz2'
+
+base_url='http://gcc.gnu.org/pub/gcc/infrastructure/'
+
+echo_archives() {
+    echo "${gmp}"
+    echo "${mpfr}"
+}
+
+verify=1
+force=0
+OS=$(uname)
+
+case $OS in
+  "Darwin"|"FreeBSD"|"DragonFly"|"AIX")
+    chksum='shasum -a 512 --check'
+  ;;
+  "OpenBSD")
+    chksum='sha512 -c'
+  ;;
+  *)
+    chksum='sha512sum -c'
+  ;;
+esac
+
+if type wget > /dev/null ; then
+  fetch='wget'
+else
+  fetch='curl -LO'
+fi
+chksum_extension='sha512'
+directory='.'
+
+helptext="usage: ${program} [OPTION...]
+
+Downloads some prerequisites needed by GDB.  Run this from the top level of the
+GDB source tree and the GDB build will do the right thing.
+
+The following options are available:
+
+ --directory=DIR  download and unpack packages into DIR instead of '.'
+ --force          download again overwriting existing packages
+ --no-force       do not download existing packages again (default)
+ --verify         verify package integrity after download (default)
+ --no-verify      don't verify package integrity
+ --sha512         use SHA512 checksum to verify package integrity (default)
+ --md5            use MD5 checksum to verify package integrity
+ --help           show this text and exit
+ --version        show version information and exit
+"
+
+versiontext="${program} ${version}
+Copyright (C) 2020 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+die() {
+    echo "error: $@" >&2
+    exit 1
+}
+
+for arg in "$@"
+do
+    case "${arg}" in
+        --help)
+            echo "${helptext}"
+            exit
+            ;;
+        --version)
+            echo "${versiontext}"
+            exit
+            ;;
+    esac
+done
+unset arg
+
+# Emulate Linux's 'md5 --check' on macOS
+md5_check() {
+  # Store the standard input: a line from contrib/prerequisites.md5:
+  md5_checksum_line=$(cat -)
+  # Grab the text before the first space
+  md5_checksum_expected="${md5_checksum_line%% *}"
+  # Grab the text after the first space
+  file_to_check="${md5_checksum_line##* }"
+  # Calculate the md5 checksum for the downloaded file
+  md5_checksum_output=$(md5 -r "${file_to_check}")
+  # Grab the text before the first space
+  md5_checksum_detected="${md5_checksum_output%% *}"
+  [ "${md5_checksum_expected}" == "${md5_checksum_detected}" ] \
+    || die "Cannot verify integrity of possibly corrupted file ${file_to_check}"
+  echo "${file_to_check}: OK"
+}
+
+
+argnext=
+for arg in "$@"
+do
+    if [ "x${argnext}" = x ]
+    then
+        case "${arg}" in
+            --directory)
+                argnext='directory'
+                ;;
+            --directory=*)
+                directory="${arg#--directory=}"
+                ;;
+            --force)
+                force=1
+                ;;
+            --no-force)
+                force=0
+                ;;
+            --verify)
+                verify=1
+                ;;
+            --no-verify)
+                verify=0
+                ;;
+            --sha512)
+                case $OS in
+                  "Darwin")
+                    chksum='shasum -a 512 --check'
+                  ;;
+                  *)
+                    chksum='sha512sum --check'
+                  ;;
+                esac
+                chksum_extension='sha512'
+                verify=1
+                ;;
+            --md5)
+                case $OS in
+                  "Darwin")
+                    chksum='md5_check'
+                  ;;
+                  *)
+                    chksum='md5 --check'
+                  ;;
+                esac
+                chksum_extension='md5'
+                verify=1
+                ;;
+            -*)
+                die "unknown option: ${arg}"
+                ;;
+            *)
+                die "too many arguments"
+                ;;
+        esac
+    else
+        case "${arg}" in
+            -*)
+                die "Missing argument for option --${argnext}"
+                ;;
+        esac
+        case "${argnext}" in
+            directory)
+                directory="${arg}"
+                ;;
+            *)
+                die "The impossible has happened"
+                ;;
+        esac
+        argnext=
+    fi
+done
+[ "x${argnext}" = x ] || die "Missing argument for option --${argnext}"
+unset arg argnext
+
+[ -e ./gdb/version.in ]                                                       \
+    || die "You must run this script in the top-level GDB source directory"
+
+[ -d "${directory}" ]                                                         \
+    || die "No such directory: ${directory}"
+
+for ar in $(echo_archives)
+do
+    if [ ${force} -gt 0 ]; then rm -f "${directory}/${ar}"; fi
+    [ -e "${directory}/${ar}" ]                                               \
+        || ( cd "${directory}" && ${fetch} --no-verbose "${base_url}${ar}" )  \
+        || die "Cannot download ${ar} from ${base_url}"
+done
+unset ar
+
+if [ ${verify} -gt 0 ]
+then
+    chksumfile="contrib/prerequisites.${chksum_extension}"
+    [ -r "${chksumfile}" ] || die "No checksums available"
+    for ar in $(echo_archives)
+    do
+        grep "${ar}" "${chksumfile}"                                          \
+            | ( cd "${directory}" && ${chksum} )                              \
+            || die "Cannot verify integrity of possibly corrupted file ${ar}"
+    done
+    unset chksumfile
+fi
+unset ar
+
+for ar in $(echo_archives)
+do
+    package="${ar%.tar*}"
+    if [ ${force} -gt 0 ]; then rm -rf "${directory}/${package}"; fi
+    case $ar in
+    *.gz)
+	uncompress='gzip -d'
+	;;
+    *.bz2)
+	uncompress='bzip2 -d'
+	;;
+    *)
+	uncompress='cat'
+	;;
+    esac
+    [ -e "${directory}/${package}" ]                                          \
+        || ( cd "${directory}" && $uncompress <"${ar}" | tar -xf - )          \
+        || die "Cannot extract package from ${ar}"
+    unset package
+done
+unset ar
+
+for ar in $(echo_archives)
+do
+    target="${directory}/${ar%.tar*}/"
+    linkname="${ar%-*}"
+    if [ ${force} -gt 0 ]; then rm -f "${linkname}"; fi
+    [ -e "${linkname}" ]                                                      \
+        || ln -s "${target}" "${linkname}"                                    \
+        || die "Cannot create symbolic link ${linkname} --> ${target}"
+    unset target linkname
+done
+unset ar
+
+echo "All prerequisites downloaded successfully."
diff --git a/contrib/prerequisites.md5 b/contrib/prerequisites.md5
new file mode 100644
index 0000000..cf7be0d
--- /dev/null
+++ b/contrib/prerequisites.md5
@@ -0,0 +1,2 @@
+86ee6e54ebfc4a90b643a65e402c4048  gmp-6.1.0.tar.bz2
+b8a2f6b0e68bef46e53da2ac439e1cf4  mpfr-3.1.4.tar.bz2
diff --git a/contrib/prerequisites.sha512 b/contrib/prerequisites.sha512
new file mode 100644
index 0000000..8f05aff
--- /dev/null
+++ b/contrib/prerequisites.sha512
@@ -0,0 +1,2 @@
+3c82aeab9c1596d4da8afac2eec38e429e84f3211e1a572cf8fd2b546493c44c039b922a1133eaaa48bd7f3e11dbe795a384e21ed95cbe3ecc58d7ac02246117  gmp-6.1.0.tar.bz2
+51066066ff2c12ed2198605ecf68846b0c96b548adafa5b80e0c786d0df488411a5e8973358fce7192dc977ad4e68414cf14500e3c39746de62465eb145bb819  mpfr-3.1.4.tar.bz2
diff --git a/gdb/README b/gdb/README
index e65c5ea..2b9c382 100644
--- a/gdb/README
+++ b/gdb/README
@@ -488,6 +488,12 @@ more obscure GDB `configure' options are not listed here.
      Build GDB using the GMP library installed at the directory DIR.
      If your host does not have GMP installed, you can get the latest
      version at `https://gmplib.org/'.
+     You can also build GMP in-tree when you use the script
+     ./contrib/download_prerequisites.
+     This must be done before configure.  No --with-gmp options must
+     be used when invoking configure in this case.
+     Note however, that this does only work with a separate build
+     directory.
 
 `--with-mpfr'
      Build GDB with GNU MPFR, a library for multiple-precision
@@ -499,6 +505,12 @@ more obscure GDB `configure' options are not listed here.
      available, GDB will fall back to using host floating-point
      arithmetic.  If your host does not have GNU MPFR installed, you
      can get the latest version from `https://www.mpfr.org/'.
+     You can also build MPFR in-tree when you use the script
+     ./contrib/download_prerequisites.
+     This must be done before configure.  No --with-mpfr options must
+     be used when invoking configure in this case.
+     Note however, that this does only work with a separate build
+     directory.
 
 `--with-python[=PYTHON]'
      Build GDB with Python scripting support.  (Done by default if
diff --git a/gdb/configure b/gdb/configure
index 24e6fbc..2bf8014 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -9991,6 +9991,13 @@ done
 fi
 
 # Verify that we have a usable GMP library.
+if test -d "../gmp"; then
+  CPPFLAGS="$CPPFLAGS -I../gmp"
+  LIBGMP="../gmp/.libs/libgmp.a"
+
+$as_echo "#define HAVE_LIBGMP 1" >>confdefs.h
+
+else
 
 
 
@@ -10431,7 +10438,7 @@ int
 main ()
 {
 mpz_t n;
-                       mpz_init (n);
+                         mpz_init (n);
   ;
   return 0;
 }
@@ -10469,8 +10476,9 @@ $as_echo "$LIBGMP" >&6; }
 
 
 
-if test "$HAVE_LIBGMP" != yes; then
-  as_fn_error $? "GMP is missing or unusable" "$LINENO" 5
+  if test "$HAVE_LIBGMP" != yes; then
+    as_fn_error $? "GMP is missing or unusable" "$LINENO" 5
+  fi
 fi
 
 
@@ -10490,6 +10498,12 @@ if test "${with_mpfr}" = no; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MPFR support disabled; some features may be unavailable." >&5
 $as_echo "$as_me: WARNING: MPFR support disabled; some features may be unavailable." >&2;}
   HAVE_LIBMPFR=no
+elif test -d "../mpfr"; then
+  CPPFLAGS="$CPPFLAGS -I${srcdir}/../mpfr/src"
+  LIBMPFR="../mpfr/src/.libs/libmpfr.a"
+
+$as_echo "#define HAVE_LIBMPFR 1" >>confdefs.h
+
 else
 
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 32f25d9..376643c 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -684,11 +684,17 @@ else
 fi
 
 # Verify that we have a usable GMP library.
-AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
-                      [mpz_t n;
-                       mpz_init (n);])
-if test "$HAVE_LIBGMP" != yes; then
-  AC_MSG_ERROR([GMP is missing or unusable])
+if test -d "../gmp"; then
+  CPPFLAGS="$CPPFLAGS -I../gmp"
+  LIBGMP="../gmp/.libs/libgmp.a"
+  AC_DEFINE(HAVE_LIBGMP, 1, [Define if you have the GMP library.])
+else
+  AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
+                        [mpz_t n;
+                         mpz_init (n);])
+  if test "$HAVE_LIBGMP" != yes; then
+    AC_MSG_ERROR([GMP is missing or unusable])
+  fi
 fi
 
 AC_ARG_WITH(mpfr,
@@ -700,6 +706,10 @@ AC_MSG_RESULT([$with_mpfr])
 if test "${with_mpfr}" = no; then
   AC_MSG_WARN([MPFR support disabled; some features may be unavailable.])
   HAVE_LIBMPFR=no
+elif test -d "../mpfr"; then
+  CPPFLAGS="$CPPFLAGS -I${srcdir}/../mpfr/src"
+  LIBMPFR="../mpfr/src/.libs/libmpfr.a"
+  AC_DEFINE(HAVE_LIBMPFR, 1, [Define if you have the MPFR library.])
 else
   AC_LIB_HAVE_LINKFLAGS([mpfr], [gmp], [#include <mpfr.h>],
 			[mpfr_exp_t exp; mpfr_t x;
-- 
1.9.1


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-16 18:16                                       ` Bernd Edlinger
@ 2020-12-25 12:05                                         ` Bernd Edlinger
  2020-12-27 22:01                                           ` Simon Marchi
  0 siblings, 1 reply; 140+ messages in thread
From: Bernd Edlinger @ 2020-12-25 12:05 UTC (permalink / raw)
  To: Joel Brobecker, Simon Marchi
  Cc: Tom Tromey, Pedro Alves, Eli Zaretskii, Andrew Burgess, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 679 bytes --]

Hi everybody,

I have now two possible ways to go forward with the configure options
for gmp and mpfr.

See the attached patches:

Variant 1: implements traditional configure options
--with-gmp-include=DIR, --with-gmp-lib=DIR, --with-gmp=DIR,
--with-mpfr-include=DIR, --with-mpfr-lib=DIR, --with-mpfr=DIR
but does additionally understand --with-libmpfr-prefix=DIR
and --with-mpfr=auto/yes/no.

Variant 2: (I already posted that one) keeps all configure options
as they are now, and just uses the presence of a ../gmp and ../mpfr
directory to override the gmp and mpfr configure flags.

I would be interested in what you think, and which variant you would
prefer.


Thanks
Bernd.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR-v1.patch --]
[-- Type: text/x-patch; name="0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR-v1.patch", Size: 60440 bytes --]

From c4dfaa57bc2bfd34d4ea4f4de9148887b10150b6 Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Sun, 15 Nov 2020 15:37:22 +0100
Subject: [PATCH] Enable GDB build with in-tree GMP and MPFR

With this patch GDB can be built with in-tree GMP and/or
MPFR.  This works also for cross-builds.

All that is needed, is a sym-link in the source tree,
like this:

gmp -> ../gmp-6.1.0
mpfr -> ../mpfr-3.1.4

2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* Makefile.def: Prepare for GDB build with intree GMP.
	* Makefile.in: Regenerate.

gdb:
2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* configure.ac: Add --with-gmp=DIR, --with-gmp-include=DIR
	and --with-gmp-lib=DIR
	as well as --with-mpfr-include=DIR and --with-mpfr-lib=DIR
	for compatibility with top level configure script.
	* configure: Regenerate.
	* README: Mention ./contrib/download_prerequisites.

contrib:
2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* download_prerequisites: New helper script.
	* prerequisites.md5: checksums.
	* prerequisites.sha512: checksums.
---
 Makefile.def                   |    5 +-
 Makefile.in                    |    4 +-
 contrib/download_prerequisites |  263 ++++++++++
 contrib/prerequisites.md5      |    2 +
 contrib/prerequisites.sha512   |    2 +
 gdb/README                     |   23 +-
 gdb/configure                  | 1126 ++++++----------------------------------
 gdb/configure.ac               |   88 +++-
 8 files changed, 522 insertions(+), 991 deletions(-)
 create mode 100755 contrib/download_prerequisites
 create mode 100644 contrib/prerequisites.md5
 create mode 100644 contrib/prerequisites.sha512

diff --git a/Makefile.def b/Makefile.def
index 089e70a..1b99b42 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -115,7 +115,8 @@ host_modules= { module= zlib; no_install=true; no_check=true;
 host_modules= { module= gnulib; };
 host_modules= { module= gdbsupport; };
 host_modules= { module= gdbserver; };
-host_modules= { module= gdb; };
+host_modules= { module= gdb;
+		extra_configure_flags='@extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@';};
 host_modules= { module= expect; };
 host_modules= { module= guile; };
 host_modules= { module= tk; };
@@ -391,6 +392,8 @@ dependencies = { module=all-intl; on=all-libiconv; };
 
 // Host modules specific to gdb.
 dependencies = { module=configure-gdb; on=all-intl; };
+dependencies = { module=configure-gdb; on=all-gmp; };
+dependencies = { module=configure-gdb; on=all-mpfr; };
 dependencies = { module=configure-gdb; on=configure-sim; };
 dependencies = { module=configure-gdb; on=all-bfd; };
 dependencies = { module=configure-gdb; on=all-gnulib; };
diff --git a/Makefile.in b/Makefile.in
index fe34132..738fd32 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -29491,7 +29491,7 @@ configure-gdb:
 	  $$s/$$module_srcdir/configure \
 	  --srcdir=$${topdir}/$$module_srcdir \
 	  $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
-	  --target=${target_alias}  \
+	  --target=${target_alias} @extra_mpfr_configure_flags@ @extra_mpc_mpfr_configure_flags@ \
 	  || exit 1
 @endif gdb
 
@@ -52449,6 +52449,8 @@ configure-libcc1: maybe-configure-gcc
 all-libcc1: maybe-all-gcc
 all-utils: maybe-all-libiberty
 configure-gdb: maybe-all-intl
+configure-gdb: maybe-all-gmp
+configure-gdb: maybe-all-mpfr
 configure-gdb: maybe-all-bfd
 configure-gdb: maybe-all-libiconv
 all-gdb: maybe-all-libiberty
diff --git a/contrib/download_prerequisites b/contrib/download_prerequisites
new file mode 100755
index 0000000..0d04030
--- /dev/null
+++ b/contrib/download_prerequisites
@@ -0,0 +1,263 @@
+#! /bin/sh
+#! -*- coding:utf-8; mode:shell-script; -*-
+
+# Download some prerequisites needed by GDB.
+# Run this from the top level of the GDB source tree and the GDB build will do
+# the right thing.  Run it with the `--help` option for more information.
+#
+# (C) 2010-2020 Free Software Foundation
+#
+# 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/.
+
+program='download_prerequisites'
+version='(unversioned)'
+
+# MAINTAINERS: If you update the package versions below, please
+# remember to also update the files `contrib/prerequisites.sha512` and
+# `contrib/prerequisites.md5` with the new checksums.
+
+gmp='gmp-6.1.0.tar.bz2'
+mpfr='mpfr-3.1.4.tar.bz2'
+
+base_url='http://gcc.gnu.org/pub/gcc/infrastructure/'
+
+echo_archives() {
+    echo "${gmp}"
+    echo "${mpfr}"
+}
+
+verify=1
+force=0
+OS=$(uname)
+
+case $OS in
+  "Darwin"|"FreeBSD"|"DragonFly"|"AIX")
+    chksum='shasum -a 512 --check'
+  ;;
+  "OpenBSD")
+    chksum='sha512 -c'
+  ;;
+  *)
+    chksum='sha512sum -c'
+  ;;
+esac
+
+if type wget > /dev/null ; then
+  fetch='wget'
+else
+  fetch='curl -LO'
+fi
+chksum_extension='sha512'
+directory='.'
+
+helptext="usage: ${program} [OPTION...]
+
+Downloads some prerequisites needed by GDB.  Run this from the top level of the
+GDB source tree and the GDB build will do the right thing.
+
+The following options are available:
+
+ --directory=DIR  download and unpack packages into DIR instead of '.'
+ --force          download again overwriting existing packages
+ --no-force       do not download existing packages again (default)
+ --verify         verify package integrity after download (default)
+ --no-verify      don't verify package integrity
+ --sha512         use SHA512 checksum to verify package integrity (default)
+ --md5            use MD5 checksum to verify package integrity
+ --help           show this text and exit
+ --version        show version information and exit
+"
+
+versiontext="${program} ${version}
+Copyright (C) 2020 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+die() {
+    echo "error: $@" >&2
+    exit 1
+}
+
+for arg in "$@"
+do
+    case "${arg}" in
+        --help)
+            echo "${helptext}"
+            exit
+            ;;
+        --version)
+            echo "${versiontext}"
+            exit
+            ;;
+    esac
+done
+unset arg
+
+# Emulate Linux's 'md5 --check' on macOS
+md5_check() {
+  # Store the standard input: a line from contrib/prerequisites.md5:
+  md5_checksum_line=$(cat -)
+  # Grab the text before the first space
+  md5_checksum_expected="${md5_checksum_line%% *}"
+  # Grab the text after the first space
+  file_to_check="${md5_checksum_line##* }"
+  # Calculate the md5 checksum for the downloaded file
+  md5_checksum_output=$(md5 -r "${file_to_check}")
+  # Grab the text before the first space
+  md5_checksum_detected="${md5_checksum_output%% *}"
+  [ "${md5_checksum_expected}" == "${md5_checksum_detected}" ] \
+    || die "Cannot verify integrity of possibly corrupted file ${file_to_check}"
+  echo "${file_to_check}: OK"
+}
+
+
+argnext=
+for arg in "$@"
+do
+    if [ "x${argnext}" = x ]
+    then
+        case "${arg}" in
+            --directory)
+                argnext='directory'
+                ;;
+            --directory=*)
+                directory="${arg#--directory=}"
+                ;;
+            --force)
+                force=1
+                ;;
+            --no-force)
+                force=0
+                ;;
+            --verify)
+                verify=1
+                ;;
+            --no-verify)
+                verify=0
+                ;;
+            --sha512)
+                case $OS in
+                  "Darwin")
+                    chksum='shasum -a 512 --check'
+                  ;;
+                  *)
+                    chksum='sha512sum --check'
+                  ;;
+                esac
+                chksum_extension='sha512'
+                verify=1
+                ;;
+            --md5)
+                case $OS in
+                  "Darwin")
+                    chksum='md5_check'
+                  ;;
+                  *)
+                    chksum='md5 --check'
+                  ;;
+                esac
+                chksum_extension='md5'
+                verify=1
+                ;;
+            -*)
+                die "unknown option: ${arg}"
+                ;;
+            *)
+                die "too many arguments"
+                ;;
+        esac
+    else
+        case "${arg}" in
+            -*)
+                die "Missing argument for option --${argnext}"
+                ;;
+        esac
+        case "${argnext}" in
+            directory)
+                directory="${arg}"
+                ;;
+            *)
+                die "The impossible has happened"
+                ;;
+        esac
+        argnext=
+    fi
+done
+[ "x${argnext}" = x ] || die "Missing argument for option --${argnext}"
+unset arg argnext
+
+[ -e ./gdb/version.in ]                                                       \
+    || die "You must run this script in the top-level GDB source directory"
+
+[ -d "${directory}" ]                                                         \
+    || die "No such directory: ${directory}"
+
+for ar in $(echo_archives)
+do
+    if [ ${force} -gt 0 ]; then rm -f "${directory}/${ar}"; fi
+    [ -e "${directory}/${ar}" ]                                               \
+        || ( cd "${directory}" && ${fetch} --no-verbose "${base_url}${ar}" )  \
+        || die "Cannot download ${ar} from ${base_url}"
+done
+unset ar
+
+if [ ${verify} -gt 0 ]
+then
+    chksumfile="contrib/prerequisites.${chksum_extension}"
+    [ -r "${chksumfile}" ] || die "No checksums available"
+    for ar in $(echo_archives)
+    do
+        grep "${ar}" "${chksumfile}"                                          \
+            | ( cd "${directory}" && ${chksum} )                              \
+            || die "Cannot verify integrity of possibly corrupted file ${ar}"
+    done
+    unset chksumfile
+fi
+unset ar
+
+for ar in $(echo_archives)
+do
+    package="${ar%.tar*}"
+    if [ ${force} -gt 0 ]; then rm -rf "${directory}/${package}"; fi
+    case $ar in
+    *.gz)
+	uncompress='gzip -d'
+	;;
+    *.bz2)
+	uncompress='bzip2 -d'
+	;;
+    *)
+	uncompress='cat'
+	;;
+    esac
+    [ -e "${directory}/${package}" ]                                          \
+        || ( cd "${directory}" && $uncompress <"${ar}" | tar -xf - )          \
+        || die "Cannot extract package from ${ar}"
+    unset package
+done
+unset ar
+
+for ar in $(echo_archives)
+do
+    target="${directory}/${ar%.tar*}/"
+    linkname="${ar%-*}"
+    if [ ${force} -gt 0 ]; then rm -f "${linkname}"; fi
+    [ -e "${linkname}" ]                                                      \
+        || ln -s "${target}" "${linkname}"                                    \
+        || die "Cannot create symbolic link ${linkname} --> ${target}"
+    unset target linkname
+done
+unset ar
+
+echo "All prerequisites downloaded successfully."
diff --git a/contrib/prerequisites.md5 b/contrib/prerequisites.md5
new file mode 100644
index 0000000..cf7be0d
--- /dev/null
+++ b/contrib/prerequisites.md5
@@ -0,0 +1,2 @@
+86ee6e54ebfc4a90b643a65e402c4048  gmp-6.1.0.tar.bz2
+b8a2f6b0e68bef46e53da2ac439e1cf4  mpfr-3.1.4.tar.bz2
diff --git a/contrib/prerequisites.sha512 b/contrib/prerequisites.sha512
new file mode 100644
index 0000000..8f05aff
--- /dev/null
+++ b/contrib/prerequisites.sha512
@@ -0,0 +1,2 @@
+3c82aeab9c1596d4da8afac2eec38e429e84f3211e1a572cf8fd2b546493c44c039b922a1133eaaa48bd7f3e11dbe795a384e21ed95cbe3ecc58d7ac02246117  gmp-6.1.0.tar.bz2
+51066066ff2c12ed2198605ecf68846b0c96b548adafa5b80e0c786d0df488411a5e8973358fce7192dc977ad4e68414cf14500e3c39746de62465eb145bb819  mpfr-3.1.4.tar.bz2
diff --git a/gdb/README b/gdb/README
index e65c5ea..2146d80 100644
--- a/gdb/README
+++ b/gdb/README
@@ -484,21 +484,32 @@ more obscure GDB `configure' options are not listed here.
      not have liblzma installed, you can get the latest version from
      `https://tukaani.org/xz/'.
 
-`--with-libgmp-prefix=DIR'
+`--with-gmp=DIR'
      Build GDB using the GMP library installed at the directory DIR.
      If your host does not have GMP installed, you can get the latest
      version at `https://gmplib.org/'.
-
-`--with-mpfr'
-     Build GDB with GNU MPFR, a library for multiple-precision
-     floating-point computation with correct rounding.  (Done by
-     default if GNU MPFR is installed and found at configure time.)
+     You can also build GMP in-tree when you use the script
+     ./contrib/download_prerequisites.
+     This must be done before configure.  No --with-gmp options must
+     be used when invoking configure in this case.
+     Note however, that this does only work with a separate build
+     directory.
+
+`--with-mpfr=DIR (or auto/yes/no)'
+     Build GDB with GNU MPFR installed at the directory DIR.
+     For backward compatibility also DIR=auto/yes/no may be used.
      This library is used to emulate target floating-point arithmetic
      during expression evaluation when the target uses different
      floating-point formats than the host.  If GNU MPFR is not
      available, GDB will fall back to using host floating-point
      arithmetic.  If your host does not have GNU MPFR installed, you
      can get the latest version from `https://www.mpfr.org/'.
+     You can also build MPFR in-tree when you use the script
+     ./contrib/download_prerequisites.
+     This must be done before configure.  No --with-mpfr options must
+     be used when invoking configure in this case.
+     Note however, that this does only work with a separate build
+     directory.
 
 `--with-python[=PYTHON]'
      Build GDB with Python scripting support.  (Done by default if
diff --git a/gdb/configure b/gdb/configure
index 51b4d19..92e4b4d 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -729,12 +729,8 @@ PYTHON_LIBS
 PYTHON_CPPFLAGS
 PYTHON_CFLAGS
 python_prog_path
-LTLIBMPFR
 LIBMPFR
-HAVE_LIBMPFR
-LTLIBGMP
 LIBGMP
-HAVE_LIBGMP
 LTLIBEXPAT
 LIBEXPAT
 HAVE_LIBEXPAT
@@ -899,11 +895,13 @@ with_jit_reader_dir
 with_expat
 with_libexpat_prefix
 with_libexpat_type
-with_libgmp_prefix
-with_libgmp_type
-with_mpfr
+with_gmp_include
+with_gmp_lib
+with_gmp
 with_libmpfr_prefix
-with_libmpfr_type
+with_mpfr_include
+with_mpfr_lib
+with_mpfr
 with_python
 with_python_libdir
 with_guile
@@ -1644,13 +1642,14 @@ Optional Packages:
   --with-libexpat-prefix[=DIR]  search for libexpat in DIR/include and DIR/lib
   --without-libexpat-prefix     don't search for libexpat in includedir and libdir
   --with-libexpat-type=TYPE     type of library to search for (auto/static/shared)
-  --with-libgmp-prefix[=DIR]  search for libgmp in DIR/include and DIR/lib
-  --without-libgmp-prefix     don't search for libgmp in includedir and libdir
-  --with-libgmp-type=TYPE     type of library to search for (auto/static/shared)
-  --with-mpfr             include MPFR support (auto/yes/no)
-  --with-libmpfr-prefix[=DIR]  search for libmpfr in DIR/include and DIR/lib
-  --without-libmpfr-prefix     don't search for libmpfr in includedir and libdir
-  --with-libmpfr-type=TYPE     type of library to search for (auto/static/shared)
+  --with-gmp-include=DIR  GMP include directory
+  --with-gmp-lib=DIR      GMP lib directory
+  --with-gmp=DIR          GMP install directory
+  --with-libmpfr-prefix=DIR
+                          this option has been DEPRECATED
+  --with-mpfr-include=DIR MPFR include directory
+  --with-mpfr-lib=DIR     MPFR lib directory
+  --with-mpfr=DIR         MFPR install directory (or auto/yes/no)
   --with-python[=PYTHON]  include python support
                           (auto/yes/no/<python-program>)
   --with-python-libdir[=DIR]
@@ -9990,994 +9989,175 @@ done
   fi
 fi
 
-# Verify that we have a usable GMP library.
 
+# Check whether --with-gmp_include was given.
+if test "${with_gmp_include+set}" = set; then :
+  withval=$with_gmp_include; CPPFLAGS="$CPPFLAGS -I$withval"
+fi
 
 
+# Check whether --with-gmp_lib was given.
+if test "${with_gmp_lib+set}" = set; then :
+  withval=$with_gmp_lib; LIBGMP="-L$withval"
+fi
 
 
+# Check whether --with-gmp was given.
+if test "${with_gmp+set}" = set; then :
+  withval=$with_gmp;
+  if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
+    CPPFLAGS="$CPPFLAGS -I$withval/include"
+    LIBGMP="-L$withval/lib"
+  else
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
 
+fi
 
 
-    use_additional=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GMP" >&5
+$as_echo_n "checking for GMP... " >&6; }
+# Verify that we have a usable GMP library.
+save_LIBS=$LIBS
+LIBS="$LIBS $LIBGMP -lgmp"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <gmp.h>
+int
+main ()
+{
+mpz_t n;
+	     mpz_init (n);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  HAVE_LIBGMP=yes
+else
+  HAVE_LIBGMP=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$save_LIBS
+if test "$HAVE_LIBGMP" != yes; then
+  as_fn_error $? "GMP is missing or unusable" "$LINENO" 5
+fi
+LIBGMP="$LIBGMP -lgmp"
 
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
 
-    eval additional_includedir=\"$includedir\"
-    eval additional_libdir=\"$libdir\"
+$as_echo "#define HAVE_LIBGMP 1" >>confdefs.h
 
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_LIBGMP" >&5
+$as_echo "$HAVE_LIBGMP" >&6; }
 
 
-# Check whether --with-libgmp-prefix was given.
-if test "${with_libgmp_prefix+set}" = set; then :
-  withval=$with_libgmp_prefix;
-    if test "X$withval" = "Xno"; then
-      use_additional=no
-    else
-      if test "X$withval" = "X"; then
+# Check whether --with-libmpfr_prefix was given.
+if test "${with_libmpfr_prefix+set}" = set; then :
+  withval=$with_libmpfr_prefix;
+  if test -z "$with_mpfr" ; then
+    with_mpfr="auto"
+  fi
+  if test x"$with_mpfr" != xauto && test x"$with_mpfr" != xyes && test x"$with_mpfr" != xno ; then
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Do not use --with-mpfr=DIR and --with-libmpfr-prefix=DIR options simultaneously.
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
 
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
+fi
 
-          eval additional_includedir=\"$includedir\"
-          eval additional_libdir=\"$libdir\"
+save_CPPFLAGS=$CPPFLAGS
 
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
+# Check whether --with-mpfr_include was given.
+if test "${with_mpfr_include+set}" = set; then :
+  withval=$with_mpfr_include; CPPFLAGS="$CPPFLAGS -I$withval"
+fi
 
-      else
-        additional_includedir="$withval/include"
-        additional_libdir="$withval/lib"
+
+# Check whether --with-mpfr_lib was given.
+if test "${with_mpfr_lib+set}" = set; then :
+  withval=$with_mpfr_lib; LIBMPFR="-L$withval"
+fi
+
+
+# Check whether --with-mpfr was given.
+if test "${with_mpfr+set}" = set; then :
+  withval=$with_mpfr;
+  if test -n "$with_libmpfr_prefix" ; then
+    withval=$with_libmpfr_prefix
+  fi
+  if test -z "$with_mpfr_lib" && test -z "$with_mpfr_include" ; then
+    if test x"$withval" != xauto && test x"$withval" != xyes && test x"$withval" != xno ; then
+      CPPFLAGS="$CPPFLAGS -I$withval/include"
+      LIBMPFR="-L$withval/lib"
+      if test -z "$with_libmpfr_prefix" ; then
+	with_mpfr=yes
       fi
     fi
+  else
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Do not use --with-mpfr and --with-mpfr-include/--with-mpfr-lib options simultaneously.
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
 
 fi
 
 
-# Check whether --with-libgmp-type was given.
-if test "${with_libgmp_type+set}" = set; then :
-  withval=$with_libgmp_type;  with_libgmp_type=$withval
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use MPFR" >&5
+$as_echo_n "checking whether to use MPFR... " >&6; }
+if test "${with_mpfr}" = no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MPFR support disabled; some features may be unavailable." >&5
+$as_echo "$as_me: WARNING: MPFR support disabled; some features may be unavailable." >&2;}
+  HAVE_LIBMPFR=no
+  LIBMPFR=
+  CPPFLAGS=$save_CPPFLAGS
+else
+  save_LIBS=$LIBS
+  LIBS="$LIBS $LIBMPFR -lmpfr $LIBGMP"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <mpfr.h>
+int
+main ()
+{
+mpfr_exp_t exp; mpfr_t x;
+	       mpfr_frexp (&exp, x, x, MPFR_RNDN);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  HAVE_LIBMPFR=yes
 else
-   with_libgmp_type=auto
+  HAVE_LIBMPFR=no
 fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  LIBS=$save_LIBS
+  if test "$HAVE_LIBMPFR" != yes; then
+    if test "$with_mpfr" = yes; then
+      as_fn_error $? "MPFR is missing or unusable" "$LINENO" 5
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MPFR is missing or unusable; some features may be unavailable." >&5
+$as_echo "$as_me: WARNING: MPFR is missing or unusable; some features may be unavailable." >&2;}
+    fi
+    LIBMPFR=
+    CPPFLAGS=$save_CPPFLAGS
+  else
+    LIBMPFR="$LIBMPFR -lmpfr"
 
-  lib_type=`eval echo \$with_libgmp_type`
-
-      LIBGMP=
-  LTLIBGMP=
-  INCGMP=
-  rpathdirs=
-  ltrpathdirs=
-  names_already_handled=
-  names_next_round='gmp '
-  while test -n "$names_next_round"; do
-    names_this_round="$names_next_round"
-    names_next_round=
-    for name in $names_this_round; do
-      already_handled=
-      for n in $names_already_handled; do
-        if test "$n" = "$name"; then
-          already_handled=yes
-          break
-        fi
-      done
-      if test -z "$already_handled"; then
-        names_already_handled="$names_already_handled $name"
-                        uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
-        eval value=\"\$HAVE_LIB$uppername\"
-        if test -n "$value"; then
-          if test "$value" = yes; then
-            eval value=\"\$LIB$uppername\"
-            test -z "$value" || LIBGMP="${LIBGMP}${LIBGMP:+ }$value"
-            eval value=\"\$LTLIB$uppername\"
-            test -z "$value" || LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }$value"
-          else
-                                    :
-          fi
-        else
-                              found_dir=
-          found_la=
-          found_so=
-          found_a=
-          if test $use_additional = yes; then
-            if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext" && test x$lib_type != xstatic; then
-              found_dir="$additional_libdir"
-              found_so="$additional_libdir/lib$name.$shlibext"
-              if test -f "$additional_libdir/lib$name.la"; then
-                found_la="$additional_libdir/lib$name.la"
-              fi
-            elif test x$lib_type != xshared; then
-              if test -f "$additional_libdir/lib$name.$libext"; then
-                found_dir="$additional_libdir"
-                found_a="$additional_libdir/lib$name.$libext"
-                if test -f "$additional_libdir/lib$name.la"; then
-                  found_la="$additional_libdir/lib$name.la"
-                fi
-              fi
-            fi
-          fi
-          if test "X$found_dir" = "X"; then
-            for x in $LDFLAGS $LTLIBGMP; do
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-              case "$x" in
-                -L*)
-                  dir=`echo "X$x" | sed -e 's/^X-L//'`
-                  if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext" && test x$lib_type != xstatic; then
-                    found_dir="$dir"
-                    found_so="$dir/lib$name.$shlibext"
-                    if test -f "$dir/lib$name.la"; then
-                      found_la="$dir/lib$name.la"
-                    fi
-                  elif test x$lib_type != xshared; then
-                    if test -f "$dir/lib$name.$libext"; then
-                      found_dir="$dir"
-                      found_a="$dir/lib$name.$libext"
-                      if test -f "$dir/lib$name.la"; then
-                        found_la="$dir/lib$name.la"
-                      fi
-                    fi
-                  fi
-                  ;;
-              esac
-              if test "X$found_dir" != "X"; then
-                break
-              fi
-            done
-          fi
-          if test "X$found_dir" != "X"; then
-                        LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-L$found_dir -l$name"
-            if test "X$found_so" != "X"; then
-                                                        if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
-                                LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
-              else
-                                                                                haveit=
-                for x in $ltrpathdirs; do
-                  if test "X$x" = "X$found_dir"; then
-                    haveit=yes
-                    break
-                  fi
-                done
-                if test -z "$haveit"; then
-                  ltrpathdirs="$ltrpathdirs $found_dir"
-                fi
-                                if test "$hardcode_direct" = yes; then
-                                                      LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
-                else
-                  if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
-                                                            LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
-                                                            haveit=
-                    for x in $rpathdirs; do
-                      if test "X$x" = "X$found_dir"; then
-                        haveit=yes
-                        break
-                      fi
-                    done
-                    if test -z "$haveit"; then
-                      rpathdirs="$rpathdirs $found_dir"
-                    fi
-                  else
-                                                                                haveit=
-                    for x in $LDFLAGS $LIBGMP; do
 
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
+$as_echo "#define HAVE_LIBMPFR 1" >>confdefs.h
 
-                      if test "X$x" = "X-L$found_dir"; then
-                        haveit=yes
-                        break
-                      fi
-                    done
-                    if test -z "$haveit"; then
-                      LIBGMP="${LIBGMP}${LIBGMP:+ }-L$found_dir"
-                    fi
-                    if test "$hardcode_minus_L" != no; then
-                                                                                        LIBGMP="${LIBGMP}${LIBGMP:+ }$found_so"
-                    else
-                                                                                                                                                                                LIBGMP="${LIBGMP}${LIBGMP:+ }-l$name"
-                    fi
-                  fi
-                fi
-              fi
-            else
-              if test "X$found_a" != "X"; then
-                                LIBGMP="${LIBGMP}${LIBGMP:+ }$found_a"
-              else
-                                                LIBGMP="${LIBGMP}${LIBGMP:+ }-L$found_dir -l$name"
-              fi
-            fi
-                        additional_includedir=
-            case "$found_dir" in
-              */lib | */lib/)
-                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
-                additional_includedir="$basedir/include"
-                ;;
-            esac
-            if test "X$additional_includedir" != "X"; then
-                                                                                                                if test "X$additional_includedir" != "X/usr/include"; then
-                haveit=
-                if test "X$additional_includedir" = "X/usr/local/include"; then
-                  if test -n "$GCC"; then
-                    case $host_os in
-                      linux*) haveit=yes;;
-                    esac
-                  fi
-                fi
-                if test -z "$haveit"; then
-                  for x in $CPPFLAGS $INCGMP; do
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-                    if test "X$x" = "X-I$additional_includedir"; then
-                      haveit=yes
-                      break
-                    fi
-                  done
-                  if test -z "$haveit"; then
-                    if test -d "$additional_includedir"; then
-                                            INCGMP="${INCGMP}${INCGMP:+ }-I$additional_includedir"
-                    fi
-                  fi
-                fi
-              fi
-            fi
-                        if test -n "$found_la"; then
-                                                        save_libdir="$libdir"
-              case "$found_la" in
-                */* | *\\*) . "$found_la" ;;
-                *) . "./$found_la" ;;
-              esac
-              libdir="$save_libdir"
-                            for dep in $dependency_libs; do
-                case "$dep" in
-                  -L*)
-                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
-                                                                                                                                                                if test "X$additional_libdir" != "X/usr/lib"; then
-                      haveit=
-                      if test "X$additional_libdir" = "X/usr/local/lib"; then
-                        if test -n "$GCC"; then
-                          case $host_os in
-                            linux*) haveit=yes;;
-                          esac
-                        fi
-                      fi
-                      if test -z "$haveit"; then
-                        haveit=
-                        for x in $LDFLAGS $LIBGMP; do
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-                          if test "X$x" = "X-L$additional_libdir"; then
-                            haveit=yes
-                            break
-                          fi
-                        done
-                        if test -z "$haveit"; then
-                          if test -d "$additional_libdir"; then
-                                                        LIBGMP="${LIBGMP}${LIBGMP:+ }-L$additional_libdir"
-                          fi
-                        fi
-                        haveit=
-                        for x in $LDFLAGS $LTLIBGMP; do
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-                          if test "X$x" = "X-L$additional_libdir"; then
-                            haveit=yes
-                            break
-                          fi
-                        done
-                        if test -z "$haveit"; then
-                          if test -d "$additional_libdir"; then
-                                                        LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-L$additional_libdir"
-                          fi
-                        fi
-                      fi
-                    fi
-                    ;;
-                  -R*)
-                    dir=`echo "X$dep" | sed -e 's/^X-R//'`
-                    if test "$enable_rpath" != no; then
-                                                                  haveit=
-                      for x in $rpathdirs; do
-                        if test "X$x" = "X$dir"; then
-                          haveit=yes
-                          break
-                        fi
-                      done
-                      if test -z "$haveit"; then
-                        rpathdirs="$rpathdirs $dir"
-                      fi
-                                                                  haveit=
-                      for x in $ltrpathdirs; do
-                        if test "X$x" = "X$dir"; then
-                          haveit=yes
-                          break
-                        fi
-                      done
-                      if test -z "$haveit"; then
-                        ltrpathdirs="$ltrpathdirs $dir"
-                      fi
-                    fi
-                    ;;
-                  -l*)
-                                        names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
-                    ;;
-                  *.la)
-                                                                                names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
-                    ;;
-                  *)
-                                        LIBGMP="${LIBGMP}${LIBGMP:+ }$dep"
-                    LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }$dep"
-                    ;;
-                esac
-              done
-            fi
-          else
-                                                            if test "x$lib_type" = "xauto" || test "x$lib_type" = "xshared"; then
-              LIBGMP="${LIBGMP}${LIBGMP:+ }-l$name"
-              LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-l$name"
-            else
-              LIBGMP="${LIBGMP}${LIBGMP:+ }-l:lib$name.$libext"
-              LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-l:lib$name.$libext"
-            fi
-          fi
-        fi
-      fi
-    done
-  done
-  if test "X$rpathdirs" != "X"; then
-    if test -n "$hardcode_libdir_separator"; then
-                        alldirs=
-      for found_dir in $rpathdirs; do
-        alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
-      done
-            acl_save_libdir="$libdir"
-      libdir="$alldirs"
-      eval flag=\"$hardcode_libdir_flag_spec\"
-      libdir="$acl_save_libdir"
-      LIBGMP="${LIBGMP}${LIBGMP:+ }$flag"
-    else
-            for found_dir in $rpathdirs; do
-        acl_save_libdir="$libdir"
-        libdir="$found_dir"
-        eval flag=\"$hardcode_libdir_flag_spec\"
-        libdir="$acl_save_libdir"
-        LIBGMP="${LIBGMP}${LIBGMP:+ }$flag"
-      done
-    fi
-  fi
-  if test "X$ltrpathdirs" != "X"; then
-            for found_dir in $ltrpathdirs; do
-      LTLIBGMP="${LTLIBGMP}${LTLIBGMP:+ }-R$found_dir"
-    done
-  fi
-
-
-        ac_save_CPPFLAGS="$CPPFLAGS"
-
-  for element in $INCGMP; do
-    haveit=
-    for x in $CPPFLAGS; do
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-      if test "X$x" = "X$element"; then
-        haveit=yes
-        break
-      fi
-    done
-    if test -z "$haveit"; then
-      CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
-    fi
-  done
-
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libgmp" >&5
-$as_echo_n "checking for libgmp... " >&6; }
-if ${ac_cv_libgmp+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-
-    ac_save_LIBS="$LIBS"
-    LIBS="$LIBS $LIBGMP"
-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <gmp.h>
-int
-main ()
-{
-mpz_t n;
-                       mpz_init (n);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_libgmp=yes
-else
-  ac_cv_libgmp=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-    LIBS="$ac_save_LIBS"
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libgmp" >&5
-$as_echo "$ac_cv_libgmp" >&6; }
-  if test "$ac_cv_libgmp" = yes; then
-    HAVE_LIBGMP=yes
-
-$as_echo "#define HAVE_LIBGMP 1" >>confdefs.h
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libgmp" >&5
-$as_echo_n "checking how to link with libgmp... " >&6; }
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBGMP" >&5
-$as_echo "$LIBGMP" >&6; }
-  else
-    HAVE_LIBGMP=no
-            CPPFLAGS="$ac_save_CPPFLAGS"
-    LIBGMP=
-    LTLIBGMP=
-  fi
-
-
-
-
-
-
-if test "$HAVE_LIBGMP" != yes; then
-  as_fn_error $? "GMP is missing or unusable" "$LINENO" 5
-fi
-
-
-# Check whether --with-mpfr was given.
-if test "${with_mpfr+set}" = set; then :
-  withval=$with_mpfr;
-else
-  with_mpfr=auto
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use MPFR" >&5
-$as_echo_n "checking whether to use MPFR... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_mpfr" >&5
-$as_echo "$with_mpfr" >&6; }
-
-if test "${with_mpfr}" = no; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MPFR support disabled; some features may be unavailable." >&5
-$as_echo "$as_me: WARNING: MPFR support disabled; some features may be unavailable." >&2;}
-  HAVE_LIBMPFR=no
-else
-
-
-
-
-
-
-
-
-    use_additional=yes
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-
-    eval additional_includedir=\"$includedir\"
-    eval additional_libdir=\"$libdir\"
-
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-
-# Check whether --with-libmpfr-prefix was given.
-if test "${with_libmpfr_prefix+set}" = set; then :
-  withval=$with_libmpfr_prefix;
-    if test "X$withval" = "Xno"; then
-      use_additional=no
-    else
-      if test "X$withval" = "X"; then
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-
-          eval additional_includedir=\"$includedir\"
-          eval additional_libdir=\"$libdir\"
-
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-      else
-        additional_includedir="$withval/include"
-        additional_libdir="$withval/lib"
-      fi
-    fi
-
-fi
-
-
-# Check whether --with-libmpfr-type was given.
-if test "${with_libmpfr_type+set}" = set; then :
-  withval=$with_libmpfr_type;  with_libmpfr_type=$withval
-else
-   with_libmpfr_type=auto
-fi
-
-  lib_type=`eval echo \$with_libmpfr_type`
-
-      LIBMPFR=
-  LTLIBMPFR=
-  INCMPFR=
-  rpathdirs=
-  ltrpathdirs=
-  names_already_handled=
-  names_next_round='mpfr gmp'
-  while test -n "$names_next_round"; do
-    names_this_round="$names_next_round"
-    names_next_round=
-    for name in $names_this_round; do
-      already_handled=
-      for n in $names_already_handled; do
-        if test "$n" = "$name"; then
-          already_handled=yes
-          break
-        fi
-      done
-      if test -z "$already_handled"; then
-        names_already_handled="$names_already_handled $name"
-                        uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
-        eval value=\"\$HAVE_LIB$uppername\"
-        if test -n "$value"; then
-          if test "$value" = yes; then
-            eval value=\"\$LIB$uppername\"
-            test -z "$value" || LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$value"
-            eval value=\"\$LTLIB$uppername\"
-            test -z "$value" || LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }$value"
-          else
-                                    :
-          fi
-        else
-                              found_dir=
-          found_la=
-          found_so=
-          found_a=
-          if test $use_additional = yes; then
-            if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext" && test x$lib_type != xstatic; then
-              found_dir="$additional_libdir"
-              found_so="$additional_libdir/lib$name.$shlibext"
-              if test -f "$additional_libdir/lib$name.la"; then
-                found_la="$additional_libdir/lib$name.la"
-              fi
-            elif test x$lib_type != xshared; then
-              if test -f "$additional_libdir/lib$name.$libext"; then
-                found_dir="$additional_libdir"
-                found_a="$additional_libdir/lib$name.$libext"
-                if test -f "$additional_libdir/lib$name.la"; then
-                  found_la="$additional_libdir/lib$name.la"
-                fi
-              fi
-            fi
-          fi
-          if test "X$found_dir" = "X"; then
-            for x in $LDFLAGS $LTLIBMPFR; do
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-              case "$x" in
-                -L*)
-                  dir=`echo "X$x" | sed -e 's/^X-L//'`
-                  if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext" && test x$lib_type != xstatic; then
-                    found_dir="$dir"
-                    found_so="$dir/lib$name.$shlibext"
-                    if test -f "$dir/lib$name.la"; then
-                      found_la="$dir/lib$name.la"
-                    fi
-                  elif test x$lib_type != xshared; then
-                    if test -f "$dir/lib$name.$libext"; then
-                      found_dir="$dir"
-                      found_a="$dir/lib$name.$libext"
-                      if test -f "$dir/lib$name.la"; then
-                        found_la="$dir/lib$name.la"
-                      fi
-                    fi
-                  fi
-                  ;;
-              esac
-              if test "X$found_dir" != "X"; then
-                break
-              fi
-            done
-          fi
-          if test "X$found_dir" != "X"; then
-                        LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }-L$found_dir -l$name"
-            if test "X$found_so" != "X"; then
-                                                        if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
-                                LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$found_so"
-              else
-                                                                                haveit=
-                for x in $ltrpathdirs; do
-                  if test "X$x" = "X$found_dir"; then
-                    haveit=yes
-                    break
-                  fi
-                done
-                if test -z "$haveit"; then
-                  ltrpathdirs="$ltrpathdirs $found_dir"
-                fi
-                                if test "$hardcode_direct" = yes; then
-                                                      LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$found_so"
-                else
-                  if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
-                                                            LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$found_so"
-                                                            haveit=
-                    for x in $rpathdirs; do
-                      if test "X$x" = "X$found_dir"; then
-                        haveit=yes
-                        break
-                      fi
-                    done
-                    if test -z "$haveit"; then
-                      rpathdirs="$rpathdirs $found_dir"
-                    fi
-                  else
-                                                                                haveit=
-                    for x in $LDFLAGS $LIBMPFR; do
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-                      if test "X$x" = "X-L$found_dir"; then
-                        haveit=yes
-                        break
-                      fi
-                    done
-                    if test -z "$haveit"; then
-                      LIBMPFR="${LIBMPFR}${LIBMPFR:+ }-L$found_dir"
-                    fi
-                    if test "$hardcode_minus_L" != no; then
-                                                                                        LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$found_so"
-                    else
-                                                                                                                                                                                LIBMPFR="${LIBMPFR}${LIBMPFR:+ }-l$name"
-                    fi
-                  fi
-                fi
-              fi
-            else
-              if test "X$found_a" != "X"; then
-                                LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$found_a"
-              else
-                                                LIBMPFR="${LIBMPFR}${LIBMPFR:+ }-L$found_dir -l$name"
-              fi
-            fi
-                        additional_includedir=
-            case "$found_dir" in
-              */lib | */lib/)
-                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
-                additional_includedir="$basedir/include"
-                ;;
-            esac
-            if test "X$additional_includedir" != "X"; then
-                                                                                                                if test "X$additional_includedir" != "X/usr/include"; then
-                haveit=
-                if test "X$additional_includedir" = "X/usr/local/include"; then
-                  if test -n "$GCC"; then
-                    case $host_os in
-                      linux*) haveit=yes;;
-                    esac
-                  fi
-                fi
-                if test -z "$haveit"; then
-                  for x in $CPPFLAGS $INCMPFR; do
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-                    if test "X$x" = "X-I$additional_includedir"; then
-                      haveit=yes
-                      break
-                    fi
-                  done
-                  if test -z "$haveit"; then
-                    if test -d "$additional_includedir"; then
-                                            INCMPFR="${INCMPFR}${INCMPFR:+ }-I$additional_includedir"
-                    fi
-                  fi
-                fi
-              fi
-            fi
-                        if test -n "$found_la"; then
-                                                        save_libdir="$libdir"
-              case "$found_la" in
-                */* | *\\*) . "$found_la" ;;
-                *) . "./$found_la" ;;
-              esac
-              libdir="$save_libdir"
-                            for dep in $dependency_libs; do
-                case "$dep" in
-                  -L*)
-                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
-                                                                                                                                                                if test "X$additional_libdir" != "X/usr/lib"; then
-                      haveit=
-                      if test "X$additional_libdir" = "X/usr/local/lib"; then
-                        if test -n "$GCC"; then
-                          case $host_os in
-                            linux*) haveit=yes;;
-                          esac
-                        fi
-                      fi
-                      if test -z "$haveit"; then
-                        haveit=
-                        for x in $LDFLAGS $LIBMPFR; do
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-                          if test "X$x" = "X-L$additional_libdir"; then
-                            haveit=yes
-                            break
-                          fi
-                        done
-                        if test -z "$haveit"; then
-                          if test -d "$additional_libdir"; then
-                                                        LIBMPFR="${LIBMPFR}${LIBMPFR:+ }-L$additional_libdir"
-                          fi
-                        fi
-                        haveit=
-                        for x in $LDFLAGS $LTLIBMPFR; do
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-                          if test "X$x" = "X-L$additional_libdir"; then
-                            haveit=yes
-                            break
-                          fi
-                        done
-                        if test -z "$haveit"; then
-                          if test -d "$additional_libdir"; then
-                                                        LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }-L$additional_libdir"
-                          fi
-                        fi
-                      fi
-                    fi
-                    ;;
-                  -R*)
-                    dir=`echo "X$dep" | sed -e 's/^X-R//'`
-                    if test "$enable_rpath" != no; then
-                                                                  haveit=
-                      for x in $rpathdirs; do
-                        if test "X$x" = "X$dir"; then
-                          haveit=yes
-                          break
-                        fi
-                      done
-                      if test -z "$haveit"; then
-                        rpathdirs="$rpathdirs $dir"
-                      fi
-                                                                  haveit=
-                      for x in $ltrpathdirs; do
-                        if test "X$x" = "X$dir"; then
-                          haveit=yes
-                          break
-                        fi
-                      done
-                      if test -z "$haveit"; then
-                        ltrpathdirs="$ltrpathdirs $dir"
-                      fi
-                    fi
-                    ;;
-                  -l*)
-                                        names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
-                    ;;
-                  *.la)
-                                                                                names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
-                    ;;
-                  *)
-                                        LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$dep"
-                    LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }$dep"
-                    ;;
-                esac
-              done
-            fi
-          else
-                                                            if test "x$lib_type" = "xauto" || test "x$lib_type" = "xshared"; then
-              LIBMPFR="${LIBMPFR}${LIBMPFR:+ }-l$name"
-              LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }-l$name"
-            else
-              LIBMPFR="${LIBMPFR}${LIBMPFR:+ }-l:lib$name.$libext"
-              LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }-l:lib$name.$libext"
-            fi
-          fi
-        fi
-      fi
-    done
-  done
-  if test "X$rpathdirs" != "X"; then
-    if test -n "$hardcode_libdir_separator"; then
-                        alldirs=
-      for found_dir in $rpathdirs; do
-        alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
-      done
-            acl_save_libdir="$libdir"
-      libdir="$alldirs"
-      eval flag=\"$hardcode_libdir_flag_spec\"
-      libdir="$acl_save_libdir"
-      LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$flag"
-    else
-            for found_dir in $rpathdirs; do
-        acl_save_libdir="$libdir"
-        libdir="$found_dir"
-        eval flag=\"$hardcode_libdir_flag_spec\"
-        libdir="$acl_save_libdir"
-        LIBMPFR="${LIBMPFR}${LIBMPFR:+ }$flag"
-      done
-    fi
-  fi
-  if test "X$ltrpathdirs" != "X"; then
-            for found_dir in $ltrpathdirs; do
-      LTLIBMPFR="${LTLIBMPFR}${LTLIBMPFR:+ }-R$found_dir"
-    done
-  fi
-
-
-        ac_save_CPPFLAGS="$CPPFLAGS"
-
-  for element in $INCMPFR; do
-    haveit=
-    for x in $CPPFLAGS; do
-
-  acl_save_prefix="$prefix"
-  prefix="$acl_final_prefix"
-  acl_save_exec_prefix="$exec_prefix"
-  exec_prefix="$acl_final_exec_prefix"
-  eval x=\"$x\"
-  exec_prefix="$acl_save_exec_prefix"
-  prefix="$acl_save_prefix"
-
-      if test "X$x" = "X$element"; then
-        haveit=yes
-        break
-      fi
-    done
-    if test -z "$haveit"; then
-      CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
-    fi
-  done
-
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libmpfr" >&5
-$as_echo_n "checking for libmpfr... " >&6; }
-if ${ac_cv_libmpfr+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-
-    ac_save_LIBS="$LIBS"
-    LIBS="$LIBS $LIBMPFR"
-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <mpfr.h>
-int
-main ()
-{
-mpfr_exp_t exp; mpfr_t x;
-			 mpfr_frexp (&exp, x, x, MPFR_RNDN);
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_libmpfr=yes
-else
-  ac_cv_libmpfr=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-    LIBS="$ac_save_LIBS"
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libmpfr" >&5
-$as_echo "$ac_cv_libmpfr" >&6; }
-  if test "$ac_cv_libmpfr" = yes; then
-    HAVE_LIBMPFR=yes
-
-$as_echo "#define HAVE_LIBMPFR 1" >>confdefs.h
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libmpfr" >&5
-$as_echo_n "checking how to link with libmpfr... " >&6; }
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBMPFR" >&5
-$as_echo "$LIBMPFR" >&6; }
-  else
-    HAVE_LIBMPFR=no
-            CPPFLAGS="$ac_save_CPPFLAGS"
-    LIBMPFR=
-    LTLIBMPFR=
-  fi
-
-
-
-
-
-
-  if test "$HAVE_LIBMPFR" != yes; then
-    if test "$with_mpfr" = yes; then
-      as_fn_error $? "MPFR is missing or unusable" "$LINENO" 5
-    else
-      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MPFR is missing or unusable; some features may be unavailable." >&5
-$as_echo "$as_me: WARNING: MPFR is missing or unusable; some features may be unavailable." >&2;}
-    fi
   fi
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_LIBMPFR" >&5
+$as_echo "$HAVE_LIBMPFR" >&6; }
 
 # --------------------- #
 # Check for libpython.  #
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 28703d7..65e44d9 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -683,35 +683,103 @@ else
   fi
 fi
 
+AC_ARG_WITH(gmp_include,
+  AS_HELP_STRING([--with-gmp-include=DIR], [GMP include directory]),
+  [CPPFLAGS="$CPPFLAGS -I$withval"])
+AC_ARG_WITH(gmp_lib,
+  AS_HELP_STRING([--with-gmp-lib=DIR], [GMP lib directory]),
+  [LIBGMP="-L$withval"])
+AC_ARG_WITH(gmp,
+  AS_HELP_STRING([--with-gmp=DIR], [GMP install directory]), [
+  if test -z "$with_gmp_lib" && test -z "$with_gmp_include" ; then
+    CPPFLAGS="$CPPFLAGS -I$withval/include"
+    LIBGMP="-L$withval/lib"
+  else
+    AC_MSG_FAILURE([Do not use --with-gmp and --with-gmp-include/--with-gmp-lib options simultaneously.])
+  fi
+])
+
+AC_MSG_CHECKING([for GMP])
 # Verify that we have a usable GMP library.
-AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
-                      [mpz_t n;
-                       mpz_init (n);])
+save_LIBS=$LIBS
+LIBS="$LIBS $LIBGMP -lgmp"
+AC_TRY_LINK([#include <gmp.h>],
+	    [mpz_t n;
+	     mpz_init (n);],
+	    [HAVE_LIBGMP=yes], [HAVE_LIBGMP=no])
+LIBS=$save_LIBS
 if test "$HAVE_LIBGMP" != yes; then
   AC_MSG_ERROR([GMP is missing or unusable])
 fi
+LIBGMP="$LIBGMP -lgmp"
+AC_SUBST(LIBGMP)
+AC_DEFINE(HAVE_LIBGMP, 1, [Define if you have the GMP library.])
+AC_MSG_RESULT([$HAVE_LIBGMP])
 
+AC_ARG_WITH(libmpfr_prefix,
+  AS_HELP_STRING([--with-libmpfr-prefix=DIR], [this option has been DEPRECATED]), [
+  if test -z "$with_mpfr" ; then
+    with_mpfr="auto"
+  fi
+  if test x"$with_mpfr" != xauto && test x"$with_mpfr" != xyes && test x"$with_mpfr" != xno ; then
+    AC_MSG_FAILURE([Do not use --with-mpfr=DIR and --with-libmpfr-prefix=DIR options simultaneously.])
+  fi
+])
+save_CPPFLAGS=$CPPFLAGS
+AC_ARG_WITH(mpfr_include,
+  AS_HELP_STRING([--with-mpfr-include=DIR], [MPFR include directory]),
+  [CPPFLAGS="$CPPFLAGS -I$withval"])
+AC_ARG_WITH(mpfr_lib,
+  AS_HELP_STRING([--with-mpfr-lib=DIR], [MPFR lib directory]),
+  [LIBMPFR="-L$withval"])
 AC_ARG_WITH(mpfr,
-  AS_HELP_STRING([--with-mpfr], [include MPFR support (auto/yes/no)]),
-  [], [with_mpfr=auto])
-AC_MSG_CHECKING([whether to use MPFR])
-AC_MSG_RESULT([$with_mpfr])
+  AS_HELP_STRING([--with-mpfr=DIR],
+		 [MFPR install directory (or auto/yes/no)]), [
+  if test -n "$with_libmpfr_prefix" ; then
+    withval=$with_libmpfr_prefix
+  fi
+  if test -z "$with_mpfr_lib" && test -z "$with_mpfr_include" ; then
+    if test x"$withval" != xauto && test x"$withval" != xyes && test x"$withval" != xno ; then
+      CPPFLAGS="$CPPFLAGS -I$withval/include"
+      LIBMPFR="-L$withval/lib"
+      if test -z "$with_libmpfr_prefix" ; then
+	with_mpfr=yes
+      fi
+    fi
+  else
+    AC_MSG_FAILURE([Do not use --with-mpfr and --with-mpfr-include/--with-mpfr-lib options simultaneously.])
+  fi
+])
 
+AC_MSG_CHECKING([whether to use MPFR])
 if test "${with_mpfr}" = no; then
   AC_MSG_WARN([MPFR support disabled; some features may be unavailable.])
   HAVE_LIBMPFR=no
+  LIBMPFR=
+  CPPFLAGS=$save_CPPFLAGS
 else
-  AC_LIB_HAVE_LINKFLAGS([mpfr], [gmp], [#include <mpfr.h>],
-			[mpfr_exp_t exp; mpfr_t x;
-			 mpfr_frexp (&exp, x, x, MPFR_RNDN);])
+  save_LIBS=$LIBS
+  LIBS="$LIBS $LIBMPFR -lmpfr $LIBGMP"
+  AC_TRY_LINK([#include <mpfr.h>],
+	      [mpfr_exp_t exp; mpfr_t x;
+	       mpfr_frexp (&exp, x, x, MPFR_RNDN);],
+	      [HAVE_LIBMPFR=yes], [HAVE_LIBMPFR=no])
+  LIBS=$save_LIBS
   if test "$HAVE_LIBMPFR" != yes; then
     if test "$with_mpfr" = yes; then
       AC_MSG_ERROR([MPFR is missing or unusable])
     else
       AC_MSG_WARN([MPFR is missing or unusable; some features may be unavailable.])
     fi
+    LIBMPFR=
+    CPPFLAGS=$save_CPPFLAGS
+  else
+    LIBMPFR="$LIBMPFR -lmpfr"
+    AC_SUBST(LIBMPFR)
+    AC_DEFINE(HAVE_LIBMPFR, 1, [Define if you have the MPFR library.])
   fi
 fi
+AC_MSG_RESULT([$HAVE_LIBMPFR])
 
 # --------------------- #
 # Check for libpython.  #
-- 
1.9.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR-v2.patch --]
[-- Type: text/x-patch; name="0001-Enable-GDB-build-with-in-tree-GMP-and-MPFR-v2.patch", Size: 15197 bytes --]

From b7cd2ebb1f555397885279a2ace6bd46ca4f5643 Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Sun, 15 Nov 2020 15:37:22 +0100
Subject: [PATCH] Enable GDB build with in-tree GMP and MPFR

With this patch GDB can be built with in-tree GMP and/or
MPFR.  This works also for cross-builds.

All that is needed, is a sym-link in the source tree,
like this:

gmp -> ../gmp-6.1.0
mpfr -> ../mpfr-3.1.4

2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* Makefile.def: Prepare for GDB build with intree GMP.
	* Makefile.in: Regenerate.

gdb:
2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* configure.ac: Detect in-tree GMP and MPFR.
	* configure: Regenerate.
	* README: Mention ./contrib/download_prerequisites.

contrib:
2020-12-10  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* download_prerequisites: New helper script.
	* prerequisites.md5: checksums.
	* prerequisites.sha512: checksums.
---
 Makefile.def                   |   2 +
 Makefile.in                    |   2 +
 contrib/download_prerequisites | 263 +++++++++++++++++++++++++++++++++++++++++
 contrib/prerequisites.md5      |   2 +
 contrib/prerequisites.sha512   |   2 +
 gdb/README                     |  12 ++
 gdb/configure                  |  20 +++-
 gdb/configure.ac               |  20 +++-
 8 files changed, 315 insertions(+), 8 deletions(-)
 create mode 100755 contrib/download_prerequisites
 create mode 100644 contrib/prerequisites.md5
 create mode 100644 contrib/prerequisites.sha512

diff --git a/Makefile.def b/Makefile.def
index 089e70a..b6872c9 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -391,6 +391,8 @@ dependencies = { module=all-intl; on=all-libiconv; };
 
 // Host modules specific to gdb.
 dependencies = { module=configure-gdb; on=all-intl; };
+dependencies = { module=configure-gdb; on=all-gmp; };
+dependencies = { module=configure-gdb; on=all-mpfr; };
 dependencies = { module=configure-gdb; on=configure-sim; };
 dependencies = { module=configure-gdb; on=all-bfd; };
 dependencies = { module=configure-gdb; on=all-gnulib; };
diff --git a/Makefile.in b/Makefile.in
index fe34132..ead9430 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -52449,6 +52449,8 @@ configure-libcc1: maybe-configure-gcc
 all-libcc1: maybe-all-gcc
 all-utils: maybe-all-libiberty
 configure-gdb: maybe-all-intl
+configure-gdb: maybe-all-gmp
+configure-gdb: maybe-all-mpfr
 configure-gdb: maybe-all-bfd
 configure-gdb: maybe-all-libiconv
 all-gdb: maybe-all-libiberty
diff --git a/contrib/download_prerequisites b/contrib/download_prerequisites
new file mode 100755
index 0000000..0d04030
--- /dev/null
+++ b/contrib/download_prerequisites
@@ -0,0 +1,263 @@
+#! /bin/sh
+#! -*- coding:utf-8; mode:shell-script; -*-
+
+# Download some prerequisites needed by GDB.
+# Run this from the top level of the GDB source tree and the GDB build will do
+# the right thing.  Run it with the `--help` option for more information.
+#
+# (C) 2010-2020 Free Software Foundation
+#
+# 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/.
+
+program='download_prerequisites'
+version='(unversioned)'
+
+# MAINTAINERS: If you update the package versions below, please
+# remember to also update the files `contrib/prerequisites.sha512` and
+# `contrib/prerequisites.md5` with the new checksums.
+
+gmp='gmp-6.1.0.tar.bz2'
+mpfr='mpfr-3.1.4.tar.bz2'
+
+base_url='http://gcc.gnu.org/pub/gcc/infrastructure/'
+
+echo_archives() {
+    echo "${gmp}"
+    echo "${mpfr}"
+}
+
+verify=1
+force=0
+OS=$(uname)
+
+case $OS in
+  "Darwin"|"FreeBSD"|"DragonFly"|"AIX")
+    chksum='shasum -a 512 --check'
+  ;;
+  "OpenBSD")
+    chksum='sha512 -c'
+  ;;
+  *)
+    chksum='sha512sum -c'
+  ;;
+esac
+
+if type wget > /dev/null ; then
+  fetch='wget'
+else
+  fetch='curl -LO'
+fi
+chksum_extension='sha512'
+directory='.'
+
+helptext="usage: ${program} [OPTION...]
+
+Downloads some prerequisites needed by GDB.  Run this from the top level of the
+GDB source tree and the GDB build will do the right thing.
+
+The following options are available:
+
+ --directory=DIR  download and unpack packages into DIR instead of '.'
+ --force          download again overwriting existing packages
+ --no-force       do not download existing packages again (default)
+ --verify         verify package integrity after download (default)
+ --no-verify      don't verify package integrity
+ --sha512         use SHA512 checksum to verify package integrity (default)
+ --md5            use MD5 checksum to verify package integrity
+ --help           show this text and exit
+ --version        show version information and exit
+"
+
+versiontext="${program} ${version}
+Copyright (C) 2020 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+die() {
+    echo "error: $@" >&2
+    exit 1
+}
+
+for arg in "$@"
+do
+    case "${arg}" in
+        --help)
+            echo "${helptext}"
+            exit
+            ;;
+        --version)
+            echo "${versiontext}"
+            exit
+            ;;
+    esac
+done
+unset arg
+
+# Emulate Linux's 'md5 --check' on macOS
+md5_check() {
+  # Store the standard input: a line from contrib/prerequisites.md5:
+  md5_checksum_line=$(cat -)
+  # Grab the text before the first space
+  md5_checksum_expected="${md5_checksum_line%% *}"
+  # Grab the text after the first space
+  file_to_check="${md5_checksum_line##* }"
+  # Calculate the md5 checksum for the downloaded file
+  md5_checksum_output=$(md5 -r "${file_to_check}")
+  # Grab the text before the first space
+  md5_checksum_detected="${md5_checksum_output%% *}"
+  [ "${md5_checksum_expected}" == "${md5_checksum_detected}" ] \
+    || die "Cannot verify integrity of possibly corrupted file ${file_to_check}"
+  echo "${file_to_check}: OK"
+}
+
+
+argnext=
+for arg in "$@"
+do
+    if [ "x${argnext}" = x ]
+    then
+        case "${arg}" in
+            --directory)
+                argnext='directory'
+                ;;
+            --directory=*)
+                directory="${arg#--directory=}"
+                ;;
+            --force)
+                force=1
+                ;;
+            --no-force)
+                force=0
+                ;;
+            --verify)
+                verify=1
+                ;;
+            --no-verify)
+                verify=0
+                ;;
+            --sha512)
+                case $OS in
+                  "Darwin")
+                    chksum='shasum -a 512 --check'
+                  ;;
+                  *)
+                    chksum='sha512sum --check'
+                  ;;
+                esac
+                chksum_extension='sha512'
+                verify=1
+                ;;
+            --md5)
+                case $OS in
+                  "Darwin")
+                    chksum='md5_check'
+                  ;;
+                  *)
+                    chksum='md5 --check'
+                  ;;
+                esac
+                chksum_extension='md5'
+                verify=1
+                ;;
+            -*)
+                die "unknown option: ${arg}"
+                ;;
+            *)
+                die "too many arguments"
+                ;;
+        esac
+    else
+        case "${arg}" in
+            -*)
+                die "Missing argument for option --${argnext}"
+                ;;
+        esac
+        case "${argnext}" in
+            directory)
+                directory="${arg}"
+                ;;
+            *)
+                die "The impossible has happened"
+                ;;
+        esac
+        argnext=
+    fi
+done
+[ "x${argnext}" = x ] || die "Missing argument for option --${argnext}"
+unset arg argnext
+
+[ -e ./gdb/version.in ]                                                       \
+    || die "You must run this script in the top-level GDB source directory"
+
+[ -d "${directory}" ]                                                         \
+    || die "No such directory: ${directory}"
+
+for ar in $(echo_archives)
+do
+    if [ ${force} -gt 0 ]; then rm -f "${directory}/${ar}"; fi
+    [ -e "${directory}/${ar}" ]                                               \
+        || ( cd "${directory}" && ${fetch} --no-verbose "${base_url}${ar}" )  \
+        || die "Cannot download ${ar} from ${base_url}"
+done
+unset ar
+
+if [ ${verify} -gt 0 ]
+then
+    chksumfile="contrib/prerequisites.${chksum_extension}"
+    [ -r "${chksumfile}" ] || die "No checksums available"
+    for ar in $(echo_archives)
+    do
+        grep "${ar}" "${chksumfile}"                                          \
+            | ( cd "${directory}" && ${chksum} )                              \
+            || die "Cannot verify integrity of possibly corrupted file ${ar}"
+    done
+    unset chksumfile
+fi
+unset ar
+
+for ar in $(echo_archives)
+do
+    package="${ar%.tar*}"
+    if [ ${force} -gt 0 ]; then rm -rf "${directory}/${package}"; fi
+    case $ar in
+    *.gz)
+	uncompress='gzip -d'
+	;;
+    *.bz2)
+	uncompress='bzip2 -d'
+	;;
+    *)
+	uncompress='cat'
+	;;
+    esac
+    [ -e "${directory}/${package}" ]                                          \
+        || ( cd "${directory}" && $uncompress <"${ar}" | tar -xf - )          \
+        || die "Cannot extract package from ${ar}"
+    unset package
+done
+unset ar
+
+for ar in $(echo_archives)
+do
+    target="${directory}/${ar%.tar*}/"
+    linkname="${ar%-*}"
+    if [ ${force} -gt 0 ]; then rm -f "${linkname}"; fi
+    [ -e "${linkname}" ]                                                      \
+        || ln -s "${target}" "${linkname}"                                    \
+        || die "Cannot create symbolic link ${linkname} --> ${target}"
+    unset target linkname
+done
+unset ar
+
+echo "All prerequisites downloaded successfully."
diff --git a/contrib/prerequisites.md5 b/contrib/prerequisites.md5
new file mode 100644
index 0000000..cf7be0d
--- /dev/null
+++ b/contrib/prerequisites.md5
@@ -0,0 +1,2 @@
+86ee6e54ebfc4a90b643a65e402c4048  gmp-6.1.0.tar.bz2
+b8a2f6b0e68bef46e53da2ac439e1cf4  mpfr-3.1.4.tar.bz2
diff --git a/contrib/prerequisites.sha512 b/contrib/prerequisites.sha512
new file mode 100644
index 0000000..8f05aff
--- /dev/null
+++ b/contrib/prerequisites.sha512
@@ -0,0 +1,2 @@
+3c82aeab9c1596d4da8afac2eec38e429e84f3211e1a572cf8fd2b546493c44c039b922a1133eaaa48bd7f3e11dbe795a384e21ed95cbe3ecc58d7ac02246117  gmp-6.1.0.tar.bz2
+51066066ff2c12ed2198605ecf68846b0c96b548adafa5b80e0c786d0df488411a5e8973358fce7192dc977ad4e68414cf14500e3c39746de62465eb145bb819  mpfr-3.1.4.tar.bz2
diff --git a/gdb/README b/gdb/README
index e65c5ea..2b9c382 100644
--- a/gdb/README
+++ b/gdb/README
@@ -488,6 +488,12 @@ more obscure GDB `configure' options are not listed here.
      Build GDB using the GMP library installed at the directory DIR.
      If your host does not have GMP installed, you can get the latest
      version at `https://gmplib.org/'.
+     You can also build GMP in-tree when you use the script
+     ./contrib/download_prerequisites.
+     This must be done before configure.  No --with-gmp options must
+     be used when invoking configure in this case.
+     Note however, that this does only work with a separate build
+     directory.
 
 `--with-mpfr'
      Build GDB with GNU MPFR, a library for multiple-precision
@@ -499,6 +505,12 @@ more obscure GDB `configure' options are not listed here.
      available, GDB will fall back to using host floating-point
      arithmetic.  If your host does not have GNU MPFR installed, you
      can get the latest version from `https://www.mpfr.org/'.
+     You can also build MPFR in-tree when you use the script
+     ./contrib/download_prerequisites.
+     This must be done before configure.  No --with-mpfr options must
+     be used when invoking configure in this case.
+     Note however, that this does only work with a separate build
+     directory.
 
 `--with-python[=PYTHON]'
      Build GDB with Python scripting support.  (Done by default if
diff --git a/gdb/configure b/gdb/configure
index 51b4d19..5819002 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -9991,6 +9991,13 @@ done
 fi
 
 # Verify that we have a usable GMP library.
+if test -d "../gmp"; then
+  CPPFLAGS="$CPPFLAGS -I../gmp"
+  LIBGMP="../gmp/.libs/libgmp.a"
+
+$as_echo "#define HAVE_LIBGMP 1" >>confdefs.h
+
+else
 
 
 
@@ -10431,7 +10438,7 @@ int
 main ()
 {
 mpz_t n;
-                       mpz_init (n);
+                         mpz_init (n);
   ;
   return 0;
 }
@@ -10469,8 +10476,9 @@ $as_echo "$LIBGMP" >&6; }
 
 
 
-if test "$HAVE_LIBGMP" != yes; then
-  as_fn_error $? "GMP is missing or unusable" "$LINENO" 5
+  if test "$HAVE_LIBGMP" != yes; then
+    as_fn_error $? "GMP is missing or unusable" "$LINENO" 5
+  fi
 fi
 
 
@@ -10490,6 +10498,12 @@ if test "${with_mpfr}" = no; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MPFR support disabled; some features may be unavailable." >&5
 $as_echo "$as_me: WARNING: MPFR support disabled; some features may be unavailable." >&2;}
   HAVE_LIBMPFR=no
+elif test -d "../mpfr"; then
+  CPPFLAGS="$CPPFLAGS -I${srcdir}/../mpfr/src"
+  LIBMPFR="../mpfr/src/.libs/libmpfr.a"
+
+$as_echo "#define HAVE_LIBMPFR 1" >>confdefs.h
+
 else
 
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 28703d7..f1c233c 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -684,11 +684,17 @@ else
 fi
 
 # Verify that we have a usable GMP library.
-AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
-                      [mpz_t n;
-                       mpz_init (n);])
-if test "$HAVE_LIBGMP" != yes; then
-  AC_MSG_ERROR([GMP is missing or unusable])
+if test -d "../gmp"; then
+  CPPFLAGS="$CPPFLAGS -I../gmp"
+  LIBGMP="../gmp/.libs/libgmp.a"
+  AC_DEFINE(HAVE_LIBGMP, 1, [Define if you have the GMP library.])
+else
+  AC_LIB_HAVE_LINKFLAGS([gmp], [], [#include <gmp.h>],
+                        [mpz_t n;
+                         mpz_init (n);])
+  if test "$HAVE_LIBGMP" != yes; then
+    AC_MSG_ERROR([GMP is missing or unusable])
+  fi
 fi
 
 AC_ARG_WITH(mpfr,
@@ -700,6 +706,10 @@ AC_MSG_RESULT([$with_mpfr])
 if test "${with_mpfr}" = no; then
   AC_MSG_WARN([MPFR support disabled; some features may be unavailable.])
   HAVE_LIBMPFR=no
+elif test -d "../mpfr"; then
+  CPPFLAGS="$CPPFLAGS -I${srcdir}/../mpfr/src"
+  LIBMPFR="../mpfr/src/.libs/libmpfr.a"
+  AC_DEFINE(HAVE_LIBMPFR, 1, [Define if you have the MPFR library.])
 else
   AC_LIB_HAVE_LINKFLAGS([mpfr], [gmp], [#include <mpfr.h>],
 			[mpfr_exp_t exp; mpfr_t x;
-- 
1.9.1


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-25 12:05                                         ` Bernd Edlinger
@ 2020-12-27 22:01                                           ` Simon Marchi
  2020-12-29  8:36                                             ` Bernd Edlinger
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-12-27 22:01 UTC (permalink / raw)
  To: Bernd Edlinger, Joel Brobecker
  Cc: Tom Tromey, Pedro Alves, Eli Zaretskii, Andrew Burgess, gdb-patches



On 2020-12-25 7:05 a.m., Bernd Edlinger wrote:
> Hi everybody,
> 
> I have now two possible ways to go forward with the configure options
> for gmp and mpfr.
> 
> See the attached patches:
> 
> Variant 1: implements traditional configure options
> --with-gmp-include=DIR, --with-gmp-lib=DIR, --with-gmp=DIR,
> --with-mpfr-include=DIR, --with-mpfr-lib=DIR, --with-mpfr=DIR
> but does additionally understand --with-libmpfr-prefix=DIR
> and --with-mpfr=auto/yes/no.
> 
> Variant 2: (I already posted that one) keeps all configure options
> as they are now, and just uses the presence of a ../gmp and ../mpfr
> directory to override the gmp and mpfr configure flags.
> 
> I would be interested in what you think, and which variant you would
> prefer.
> 
> 
> Thanks
> Bernd.
> 

I really don't have a strong opinion about this, but my only strong-ish
opinion is that I want to minimize the complexity of what we add.
I'm already on the fence about the download script and detecting gmp
/ mpfr in-tree, because I think this is complexity we don't need.
It's not difficult for the user to download and build these two
libraries.  It's totally fine for a project to have required
dependencies that the user needs to build first...

We already provide --with-libmpfr-prefix and --with-libgmp-prefix.
Any complexity we add (like adding --with-gmp-include and
--with-gmp-lib on top of that) means more combinations to test for
whoever needs to modify that code next, more chances of breaking
something.  IMO it is not a net benefit for the project to add
these additional new switches.

Joel convinced me that it's not so important to stay in sync with
gcc for this.  So I'd choose the existing solution of using
AC_LIB_HAVE_LINKFLAGS, since that takes care of all the low level
details for us.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-27 22:01                                           ` Simon Marchi
@ 2020-12-29  8:36                                             ` Bernd Edlinger
  2020-12-29 14:50                                               ` Simon Marchi
  0 siblings, 1 reply; 140+ messages in thread
From: Bernd Edlinger @ 2020-12-29  8:36 UTC (permalink / raw)
  To: Simon Marchi, Joel Brobecker
  Cc: Tom Tromey, Pedro Alves, Eli Zaretskii, Andrew Burgess, gdb-patches



On 12/27/20 11:01 PM, Simon Marchi wrote:
> 
> 
> On 2020-12-25 7:05 a.m., Bernd Edlinger wrote:
>> Hi everybody,
>>
>> I have now two possible ways to go forward with the configure options
>> for gmp and mpfr.
>>
>> See the attached patches:
>>
>> Variant 1: implements traditional configure options
>> --with-gmp-include=DIR, --with-gmp-lib=DIR, --with-gmp=DIR,
>> --with-mpfr-include=DIR, --with-mpfr-lib=DIR, --with-mpfr=DIR
>> but does additionally understand --with-libmpfr-prefix=DIR
>> and --with-mpfr=auto/yes/no.
>>
>> Variant 2: (I already posted that one) keeps all configure options
>> as they are now, and just uses the presence of a ../gmp and ../mpfr
>> directory to override the gmp and mpfr configure flags.
>>
>> I would be interested in what you think, and which variant you would
>> prefer.
>>
>>
>> Thanks
>> Bernd.
>>
> 
> I really don't have a strong opinion about this, but my only strong-ish
> opinion is that I want to minimize the complexity of what we add.
> I'm already on the fence about the download script and detecting gmp
> / mpfr in-tree, because I think this is complexity we don't need.
> It's not difficult for the user to download and build these two
> libraries.  It's totally fine for a project to have required
> dependencies that the user needs to build first...
> 
> We already provide --with-libmpfr-prefix and --with-libgmp-prefix.
> Any complexity we add (like adding --with-gmp-include and
> --with-gmp-lib on top of that) means more combinations to test for
> whoever needs to modify that code next, more chances of breaking
> something.  IMO it is not a net benefit for the project to add
> these additional new switches.
> 
> Joel convinced me that it's not so important to stay in sync with
> gcc for this.  So I'd choose the existing solution of using
> AC_LIB_HAVE_LINKFLAGS, since that takes care of all the low level
> details for us.
> 
> Simon
> 

Okay, I also like the second variant better.

Can I assume that you agree to that variant?

If yes, then I should send the patch regarding the
toplevel configury change also to the binutils mailing list,
right?


Thanks
Bernd.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-29  8:36                                             ` Bernd Edlinger
@ 2020-12-29 14:50                                               ` Simon Marchi
  2021-01-10 14:12                                                 ` Bernd Edlinger
  0 siblings, 1 reply; 140+ messages in thread
From: Simon Marchi @ 2020-12-29 14:50 UTC (permalink / raw)
  To: Bernd Edlinger, Joel Brobecker
  Cc: Tom Tromey, Pedro Alves, Eli Zaretskii, Andrew Burgess, gdb-patches

On 2020-12-29 3:36 a.m., Bernd Edlinger wrote:
> Okay, I also like the second variant better.
> 
> Can I assume that you agree to that variant?
> 
> If yes, then I should send the patch regarding the
> toplevel configury change also to the binutils mailing list,
> right?

I do prefer the second variant over the first one, because it's
simpler.

But I prefer having none of them, and just having a built mpfr/gmp
be a prerequisite step to building GDB.

Simon


^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2020-12-29 14:50                                               ` Simon Marchi
@ 2021-01-10 14:12                                                 ` Bernd Edlinger
  2021-01-10 15:32                                                   ` Simon Marchi
  2021-01-11  3:22                                                   ` Joel Brobecker
  0 siblings, 2 replies; 140+ messages in thread
From: Bernd Edlinger @ 2021-01-10 14:12 UTC (permalink / raw)
  To: Simon Marchi, Joel Brobecker
  Cc: Tom Tromey, Pedro Alves, Eli Zaretskii, Andrew Burgess, gdb-patches

On 12/29/20 3:50 PM, Simon Marchi wrote:
> On 2020-12-29 3:36 a.m., Bernd Edlinger wrote:
>> Okay, I also like the second variant better.
>>
>> Can I assume that you agree to that variant?
>>
>> If yes, then I should send the patch regarding the
>> toplevel configury change also to the binutils mailing list,
>> right?
> 
> I do prefer the second variant over the first one, because it's
> simpler.
> 
> But I prefer having none of them, and just having a built mpfr/gmp
> be a prerequisite step to building GDB.
> 

Hmm, I see, but it was argued previously on this list, that it is okay
for GDB to have a mandatory dependency to GMP because GCC has the same
dependency.

However GCC offers exactly the same convenience as it allows GMP
to be optionally built in-tree.


Bernd.

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2021-01-10 14:12                                                 ` Bernd Edlinger
@ 2021-01-10 15:32                                                   ` Simon Marchi
  2021-01-11  3:22                                                   ` Joel Brobecker
  1 sibling, 0 replies; 140+ messages in thread
From: Simon Marchi @ 2021-01-10 15:32 UTC (permalink / raw)
  To: Bernd Edlinger, Joel Brobecker
  Cc: Tom Tromey, Pedro Alves, Eli Zaretskii, Andrew Burgess, gdb-patches

On 2021-01-10 9:12 a.m., Bernd Edlinger wrote:
> Hmm, I see, but it was argued previously on this list, that it is okay
> for GDB to have a mandatory dependency to GMP because GCC has the same
> dependency.
> 
> However GCC offers exactly the same convenience as it allows GMP
> to be optionally built in-tree.

I don't see how that requires us to do the same thing.

Simon

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2021-01-10 14:12                                                 ` Bernd Edlinger
  2021-01-10 15:32                                                   ` Simon Marchi
@ 2021-01-11  3:22                                                   ` Joel Brobecker
  2021-01-16 18:01                                                     ` Bernd Edlinger
  1 sibling, 1 reply; 140+ messages in thread
From: Joel Brobecker @ 2021-01-11  3:22 UTC (permalink / raw)
  To: Bernd Edlinger; +Cc: Simon Marchi, Pedro Alves, Tom Tromey, gdb-patches

> > But I prefer having none of them, and just having a built mpfr/gmp
> > be a prerequisite step to building GDB.
> 
> Hmm, I see, but it was argued previously on this list, that it is okay
> for GDB to have a mandatory dependency to GMP because GCC has the same
> dependency.

I think it was to show that this extra dependency wasn't going to
introduce an unreasonable burden on the developers of some specific
platform. Other that that, I wasn't trying to "follow" GCC.

> However GCC offers exactly the same convenience as it allows GMP
> to be optionally built in-tree.

I wouldn't object to that convenience, but I'm in the same camp as
Simon on that one. I know that this convenience is easier, and
I used to take advantage of something like that for e.g. libiconv;
but I soon realized that I kept rebuilding the same thing over and over
every time I rebuilt everything from scratch. In the end, it took a tiny
bit of effort to build and install that library once, and that was it,
I used that same library build until I had to switch to a different
machine. Maybe those libraries aren't big enough to make that much of
a difference (I haven't checked), but I found in the end that I didn't
really miss the convenience.

Another option if you are on GNU/Linux is to install the system version
together with the corresponding "devel" package. I assume it's not
something that works for you?

-- 
Joel

^ permalink raw reply	[flat|nested] 140+ messages in thread

* Re: [PATCH v2] Enable GDB build with in-tree GMP and MPFR
  2021-01-11  3:22                                                   ` Joel Brobecker
@ 2021-01-16 18:01                                                     ` Bernd Edlinger
  0 siblings, 0 replies; 140+ messages in thread
From: Bernd Edlinger @ 2021-01-16 18:01 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Simon Marchi, Pedro Alves, Tom Tromey, gdb-patches

On 1/11/21 4:22 AM, Joel Brobecker wrote:
>>> But I prefer having none of them, and just having a built mpfr/gmp
>>> be a prerequisite step to building GDB.
>>
>> Hmm, I see, but it was argued previously on this list, that it is okay
>> for GDB to have a mandatory dependency to GMP because GCC has the same
>> dependency.
> 
> I think it was to show that this extra dependency wasn't going to
> introduce an unreasonable burden on the developers of some specific
> platform. Other that that, I wasn't trying to "follow" GCC.
> 
>> However GCC offers exactly the same convenience as it allows GMP
>> to be optionally built in-tree.
> 
> I wouldn't object to that convenience, but I'm in the same camp as
> Simon on that one. I know that this convenience is easier, and
> I used to take advantage of something like that for e.g. libiconv;
> but I soon realized that I kept rebuilding the same thing over and over
> every time I rebuilt everything from scratch. In the end, it took a tiny
> bit of effort to build and install that library once, and that was it,
> I used that same library build until I had to switch to a different
> machine. Maybe those libraries aren't big enough to make that much of
> a difference (I haven't checked), but I found in the end that I didn't
> really miss the convenience.
> 
> Another option if you are on GNU/Linux is to install the system version
> together with the corresponding "devel" package. I assume it's not
> something that works for you?
> 

Sure, but from time to time, I also want to build using a cross-compiler
for an entirely different target.  And for that I would like the binary
to be completely self-contained if possible, just like when I build
gcc for a different target.
I don't say it is impossible to set up a statically built cross-gmp for that,
but it is not straight-forward either, and since the top-level configury
handles everything automatically for cross-builds, it is rather simple
in comparison.


Bernd.

^ permalink raw reply	[flat|nested] 140+ messages in thread

end of thread, other threads:[~2021-01-16 18:01 UTC | newest]

Thread overview: 140+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-08  6:30 RFA: Add support for DWARF-based fixed point types Joel Brobecker
2020-11-08  6:30 ` [PATCH 1/9] gdb/configure: Add --with-libgmp-prefix option Joel Brobecker
2020-11-08  6:30 ` [PATCH 2/9] gdb: Make GMP a required dependency for building GDB Joel Brobecker
2020-12-15  6:55   ` Sebastian Huber
2020-12-15  8:57     ` Joel Brobecker
2020-11-08  6:30 ` [PATCH 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects Joel Brobecker
2020-11-10 20:15   ` Simon Marchi
2020-11-13  8:12     ` Joel Brobecker
2020-11-13 15:04       ` Tom Tromey
2020-11-13 15:06         ` Simon Marchi
2020-11-16 16:18         ` Tom Tromey
2020-11-16 16:34   ` Luis Machado
2020-11-18  3:52     ` Joel Brobecker
2020-11-08  6:30 ` [PATCH 4/9] Move uinteger_pow gdb/valarith.c to gdb/utils.c and make it public Joel Brobecker
2020-11-08  6:30 ` [PATCH 5/9] Add support for printing value of DWARF-based fixed-point type objects Joel Brobecker
2020-11-10 21:06   ` Simon Marchi
2020-11-14 10:48     ` Joel Brobecker
2020-11-14 13:20       ` Simon Marchi
2020-11-14 11:30     ` Joel Brobecker
2020-11-14 16:14       ` Simon Marchi
2020-11-15  5:30         ` Joel Brobecker
2020-11-15  6:33     ` Joel Brobecker
2020-11-16  0:13       ` Simon Marchi
2020-11-08  6:30 ` [PATCH 6/9] fix printing of DWARF fixed-point type objects with format modifier Joel Brobecker
2020-11-10 22:50   ` Simon Marchi
2020-11-08  6:30 ` [PATCH 7/9] Add ptype support for DWARF-based fixed-point types Joel Brobecker
2020-11-10 23:00   ` Simon Marchi
2020-11-15  6:57     ` Joel Brobecker
2020-11-15  7:09       ` Joel Brobecker
2020-11-16  0:16         ` Simon Marchi
2020-11-16  4:03           ` Joel Brobecker
2020-11-08  6:30 ` [PATCH 8/9] Add support for fixed-point type arithmetic Joel Brobecker
2020-11-10 23:18   ` Simon Marchi
2020-11-08  6:30 ` [PATCH 9/9] Add support for fixed-point type comparison operators Joel Brobecker
2020-11-10 23:21 ` RFA: Add support for DWARF-based fixed point types Simon Marchi
2020-11-11  4:53   ` Joel Brobecker
2020-11-15  8:35 ` pushed: " Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 1/9] gdb/configure: Add --with-libgmp-prefix option Joel Brobecker
2020-11-15 15:52     ` Bernd Edlinger
2020-11-16  3:45       ` Joel Brobecker
2020-11-16 14:20         ` Bernd Edlinger
2020-11-17  7:41           ` [PATCH] Enable GDB build with in-tree GMP and MPFR Bernd Edlinger
2020-11-18  3:44             ` Joel Brobecker
2020-11-18  8:14               ` Bernd Edlinger
2020-12-01 19:29                 ` Bernd Edlinger
2020-12-01 19:32                   ` Simon Marchi
2020-12-01 19:38                     ` Bernd Edlinger
2020-12-01 20:29                       ` Bernd Edlinger
2020-12-01 20:30                         ` Simon Marchi
2020-12-02  3:21                           ` Joel Brobecker
2020-12-08 20:39                             ` [PING] " Bernd Edlinger
2020-12-14 17:40                         ` [PATCH v2] " Bernd Edlinger
2020-12-14 18:47                           ` Simon Marchi
2020-12-14 21:35                             ` Tom Tromey
2020-12-14 22:17                               ` Simon Marchi
2020-12-15  2:33                                 ` Joel Brobecker
2020-12-15 14:39                                   ` Simon Marchi
2020-12-15 16:24                                     ` Bernd Edlinger
2020-12-16  7:33                                     ` Joel Brobecker
2020-12-16 18:16                                       ` Bernd Edlinger
2020-12-25 12:05                                         ` Bernd Edlinger
2020-12-27 22:01                                           ` Simon Marchi
2020-12-29  8:36                                             ` Bernd Edlinger
2020-12-29 14:50                                               ` Simon Marchi
2021-01-10 14:12                                                 ` Bernd Edlinger
2021-01-10 15:32                                                   ` Simon Marchi
2021-01-11  3:22                                                   ` Joel Brobecker
2021-01-16 18:01                                                     ` Bernd Edlinger
2020-12-15 15:33                                 ` Bernd Edlinger
2020-12-15 15:10                             ` Bernd Edlinger
2020-11-15  8:35   ` [pushed/v2 2/9] gdb: Make GMP a required dependency for building GDB Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 3/9] gmp-utils: New API to simply use of GMP's integer/rational/float objects Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 4/9] Move uinteger_pow gdb/valarith.c to gdb/utils.c and make it public Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 5/9] Add support for printing value of DWARF-based fixed-point type objects Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 6/9] fix printing of DWARF fixed-point type objects with format modifier Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 7/9] Add ptype support for DWARF-based fixed-point types Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 8/9] Add support for fixed-point type arithmetic Joel Brobecker
2020-11-15  8:35   ` [pushed/v2 9/9] Add support for fixed-point type comparison operators Joel Brobecker
2020-11-16 23:48   ` pushed: Add support for DWARF-based fixed point types Pedro Alves
2020-11-17 14:25     ` Simon Marchi
2020-11-18  3:47       ` Joel Brobecker
2020-11-22 13:12         ` [RFA] Add TYPE_CODE_FIXED_POINT handling in print_type_scalar Joel Brobecker
2020-11-22 14:35           ` Simon Marchi
2020-11-24  3:04             ` Joel Brobecker
2020-11-22 14:00         ` pushed: Add support for DWARF-based fixed point types Joel Brobecker
2020-11-22 20:11           ` Simon Marchi
2020-11-23  4:27             ` Joel Brobecker
2020-11-23 16:12               ` Simon Marchi
2020-11-24  2:39                 ` Joel Brobecker
2020-11-29 15:45               ` RFA: wrap mpz_export into gdb_mpz::safe_export Joel Brobecker
2020-11-29 15:45                 ` [RFA 1/2] Fix TARGET_CHAR_BIT/HOST_CHAR_BIT confusion in gmp-utils.c Joel Brobecker
2020-11-30 15:42                   ` Simon Marchi
2020-12-05  8:05                     ` Joel Brobecker
2020-11-29 15:45                 ` [RFA 2/2] gmp-utils: protect gdb_mpz exports against out-of-range values Joel Brobecker
2020-11-30 15:56                   ` Simon Marchi
2020-12-01  3:37                     ` Joel Brobecker
2020-12-01  4:02                       ` Simon Marchi
2020-12-01  7:11                         ` Joel Brobecker
2020-12-05  8:10                   ` [RFAv2 " Joel Brobecker
2020-12-05 23:26                     ` Simon Marchi
2020-12-06  4:58                       ` Joel Brobecker
2020-11-30 12:44                 ` RFA: wrap mpz_export into gdb_mpz::safe_export Christian Biesinger
2020-11-20 14:08   ` pushed: Add support for DWARF-based fixed point types Pedro Alves
2020-11-20 14:14     ` Joel Brobecker
2020-11-22 11:56   ` RFA/doco: Various changes related to GMP and fixed point type support Joel Brobecker
2020-11-22 11:56     ` [RFA/doco 1/4] gdb/NEWS: Document that building GDB now requires GMP Joel Brobecker
2020-11-22 15:31       ` Eli Zaretskii
2020-11-24  3:11         ` Joel Brobecker
2020-11-22 11:56     ` [RFA/doco 2/4] gdb/NEWS: Document that GDB now supports DWARF-based fixed point types Joel Brobecker
2020-11-22 15:33       ` Eli Zaretskii
2020-11-24  3:12         ` Joel Brobecker
2020-11-22 11:56     ` [RFA/doco 3/4] gdb/README: Document the --with-libgmp-prefix configure option Joel Brobecker
2020-11-22 15:32       ` Eli Zaretskii
2020-11-24  3:11         ` Joel Brobecker
2020-11-22 11:56     ` [RFA/doco 4/4] gdb/README: Fix the URL of the MPFR website (now https) Joel Brobecker
2020-11-22 15:33       ` Eli Zaretskii
2020-11-24  3:11         ` Joel Brobecker
2020-11-15  8:49 ` RFA: Various enhancements to the fixed-point support implementation Joel Brobecker
2020-11-15  8:49   ` [RFA 1/6] change gmp_string_asprintf to return an std::string Joel Brobecker
2020-11-16  0:41     ` Simon Marchi
2020-11-16  3:55       ` Joel Brobecker
2020-11-16 20:10         ` Simon Marchi
2020-11-15  8:49   ` [RFA 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view Joel Brobecker
2020-11-16  0:52     ` Simon Marchi
2020-11-16 23:05       ` Pedro Alves
2020-11-17 14:32         ` Simon Marchi
2020-11-15  8:49   ` [RFA 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro Joel Brobecker
2020-11-15  8:49   ` [RFA 4/6] Make fixed_point_type_base_type a method of struct type Joel Brobecker
2020-11-15  8:49   ` [RFA 5/6] Make function fixed_point_scaling_factor " Joel Brobecker
2020-11-15  8:49   ` [RFA 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by lambda Joel Brobecker
2020-11-16  1:01   ` RFA: Various enhancements to the fixed-point support implementation Simon Marchi
2020-11-22 11:14   ` RFA v2: " Joel Brobecker
2020-11-22 11:14     ` [RFA v2 1/6] change and rename gmp_string_asprintf to return an std::string Joel Brobecker
2020-11-22 11:14     ` [RFA v2 2/6] gmp-utils: Convert the read/write methods to using gdb::array_view Joel Brobecker
2020-11-22 11:14     ` [RFA v2 3/6] gdbtypes.h: Get rid of the TYPE_FIXED_POINT_INFO macro Joel Brobecker
2020-11-22 11:14     ` [RFA v2 4/6] Make fixed_point_type_base_type a method of struct type Joel Brobecker
2020-11-22 11:14     ` [RFA v2 5/6] Make function fixed_point_scaling_factor " Joel Brobecker
2020-11-22 11:14     ` [RFA v2 6/6] valarith.c: Replace INIT_VAL_WITH_FIXED_POINT_VAL macro by lambda Joel Brobecker
2020-11-23 16:46     ` RFA v2: Various enhancements to the fixed-point support implementation Simon Marchi
2020-11-24  2:56       ` Joel Brobecker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).