gdb: Add $_cimag and $_creal internal functions
authorAndrew Burgess <andrew.burgess@embecosm.com>
Thu, 14 Mar 2019 13:58:58 +0000 (13:58 +0000)
committerAndrew Burgess <andrew.burgess@embecosm.com>
Mon, 1 Apr 2019 20:41:49 +0000 (21:41 +0100)
Add two new internal functions $_cimag and $_creal that extract the
imaginary and real parts of a complex value.

These internal functions can take a complex value of any type 'float
complex', 'double complex', or 'long double complex' and return a
suitable floating point value 'float', 'double', or 'long double'.
So we can now do this:

    (gdb) p z1
    $1 = 1.5 + 4.5 * I
    (gdb) p $_cimag (z1)
    $4 = 4.5
    (gdb) p $_creal (z1)
    $4 = 1.5

The components of a complex value are not strictly named types in
DWARF, as the complex type is itself the base type.  However, once we
are able to extract the components it makes sense to be able to ask
what the type of these components is and get a sensible answer back,
rather than the error we would currently get.  Currently GDB says:

    (gdb) ptype z1
    type = complex double
    (gdb) p $_cimag (z1)
    $4 = 4.5
    (gdb) ptype $
    type = <invalid type code 9>

With the changes in dwarf2read.c, GDB now says:

    (gdb) ptype z1
    type = complex double
    (gdb) p $_cimag (z1)
    $4 = 4.5
    (gdb) ptype $
    type = double

Which seems to make more sense.

gdb/ChangeLog:

* NEWS: Mention new internal functions.
* dwarf2read.c (dwarf2_init_complex_target_type): New function.
(read_base_type): Use dwarf2_init_complex_target_type.
* value.c (creal_internal_fn): New function.
(cimag_internal_fn): New function.
(_initialize_values): Register new internal functions.

gdb/doc/ChangeLog:

* gdb.texinfo (Convenience Funs): Document '$_creal' and
'$_cimag'.

gdb/testsuite/ChangeLog:

* gdb.base/complex-parts.c: New file.
* gdb.base/complex-parts.exp: New file.

gdb/ChangeLog
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/dwarf2read.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/complex-parts.c [new file with mode: 0644]
gdb/testsuite/gdb.base/complex-parts.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/default.exp
gdb/value.c

index ce9c573a8ef73632ee3ce2d858bbf94eed41dfb2..35a9550ecdd440f9f6cd5161c82628306b2aed4e 100644 (file)
@@ -1,3 +1,12 @@
+2019-04-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * NEWS: Mention new internal functions.
+       * dwarf2read.c (dwarf2_init_complex_target_type): New function.
+       (read_base_type): Use dwarf2_init_complex_target_type.
+       * value.c (creal_internal_fn): New function.
+       (cimag_internal_fn): New function.
+       (_initialize_values): Register new internal functions.
+
 2019-04-01  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
 
        * infrun.c (stop_all_threads): If debug_infrun, always
index dc9e7b3cb827e661e3a12ca12cb3f976df0835bf..5309a8f923b46a49650bde0bb1ec713d23c3a05c 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -16,6 +16,9 @@
 
 * Support for Pointer Authentication on AArch64 Linux.
 
+* Two new convernience functions $_cimag and $_creal that extract the
+  imaginary and real parts respectively from complex numbers.
+
 * Python API
 
   ** The gdb.Value type has a new method 'format_string' which returns a
@@ -24,7 +27,6 @@
      'array_indexes', 'symbols', 'unions', 'deref_refs', 'actual_objects',
      'static_members', 'max_elements', 'repeat_threshold', and 'format'.
 
-
 *** Changes in GDB 8.3
 
 * GDB and GDBserver now support access to additional registers on
index c0d5aac176455e13fa99ebf664e65ca64b957591..ea5fafdff1a0b15f146a7e1ec0fcd451932564a2 100644 (file)
@@ -1,3 +1,8 @@
+2019-04-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * gdb.texinfo (Convenience Funs): Document '$_creal' and
+       '$_cimag'.
+
 2019-03-30  Eli Zaretskii  <eliz@gnu.org>
 
        * gdb.texinfo (Convenience Vars): Document $_gdb_major and
index bb958cf25ddaad87e44131af6c173ae22dc76cf2..f410d026b82afe369c56bc70969afcc61a127c4b 100644 (file)
@@ -11401,6 +11401,17 @@ an enumerated type:
 Visiting node of type NODE_INTEGER
 @end smallexample
 
+@item $_cimag(@var{value})
+@itemx $_creal(@var{value})
+@findex $_cimag@r{, convenience function}
+@findex $_creal@r{, convenience function}
+Return the imaginary (@code{$_cimag}) or real (@code{$_creal}) part of
+the complex number @var{value}.
+
+The type of the imaginary or real part depends on the type of the
+complex number, e.g., using @code{$_cimag} on a @code{float complex}
+will return an imaginary part of type @code{float}.
+
 @end table
 
 @value{GDBN} provides the ability to list and get help on
index a5e953bd4275b092f9fe48f61c5b33cb46659fab..8881a1e28a83ac21e1cd57f7647bdd1051826e77 100644 (file)
@@ -17530,6 +17530,40 @@ dwarf2_init_integer_type (struct dwarf2_cu *cu, struct objfile *objfile,
   return type;
 }
 
+/* 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
+   type.
+
+   As DWARF doesn't currently provide an explicit name for the components
+   of a complex number, but it can be helpful to have these components
+   named, we try to select a suitable name based on the size of the
+   component.  */
+static struct type *
+dwarf2_init_complex_target_type (struct dwarf2_cu *cu,
+                                struct objfile *objfile,
+                                int bits, const char *name_hint)
+{
+  gdbarch *gdbarch = get_objfile_arch (objfile);
+  struct type *tt = nullptr;
+
+  switch (bits)
+    {
+    case 32:
+      tt = builtin_type (gdbarch)->builtin_float;
+      break;
+    case 64:
+      tt = builtin_type (gdbarch)->builtin_double;
+      break;
+    case 128:
+      tt = builtin_type (gdbarch)->builtin_long_double;
+      break;
+    }
+
+  const char *name = (tt == nullptr) ? nullptr : TYPE_NAME (tt);
+  return dwarf2_init_float_type (objfile, bits, name, name_hint);
+}
+
 /* Find a representation of a given base type and install
    it in the TYPE field of the die.  */
 
@@ -17569,7 +17603,7 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
        type = init_boolean_type (objfile, bits, 1, name);
        break;
       case DW_ATE_complex_float:
-       type = dwarf2_init_float_type (objfile, bits / 2, NULL, name);
+       type = dwarf2_init_complex_target_type (cu, objfile, bits / 2, name);
        type = init_complex_type (objfile, name, type);
        break;
       case DW_ATE_decimal_float:
index b429149c04e4be4cdd7784957645d8cce6398ca4..7d603ad6c1c975da4d9a77053cc13b8b924e1386 100644 (file)
@@ -1,3 +1,8 @@
+2019-04-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * gdb.base/complex-parts.c: New file.
+       * gdb.base/complex-parts.exp: New file.
+
 2019-04-01  Tom Tromey  <tromey@adacore.com>
 
        PR symtab/23331:
diff --git a/gdb/testsuite/gdb.base/complex-parts.c b/gdb/testsuite/gdb.base/complex-parts.c
new file mode 100644 (file)
index 0000000..243caee
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright 2019 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/>.  */
+
+/* Unlike the other 'complex.c' test, this one uses the "standard" header
+   file to pull in the complex types.  The testing is around printing the
+   complex numbers, and using the convenience function $_cimag and $_creal
+   to extract the parts of the complex numbers.  */
+
+#include <complex.h>
+
+void
+keep_around (volatile void *ptr)
+{
+  asm ("" ::: "memory");
+}
+
+int
+main (void)
+{
+  double complex z1 = 1.5 + 4.5 * I;
+  float complex z2 = 2.5 - 5.5 * I;
+  long double complex z3 = 3.5 + 6.5 * I;
+
+  double d1 = 1.5;
+  float f1 = 2.5;
+  int i1 = 3;
+
+  keep_around (&z1);
+  keep_around (&z2);
+  keep_around (&z3);
+  keep_around (&d1);
+  keep_around (&f1);
+  keep_around (&i1);
+
+  return 0;    /* Break Here.  */
+}
diff --git a/gdb/testsuite/gdb.base/complex-parts.exp b/gdb/testsuite/gdb.base/complex-parts.exp
new file mode 100644 (file)
index 0000000..ce8f427
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+standard_testfile
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} {
+    return -1
+}
+
+if { ![runto_main] } then {
+    fail "can't run to main"
+    return 0
+}
+
+gdb_breakpoint [gdb_get_line_number "Break Here"]
+gdb_continue_to_breakpoint "breakpt" ".* Break Here\\. .*"
+
+gdb_test "p z1" " = 1.5 \\+ 4.5 \\* I"
+gdb_test "p z2" " = 2.5 \\+ -5.5 \\* I"
+gdb_test "p z3" " = 3.5 \\+ 6.5 \\* I"
+
+gdb_test "ptype z1" " = complex double"
+gdb_test "ptype z2" " = complex float"
+gdb_test "ptype z3" " = complex long double"
+
+gdb_test "p \$_cimag (z1)" " = 4.5"
+gdb_test "ptype \$" " = double"
+
+gdb_test "p \$_cimag (z2)" " = -5.5"
+gdb_test "ptype \$" " = float"
+
+gdb_test "p \$_cimag (z3)" " = 6.5"
+gdb_test "ptype \$" " = long double"
+
+gdb_test "p \$_creal (z1)" " = 1.5"
+gdb_test "ptype \$" " = double"
+
+gdb_test "p \$_creal (z2)" " = 2.5"
+gdb_test "ptype \$" " = float"
+
+gdb_test "p \$_creal (z3)" " = 3.5"
+gdb_test "ptype \$" " = long double"
+
+gdb_test "p \$_cimag (d1)" "expected a complex number"
+gdb_test "p \$_cimag (f1)" "expected a complex number"
+gdb_test "p \$_cimag (i1)" "expected a complex number"
+
+gdb_test "p \$_creal (d1)" "expected a complex number"
+gdb_test "p \$_creal (f1)" "expected a complex number"
+gdb_test "p \$_creal (i1)" "expected a complex number"
index 9ff5144448d8402e337ff5efbd88f1eb1ebc0542..56ec917aa3f83867fa9c08df96d05b7d5a1754d9 100644 (file)
@@ -601,6 +601,8 @@ set show_conv_list \
        {$_probe_arg9 = <error: No frame selected>} \
        {$_probe_arg10 = <error: No frame selected>} \
        {$_probe_arg11 = <error: No frame selected>} \
+       {$_cimag = <internal function _cimag>} \
+       {$_creal = <internal function _creal>} \
        {$_isvoid = <internal function _isvoid>} \
        {$_gdb_major = 8} \
        {$_gdb_minor = 4} \
index bcfc084e09092a187baa691856f7b3f940573073..c0f8a58168a45f72343ffa5f44b0e2f830cc82a2 100644 (file)
@@ -3933,6 +3933,44 @@ isvoid_internal_fn (struct gdbarch *gdbarch,
   return value_from_longest (builtin_type (gdbarch)->builtin_int, ret);
 }
 
+/* Implementation of the convenience function $_cimag.  Extracts the
+   real part from a complex number.  */
+
+static struct value *
+creal_internal_fn (struct gdbarch *gdbarch,
+                  const struct language_defn *language,
+                  void *cookie, int argc, struct value **argv)
+{
+  if (argc != 1)
+    error (_("You must provide one argument for $_creal."));
+
+  value *cval = argv[0];
+  type *ctype = check_typedef (value_type (cval));
+  if (TYPE_CODE (ctype) != TYPE_CODE_COMPLEX)
+    error (_("expected a complex number"));
+  return value_from_component (cval, TYPE_TARGET_TYPE (ctype), 0);
+}
+
+/* Implementation of the convenience function $_cimag.  Extracts the
+   imaginary part from a complex number.  */
+
+static struct value *
+cimag_internal_fn (struct gdbarch *gdbarch,
+                  const struct language_defn *language,
+                  void *cookie, int argc,
+                  struct value **argv)
+{
+  if (argc != 1)
+    error (_("You must provide one argument for $_cimag."));
+
+  value *cval = argv[0];
+  type *ctype = check_typedef (value_type (cval));
+  if (TYPE_CODE (ctype) != TYPE_CODE_COMPLEX)
+    error (_("expected a complex number"));
+  return value_from_component (cval, TYPE_TARGET_TYPE (ctype),
+                              TYPE_LENGTH (TYPE_TARGET_TYPE (ctype)));
+}
+
 #if GDB_SELF_TEST
 namespace selftests
 {
@@ -4114,6 +4152,20 @@ Usage: $_isvoid (expression)\n\
 Return 1 if the expression is void, zero otherwise."),
                         isvoid_internal_fn, NULL);
 
+  add_internal_function ("_creal", _("\
+Extract the real part of a complex number.\n\
+Usage: $_creal (expression)\n\
+Return the real part of a complex number, the type depends on the\n\
+type of a complex number."),
+                        creal_internal_fn, NULL);
+
+  add_internal_function ("_cimag", _("\
+Extract the imaginary part of a complex number.\n\
+Usage: $_cimag (expression)\n\
+Return the imaginary part of a complex number, the type depends on the\n\
+type of a complex number."),
+                        cimag_internal_fn, NULL);
+
   add_setshow_zuinteger_unlimited_cmd ("max-value-size",
                                       class_support, &max_value_size, _("\
 Set maximum sized value gdb will load from the inferior."), _("\