This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 2/2] Teach GDB that wchar_t is a built-in type in C++ mode


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]