public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/2] PR c++/21323: char16_t/char32_t/wchar_t built-in C++ types
@ 2017-03-30 17:34 Pedro Alves
  2017-03-30 17:34 ` [PATCH 2/2] Teach GDB that wchar_t is a built-in type in C++ mode Pedro Alves
  2017-03-30 17:34 ` [PATCH 1/2] Fix PR c++/21323: GDB thinks char16_t and char32_t are signed in C++ Pedro Alves
  0 siblings, 2 replies; 4+ messages in thread
From: Pedro Alves @ 2017-03-30 17:34 UTC (permalink / raw)
  To: gdb-patches

This series fixes PR c++/21323, a bug report that shows that GDB
thinks C++11's char16_t and char32_t built-in types are signed, while
the standard clearly says they're unsigned.

While working on it, I noticed that GDB isn't aware that wchar_t is a
built-in type in C++ either (and it was already the case in C++98).
The second patch fixes that.

Tested on x86_64 Fedora 23.

Pedro Alves (2):
  Fix PR c++/21323: GDB thinks char16_t and char32_t are signed in C++
  Teach GDB that wchar_t is a built-in type in C++ mode

 gdb/c-lang.c                             |   9 ++
 gdb/dwarf2read.c                         |  19 +++-
 gdb/gdbarch.c                            |  48 ++++++++
 gdb/gdbarch.h                            |  11 ++
 gdb/gdbarch.sh                           |   6 +
 gdb/gdbtypes.c                           |   8 +-
 gdb/gdbtypes.h                           |   1 +
 gdb/testsuite/gdb.cp/wide_char_types.c   |  30 +++++
 gdb/testsuite/gdb.cp/wide_char_types.exp | 181 +++++++++++++++++++++++++++++++
 gdb/windows-tdep.c                       |   3 +
 10 files changed, 310 insertions(+), 6 deletions(-)
 create mode 100644 gdb/testsuite/gdb.cp/wide_char_types.c
 create mode 100644 gdb/testsuite/gdb.cp/wide_char_types.exp

-- 
2.5.5

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

* [PATCH 1/2] Fix PR c++/21323: GDB thinks char16_t and char32_t are signed in C++
  2017-03-30 17:34 [PATCH 0/2] PR c++/21323: char16_t/char32_t/wchar_t built-in C++ types Pedro Alves
  2017-03-30 17:34 ` [PATCH 2/2] Teach GDB that wchar_t is a built-in type in C++ mode Pedro Alves
@ 2017-03-30 17:34 ` Pedro Alves
  1 sibling, 0 replies; 4+ messages in thread
From: Pedro Alves @ 2017-03-30 17:34 UTC (permalink / raw)
  To: gdb-patches

While the C++ standard says that char16_t and char32_t are unsigned types:

 Types char16_t and char32_t denote distinct types with the same size,
 signedness, and alignment as uint_least16_t and uint_least32_t,
 respectively, in <cstdint>, called the underlying types.

... gdb treats them as signed currently:

 (gdb) p (char16_t)-1
 $1 = -1 u'\xffff'

There are actually two places in gdb that hardcode these types:

- gdbtypes.c:gdbtypes_post_init, when creating the built-in types,
  seemingly used by the "x /s" command (judging from commit 9a22f0d0).

- dwarf2read.c, when reading base types with DW_ATE_UTF encoding
  (which is what is used for these types, when compiling for C++11 and
  up).  Despite the comment, the type created does end up used.

Both places need fixing.  But since I couldn't tell why dwarf2read.c
needs to create a new type, I've made it use the per-arch built-in
types instead, so that the types are only created once per arch
instead of once per objfile.  That seems to work fine.

While writting the test, I noticed that the C++ language parser isn't
actually aware of these built-in types, so if you try to use them
without a program that uses them, you get:

 (gdb) set language c++
 (gdb) ptype char16_t
 No symbol table is loaded.  Use the "file" command.
 (gdb) ptype u"hello"
 No type named char16_t.
 (gdb) p u"hello"
 No type named char16_t.

That's fixed by simply adding a couple entries to C++'s built-in types
array in c-lang.c.  With that, we get the expected:

 (gdb) ptype char16_t
 type = char16_t
 (gdb) ptype u"hello"
 type = char16_t [6]
 (gdb) p u"hello"
 $1 = u"hello"

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	PR c++/21323
	* c-lang.c (cplus_primitive_types) <cplus_primitive_type_char16_t,
	cplus_primitive_type_char32_t>: New enum values.
	(cplus_language_arch_info): Register cplus_primitive_type_char16_t
	and cplus_primitive_type_char32_t.
	* dwarf2read.c (read_base_type) <DW_ATE_UTF>: If bit size is 16 or
	32, use the archtecture's built-in type for char16_t and char32_t,
	respectively.  Otherwise, fallback to init_integer_type as before,
	but make the type unsigned, and issue a complaint.
	* gdbtypes.c (gdbtypes_post_init): Make char16_t and char32_t unsigned.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	PR c++/21323
	* gdb.cp/wide_char_types.c: New file.
	* gdb.cp/wide_char_types.exp: New file.
---
 gdb/c-lang.c                             |   6 ++
 gdb/dwarf2read.c                         |  19 +++-
 gdb/gdbtypes.c                           |   5 +-
 gdb/testsuite/gdb.cp/wide_char_types.c   |  28 ++++++
 gdb/testsuite/gdb.cp/wide_char_types.exp | 143 +++++++++++++++++++++++++++++++
 5 files changed, 195 insertions(+), 6 deletions(-)
 create mode 100644 gdb/testsuite/gdb.cp/wide_char_types.c
 create mode 100644 gdb/testsuite/gdb.cp/wide_char_types.exp

diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index a100199..616aa26 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -895,6 +895,8 @@ enum cplus_primitive_types {
   cplus_primitive_type_decfloat,
   cplus_primitive_type_decdouble,
   cplus_primitive_type_declong,
+  cplus_primitive_type_char16_t,
+  cplus_primitive_type_char32_t,
   nr_cplus_primitive_types
 };
 
@@ -950,6 +952,10 @@ cplus_language_arch_info (struct gdbarch *gdbarch,
     = builtin->builtin_decdouble;
   lai->primitive_type_vector [cplus_primitive_type_declong]
     = builtin->builtin_declong;
+  lai->primitive_type_vector [cplus_primitive_type_char16_t]
+    = builtin->builtin_char16;
+  lai->primitive_type_vector [cplus_primitive_type_char32_t]
+    = builtin->builtin_char32;
 
   lai->bool_type_symbol = "bool";
   lai->bool_type_default = builtin->builtin_bool;
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index f1a10c4..1a06f7b 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -15089,9 +15089,22 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
 	  type = init_integer_type (objfile, bits, 1, name);
 	break;
       case DW_ATE_UTF:
-	/* We just treat this as an integer and then recognize the
-	   type by name elsewhere.  */
-	type = init_integer_type (objfile, bits, 0, name);
+	{
+	  gdbarch *arch = get_objfile_arch (objfile);
+
+	  if (bits == 16)
+	    type = builtin_type (arch)->builtin_char16;
+	  else if (bits == 32)
+	    type = builtin_type (arch)->builtin_char32;
+	  else
+	    {
+	      complaint (&symfile_complaints,
+			 _("unsupported DW_ATE_UTF bit size: '%d'"),
+			 bits);
+	      type = init_integer_type (objfile, bits, 1, name);
+	    }
+	  return set_die_type (die, type, cu);
+	}
 	break;
 
       default:
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 6f3aeab..c1f76fb 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -5204,10 +5204,9 @@ gdbtypes_post_init (struct gdbarch *gdbarch)
 
   /* Wide character types.  */
   builtin_type->builtin_char16
-    = arch_integer_type (gdbarch, 16, 0, "char16_t");
+    = arch_integer_type (gdbarch, 16, 1, "char16_t");
   builtin_type->builtin_char32
-    = arch_integer_type (gdbarch, 32, 0, "char32_t");
-	
+    = arch_integer_type (gdbarch, 32, 1, "char32_t");
 
   /* Default data/code pointer types.  */
   builtin_type->builtin_data_ptr
diff --git a/gdb/testsuite/gdb.cp/wide_char_types.c b/gdb/testsuite/gdb.cp/wide_char_types.c
new file mode 100644
index 0000000..8337cd4
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/wide_char_types.c
@@ -0,0 +1,28 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2017 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <uchar.h>
+
+char16_t u16 = -1;
+char32_t u32 = -1;
+
+int
+main ()
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.cp/wide_char_types.exp b/gdb/testsuite/gdb.cp/wide_char_types.exp
new file mode 100644
index 0000000..dccb623
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/wide_char_types.exp
@@ -0,0 +1,143 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2017 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/>.
+
+# Test GDB's awareness of the char16_t, char32_t (C++11+) built-in
+# types.  We also run most tests here in C mode, and check whether the
+# built-ins are disabled (gdb uses the typedefs in the debug info
+# instead.)
+
+standard_testfile
+
+# Test char16_t/char32_t in language LANG, against symbols in
+# a program.  Lang can be "c", "c++03" or "c++11".  In C++11,
+# char16_t/char32_t are built-in types, and the debug information
+# reflects that (see
+# http://wiki.dwarfstd.org/index.php?title=C%2B%2B0x:_New_string_literals).
+
+proc wide_char_types_program {lang} {
+    global srcfile testfile
+
+    set options {debug}
+    if {$lang == "c++03"} {
+	lappend options c++ additional_flags=-std=c++03
+	set out $testfile-cxx03
+    } elseif {$lang == "c++11"} {
+	lappend options c++ additional_flags=-std=c++11
+	set out $testfile-cxx11
+    } else {
+	set out $testfile-c
+    }
+
+    if { [prepare_for_testing "failed to prepare" \
+	      ${out} [list $srcfile] $options] } {
+	return -1
+    }
+
+    if ![runto_main] then {
+	fail "can't run to main"
+	return 0
+    }
+    do_test_wide_char $lang "u16" "u32"
+}
+
+# Test char16_t/char32_t in language LANG.  Use CHAR16_EXP and
+# CHAR32_EXP as expression for each of the corresponding types.
+# (E.g., CHAR16_EXP will be u16 when testing against the program, and
+# "(char16_t)-1" when testing the built-in types without a program
+# loaded.)
+
+proc do_test_wide_char {lang char16_exp char32_exp} {
+    global gdb_prompt
+
+    # Check that the fixed-width wide types are distinct built-in
+    # types in C++11+.  In other modes, they're instead typedefs,
+    # found in the debug info.
+    if {$lang == "c++11"} {
+	gdb_test "ptype $char16_exp" "type = char16_t" \
+	    "char16_t is distinct"
+	gdb_test "ptype $char32_exp" "type = char32_t" \
+	    "char32_t is distinct"
+    } else {
+	gdb_test "ptype $char16_exp" "type = unsigned short" \
+	    "char16_t is typedef"
+	gdb_test "ptype $char32_exp" "type = unsigned int" \
+	    "char32_t is typedef"
+    }
+
+    # Check that the fixed-width wide char types are unsigned.
+    gdb_test "p $char16_exp" " = 65535 u'\\\\xffff'" \
+	"char16_t is unsigned"
+    gdb_test "p $char32_exp" " = 4294967295 U'\\\\xffffffff'" \
+	"char32_t is unsigned"
+
+    # Check sizeof.  These are fixed-width.
+    gdb_test "p sizeof($char16_exp)" "= 2" \
+	"sizeof($char16_exp) == 2"
+    gdb_test "p sizeof($char32_exp)" "= 4" \
+	"sizeof(char16_t) == 4"
+
+    # Test printing wide literal strings.  Note that when testing with
+    # no program started, this relies on GDB's awareness of the
+    # built-in wide char types.
+    gdb_test {p U"hello"} {= U"hello"}
+    gdb_test {p u"hello"} {= u"hello"}
+}
+
+# Make sure that the char16_t/char32_t types are recognized as
+# distinct built-in types in C++ mode, even with no program loaded.
+# Check that in C mode, the types are not recognized.
+
+proc wide_char_types_no_program {} {
+    global srcfile testfile
+
+    gdb_exit
+    gdb_start
+
+    # These types are not built-in in C.
+    with_test_prefix "c" {
+	gdb_test "set language c"
+
+	gdb_test "p (char16_t) -1" "No symbol table is loaded.*" \
+	    "char16_t is not built-in"
+	gdb_test "p (char32_t) -1" "No symbol table is loaded.*" \
+	    "char32_t is not built-in"
+
+	gdb_test {p U"hello"} "No type named char32_t\\\."
+	gdb_test {p u"hello"} "No type named char16_t\\\."
+    }
+
+    # Note GDB does not distinguish C++ dialects, so the fixed-width
+    # types are always available in C++ mode, even if they were not
+    # built-in types before C++11.
+    with_test_prefix "c++" {
+	gdb_test "set language c++"
+
+	do_test_wide_char "c++11" "(char16_t) -1" "(char32_t) -1"
+    }
+}
+
+# Check wide char types with no program loaded.
+with_test_prefix "no program" {
+    wide_char_types_no_program
+}
+
+# Check types when a program is loaded.
+with_test_prefix "with program" {
+    foreach_with_prefix lang {"c" "c++03" "c++11"} {
+	wide_char_types_program $lang
+    }
+}
-- 
2.5.5

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

* [PATCH 2/2] Teach GDB that wchar_t is a built-in type in C++ mode
  2017-03-30 17:34 [PATCH 0/2] PR c++/21323: char16_t/char32_t/wchar_t built-in C++ types Pedro Alves
@ 2017-03-30 17:34 ` Pedro Alves
  2017-03-31 10:47   ` Pedro Alves
  2017-03-30 17:34 ` [PATCH 1/2] Fix PR c++/21323: GDB thinks char16_t and char32_t are signed in C++ Pedro Alves
  1 sibling, 1 reply; 4+ messages in thread
From: Pedro Alves @ 2017-03-30 17:34 UTC (permalink / raw)
  To: gdb-patches

GDB is currently not aware that wchar_t is a built-in type in C++
mode.  This is usually not a problem because the debug info describes
the type, so when you have a program loaded, you don't notice this.
However, if you try expressions involving wchar_t before a program is
loaded, gdb errors out:

 (gdb) p (wchar_t)-1
 No symbol table is loaded.  Use the "file" command.
 (gdb) p L"hello"
 No type named wchar_t.
 (gdb) ptype L"hello"
 No type named wchar_t.

This commit teaches gdb about the type.  After:

 (gdb) p (wchar_t)-1
 $1 = -1 L'\xffffffff'
 (gdb) p L"hello"
 $2 = L"hello"
 (gdb) ptype L"hello"
 type = wchar_t [6]

Unlike char16_t/char32_t, unfortunately, the underlying type of
wchar_t is implementation dependent, both size and signness.  So this
requires adding a couple new gdbarch hooks.

Looking at the GCC code base, it seems to me that the majority of the
ABIs have a 4-byte signed wchar_t, so that's what I made the default
for GDB too.

I know that Windows has a 16-bit unsigned type wchar_t, so I taught
GDB about that too.

I didn't bother with doing a compreensive cross check for all the
ports that would need tweaking, on grounds that this doesn't really
affect all that much that I'm aware of (I'm mainly doing this for
completeness).  If it does, and the new test doesn't expose it, then
we can take that as the testsuite needing improvement.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	PR gdb/21323
	* c-lang.c (cplus_primitive_types) <cplus_primitive_type_wchar_t>:
	New enum value.
	(cplus_language_arch_info): Register cplus_primitive_type_wchar_t.
	* gdbtypes.h (struct builtin_type) <builtin_wchar>: New field.
	* gdbtypes.c (gdbtypes_post_init): Create the "wchar_t" type.
	* windows-tdep.c (windows_init_abi): Override gdbarch_wchar_bit
	and gdbarch_wchar_signed.
	* gdbarch.sh (wchar_bit, wchar_signed): New per-arch values.
	* gdbarch.h, gdbarch.c: Regenerate.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	PR gdb/21323
	* gdb.cp/wide_char_types.c: Include <wchar.h>.
	(wchar): New global.
	* gdb.cp/wide_char_types.exp (wide_char_types_program)
	(do_test_wide_char, wide_char_types_no_program, top level): Add
	wchar_t testing.
---
 gdb/c-lang.c                             |  3 ++
 gdb/gdbarch.c                            | 48 +++++++++++++++++++++++
 gdb/gdbarch.h                            | 11 ++++++
 gdb/gdbarch.sh                           |  6 +++
 gdb/gdbtypes.c                           |  3 ++
 gdb/gdbtypes.h                           |  1 +
 gdb/testsuite/gdb.cp/wide_char_types.c   |  2 +
 gdb/testsuite/gdb.cp/wide_char_types.exp | 66 +++++++++++++++++++++++++-------
 gdb/windows-tdep.c                       |  3 ++
 9 files changed, 129 insertions(+), 14 deletions(-)

diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 616aa26..19a8608 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -897,6 +897,7 @@ enum cplus_primitive_types {
   cplus_primitive_type_declong,
   cplus_primitive_type_char16_t,
   cplus_primitive_type_char32_t,
+  cplus_primitive_type_wchar_t,
   nr_cplus_primitive_types
 };
 
@@ -956,6 +957,8 @@ cplus_language_arch_info (struct gdbarch *gdbarch,
     = builtin->builtin_char16;
   lai->primitive_type_vector [cplus_primitive_type_char32_t]
     = builtin->builtin_char32;
+  lai->primitive_type_vector [cplus_primitive_type_wchar_t]
+    = builtin->builtin_wchar;
 
   lai->bool_type_symbol = "bool";
   lai->bool_type_default = builtin->builtin_bool;
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 87eafb2..8fd9c00 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -184,6 +184,8 @@ struct gdbarch
   const struct floatformat ** double_format;
   int long_double_bit;
   const struct floatformat ** long_double_format;
+  int wchar_bit;
+  int wchar_signed;
   gdbarch_floatformat_for_type_ftype *floatformat_for_type;
   int ptr_bit;
   int addr_bit;
@@ -389,6 +391,8 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->float_bit = 4*TARGET_CHAR_BIT;
   gdbarch->double_bit = 8*TARGET_CHAR_BIT;
   gdbarch->long_double_bit = 8*TARGET_CHAR_BIT;
+  gdbarch->wchar_bit = 4*TARGET_CHAR_BIT;
+  gdbarch->wchar_signed = -1;
   gdbarch->floatformat_for_type = default_floatformat_for_type;
   gdbarch->ptr_bit = gdbarch->int_bit;
   gdbarch->char_signed = -1;
@@ -533,6 +537,9 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of long_double_bit, invalid_p == 0 */
   if (gdbarch->long_double_format == 0)
     gdbarch->long_double_format = floatformats_ieee_double;
+  /* Skip verify of wchar_bit, invalid_p == 0 */
+  if (gdbarch->wchar_signed == -1)
+    gdbarch->wchar_signed = 1;
   /* Skip verify of floatformat_for_type, invalid_p == 0 */
   /* Skip verify of ptr_bit, invalid_p == 0 */
   if (gdbarch->addr_bit == 0)
@@ -1457,6 +1464,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                       "gdbarch_dump: vtable_function_descriptors = %s\n",
                       plongest (gdbarch->vtable_function_descriptors));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: wchar_bit = %s\n",
+                      plongest (gdbarch->wchar_bit));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: wchar_signed = %s\n",
+                      plongest (gdbarch->wchar_signed));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_write_pc_p() = %d\n",
                       gdbarch_write_pc_p (gdbarch));
   fprintf_unfiltered (file,
@@ -1757,6 +1770,41 @@ set_gdbarch_long_double_format (struct gdbarch *gdbarch,
   gdbarch->long_double_format = long_double_format;
 }
 
+int
+gdbarch_wchar_bit (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  /* Skip verify of wchar_bit, invalid_p == 0 */
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_wchar_bit called\n");
+  return gdbarch->wchar_bit;
+}
+
+void
+set_gdbarch_wchar_bit (struct gdbarch *gdbarch,
+                       int wchar_bit)
+{
+  gdbarch->wchar_bit = wchar_bit;
+}
+
+int
+gdbarch_wchar_signed (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  /* Check variable changed from pre-default.  */
+  gdb_assert (gdbarch->wchar_signed != -1);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_wchar_signed called\n");
+  return gdbarch->wchar_signed;
+}
+
+void
+set_gdbarch_wchar_signed (struct gdbarch *gdbarch,
+                          int wchar_signed)
+{
+  gdbarch->wchar_signed = wchar_signed;
+}
+
 const struct floatformat **
 gdbarch_floatformat_for_type (struct gdbarch *gdbarch, const char *name, int length)
 {
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 34f82a7..5301da1 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -188,6 +188,17 @@ extern void set_gdbarch_long_double_bit (struct gdbarch *gdbarch, int long_doubl
 extern const struct floatformat ** gdbarch_long_double_format (struct gdbarch *gdbarch);
 extern void set_gdbarch_long_double_format (struct gdbarch *gdbarch, const struct floatformat ** long_double_format);
 
+/* The ABI default bit-size for "wchar_t".  wchar_t is a built-in type
+   starting with C++11. */
+
+extern int gdbarch_wchar_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_wchar_bit (struct gdbarch *gdbarch, int wchar_bit);
+
+/* One if `wchar_t' is signed, zero if unsigned. */
+
+extern int gdbarch_wchar_signed (struct gdbarch *gdbarch);
+extern void set_gdbarch_wchar_signed (struct gdbarch *gdbarch, int wchar_signed);
+
 /* Returns the floating-point format to be used for values of length LENGTH.
    NAME, if non-NULL, is the type name, which may be used to distinguish
    different target formats of the same length. */
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 39b1f94..d90755c 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -383,6 +383,12 @@ v:const struct floatformat **:double_format:::::floatformats_ieee_double::pforma
 v:int:long_double_bit:::8 * sizeof (long double):8*TARGET_CHAR_BIT::0
 v:const struct floatformat **:long_double_format:::::floatformats_ieee_double::pformat (gdbarch->long_double_format)
 
+# The ABI default bit-size for "wchar_t".  wchar_t is a built-in type
+# starting with C++11.
+v:int:wchar_bit:::8 * sizeof (wchar_t):4*TARGET_CHAR_BIT::0
+# One if \`wchar_t' is signed, zero if unsigned.
+v:int:wchar_signed:::1:-1:1
+
 # Returns the floating-point format to be used for values of length LENGTH.
 # NAME, if non-NULL, is the type name, which may be used to distinguish
 # different target formats of the same length.
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index c1f76fb..dd3992c 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -5207,6 +5207,9 @@ gdbtypes_post_init (struct gdbarch *gdbarch)
     = arch_integer_type (gdbarch, 16, 1, "char16_t");
   builtin_type->builtin_char32
     = arch_integer_type (gdbarch, 32, 1, "char32_t");
+  builtin_type->builtin_wchar
+    = arch_integer_type (gdbarch, gdbarch_wchar_bit (gdbarch),
+			 !gdbarch_wchar_signed (gdbarch), "wchar_t");
 
   /* Default data/code pointer types.  */
   builtin_type->builtin_data_ptr
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 4abeaf3..cfb9c28 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1509,6 +1509,7 @@ struct builtin_type
   /* Wide character types.  */
   struct type *builtin_char16;
   struct type *builtin_char32;
+  struct type *builtin_wchar;
 
   /* Pointer types.  */
 
diff --git a/gdb/testsuite/gdb.cp/wide_char_types.c b/gdb/testsuite/gdb.cp/wide_char_types.c
index 8337cd4..c899b71 100644
--- a/gdb/testsuite/gdb.cp/wide_char_types.c
+++ b/gdb/testsuite/gdb.cp/wide_char_types.c
@@ -17,9 +17,11 @@
 */
 
 #include <uchar.h>
+#include <wchar.h>
 
 char16_t u16 = -1;
 char32_t u32 = -1;
+wchar_t wchar = -1;
 
 int
 main ()
diff --git a/gdb/testsuite/gdb.cp/wide_char_types.exp b/gdb/testsuite/gdb.cp/wide_char_types.exp
index dccb623..52502c7 100644
--- a/gdb/testsuite/gdb.cp/wide_char_types.exp
+++ b/gdb/testsuite/gdb.cp/wide_char_types.exp
@@ -15,14 +15,14 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-# Test GDB's awareness of the char16_t, char32_t (C++11+) built-in
-# types.  We also run most tests here in C mode, and check whether the
-# built-ins are disabled (gdb uses the typedefs in the debug info
-# instead.)
+# Test GDB's awareness of the wchar_t (C++98+) and char16_t, char32_t
+# (C++11+) built-in types.  We also run most tests here in C mode, and
+# check whether the built-ins are disabled (gdb uses the typedefs in
+# the debug info instead.)
 
 standard_testfile
 
-# Test char16_t/char32_t in language LANG, against symbols in
+# Test char16_t/char32_t/wchar_t in language LANG, against symbols in
 # a program.  Lang can be "c", "c++03" or "c++11".  In C++11,
 # char16_t/char32_t are built-in types, and the debug information
 # reflects that (see
@@ -51,16 +51,16 @@ proc wide_char_types_program {lang} {
 	fail "can't run to main"
 	return 0
     }
-    do_test_wide_char $lang "u16" "u32"
+    do_test_wide_char $lang "u16" "u32" "wchar"
 }
 
-# Test char16_t/char32_t in language LANG.  Use CHAR16_EXP and
-# CHAR32_EXP as expression for each of the corresponding types.
-# (E.g., CHAR16_EXP will be u16 when testing against the program, and
-# "(char16_t)-1" when testing the built-in types without a program
-# loaded.)
+# Test char16_t/char32_t/wchar_t in language LANG.  Use CHAR16_EXP,
+# CHAR32_EXP, and WCHAR_EXP as expression for each of the
+# corresponding types.  (E.g., CHAR16_EXP will be u16 when testing
+# against the program, and "(char16_t)-1" when testing the built-in
+# types without a program loaded.)
 
-proc do_test_wide_char {lang char16_exp char32_exp} {
+proc do_test_wide_char {lang char16_exp char32_exp wchar_exp} {
     global gdb_prompt
 
     # Check that the fixed-width wide types are distinct built-in
@@ -78,26 +78,60 @@ proc do_test_wide_char {lang char16_exp char32_exp} {
 	    "char32_t is typedef"
     }
 
+    # wchar_t is a disctinct built-in type in C++03+.
+    if {$lang != "c"} {
+	gdb_test "ptype $wchar_exp" "type = wchar_t" \
+	    "wchar_t is distinct"
+    } else {
+	gdb_test "ptype $wchar_exp" "type = (unsigned )?(long|int|short)" \
+	    "wchar_t is typedef"
+    }
+
     # Check that the fixed-width wide char types are unsigned.
     gdb_test "p $char16_exp" " = 65535 u'\\\\xffff'" \
 	"char16_t is unsigned"
     gdb_test "p $char32_exp" " = 4294967295 U'\\\\xffffffff'" \
 	"char32_t is unsigned"
 
+    # Whether wchar_t is signed is implementation-dependent.  While we
+    # ignore whether GDB got the ABI size/sign details right here,
+    # this at least verifies that the value isn't garbage, and that
+    # GDB correctly outputs the character using the "L" prefix.
+    set test "wchar_t sign"
+    gdb_test_multiple "p $wchar_exp" $test {
+	-re " = 4294967295 L'\\\\xffffffff'\r\n$gdb_prompt $" {
+	    pass "$test (unsigned)"
+	}
+	-re " = 65535 L'\\\\xffff'\r\n$gdb_prompt $" {
+	    pass "$test (unsigned)"
+	}
+	-re " = -1 L'\\\\xffffffff'\r\n$gdb_prompt $" {
+	    pass "$test (signed)"
+	}
+	-re " = -1 L'\\\\xffff'\r\n$gdb_prompt $" {
+	    pass "$test (signed)"
+	}
+    }
+
     # Check sizeof.  These are fixed-width.
     gdb_test "p sizeof($char16_exp)" "= 2" \
 	"sizeof($char16_exp) == 2"
     gdb_test "p sizeof($char32_exp)" "= 4" \
 	"sizeof(char16_t) == 4"
 
+    # Size of wchar_t depends on ABI.
+    gdb_test "p sizeof($wchar_exp)" "= (2|4)" \
+	"sizeof(wchar_t)"
+
     # Test printing wide literal strings.  Note that when testing with
     # no program started, this relies on GDB's awareness of the
     # built-in wide char types.
     gdb_test {p U"hello"} {= U"hello"}
     gdb_test {p u"hello"} {= u"hello"}
+    gdb_test {p L"hello"} {= L"hello"}
 }
 
-# Make sure that the char16_t/char32_t types are recognized as
+# Make sure that the char16_t/char32_t/wchar_t types are recognized as
 # distinct built-in types in C++ mode, even with no program loaded.
 # Check that in C mode, the types are not recognized.
 
@@ -116,8 +150,12 @@ proc wide_char_types_no_program {} {
 	gdb_test "p (char32_t) -1" "No symbol table is loaded.*" \
 	    "char32_t is not built-in"
 
+	gdb_test "p (wchar_t) -1" "No symbol table is loaded.*" \
+	    "wchar_t is not built-in"
+
 	gdb_test {p U"hello"} "No type named char32_t\\\."
 	gdb_test {p u"hello"} "No type named char16_t\\\."
+	gdb_test {p L"hello"} "No type named wchar_t\\\."
     }
 
     # Note GDB does not distinguish C++ dialects, so the fixed-width
@@ -126,7 +164,7 @@ proc wide_char_types_no_program {} {
     with_test_prefix "c++" {
 	gdb_test "set language c++"
 
-	do_test_wide_char "c++11" "(char16_t) -1" "(char32_t) -1"
+	do_test_wide_char "c++11" "(char16_t) -1" "(char32_t) -1" "(wchar_t) -1"
     }
 }
 
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index 62a303d..3e7e8f8 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -466,6 +466,9 @@ init_w32_command_list (void)
 void
 windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
+  set_gdbarch_wchar_bit (gdbarch, 16);
+  set_gdbarch_wchar_signed (gdbarch, 0);
+
   /* Canonical paths on this target look like
      `c:\Program Files\Foo App\mydll.dll', for example.  */
   set_gdbarch_has_dos_based_file_system (gdbarch, 1);
-- 
2.5.5

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

* Re: [PATCH 2/2] Teach GDB that wchar_t is a built-in type in C++ mode
  2017-03-30 17:34 ` [PATCH 2/2] Teach GDB that wchar_t is a built-in type in C++ mode Pedro Alves
@ 2017-03-31 10:47   ` Pedro Alves
  0 siblings, 0 replies; 4+ messages in thread
From: Pedro Alves @ 2017-03-31 10:47 UTC (permalink / raw)
  To: gdb-patches

On 03/30/2017 06:34 PM, Pedro Alves wrote:

> Unlike char16_t/char32_t, unfortunately, the underlying type of
> wchar_t is implementation dependent, both size and signness.  So this
> requires adding a couple new gdbarch hooks.
> 
> Looking at the GCC code base, it seems to me that the majority of the
> ABIs have a 4-byte signed wchar_t, so that's what I made the default
> for GDB too.
> 
> I know that Windows has a 16-bit unsigned type wchar_t, so I taught
> GDB about that too.
> 
> I didn't bother with doing a compreensive cross check for all the
> ports that would need tweaking, on grounds that this doesn't really
> affect all that much that I'm aware of (I'm mainly doing this for
> completeness).  If it does, and the new test doesn't expose it, then
> we can take that as the testsuite needing improvement.

Bah, I hate leaving a job half done.  I've cross-checked the types
against GCC now, and adjusted all ports in GDB accordingly.  I'll send a
v2 shortly.

Thanks,
Pedro Alves

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

end of thread, other threads:[~2017-03-31 10:47 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-30 17:34 [PATCH 0/2] PR c++/21323: char16_t/char32_t/wchar_t built-in C++ types Pedro Alves
2017-03-30 17:34 ` [PATCH 2/2] Teach GDB that wchar_t is a built-in type in C++ mode Pedro Alves
2017-03-31 10:47   ` Pedro Alves
2017-03-30 17:34 ` [PATCH 1/2] Fix PR c++/21323: GDB thinks char16_t and char32_t are signed in C++ Pedro Alves

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).