Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
@ 2025-08-06 13:13 Tom Tromey
  2025-08-06 13:13 ` [PATCH 1/3] Import the c-ctype module from gnulib Tom Tromey
                   ` (4 more replies)
  0 siblings, 5 replies; 16+ messages in thread
From: Tom Tromey @ 2025-08-06 13:13 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This series changes gdb to use the gnulib c-ctype module rather than
<ctype.h> or "safe-ctype.h".

The rationale is mostly in patch #3.  I do wonder if it would be
better to just add the casts everywhere.

Regression tested on x86-64 Fedora 41.  This doesn't cover
solib-rocm.c though.

Signed-off-by: Tom Tromey <tromey@adacore.com>
---
Tom Tromey (3):
      Import the c-ctype module from gnulib
      Use c-ctype.h (not safe-ctype.h) in gdb
      Use gnulib c-ctype module in gdb

 gdb/aarch64-linux-tdep.c              |   9 +-
 gdb/ada-exp.y                         |   5 +-
 gdb/ada-lang.c                        |  87 ++++----
 gdb/ada-lex.l                         |  23 +--
 gdb/ada-typeprint.c                   |   3 +-
 gdb/ada-valprint.c                    |   5 +-
 gdb/arm-linux-tdep.c                  |   9 +-
 gdb/arm-tdep.c                        |   1 -
 gdb/auto-load.c                       |   3 +-
 gdb/break-catch-exec.c                |   4 +-
 gdb/break-catch-fork.c                |   2 +-
 gdb/break-catch-syscall.c             |   3 +-
 gdb/break-catch-throw.c               |   3 +-
 gdb/break-cond-parse.c                |   4 +-
 gdb/breakpoint.c                      |   7 +-
 gdb/btrace.c                          |   5 +-
 gdb/c-exp.y                           |  19 +-
 gdb/c-lang.c                          |  11 +-
 gdb/c-support.h                       |  10 +-
 gdb/charset.c                         |   1 -
 gdb/cli/cli-cmds.c                    |  16 +-
 gdb/cli/cli-decode.c                  |   9 +-
 gdb/cli/cli-dump.c                    |   1 -
 gdb/cli/cli-option.c                  |   4 +-
 gdb/cli/cli-script.c                  |   7 +-
 gdb/cli/cli-setshow.c                 |   3 +-
 gdb/cli/cli-utils.c                   |  27 ++-
 gdb/coff-pe-read.c                    |   3 +-
 gdb/coffread.c                        |   7 +-
 gdb/completer.c                       |   2 +-
 gdb/cp-name-parser.y                  |  11 +-
 gdb/cp-support.c                      |   9 +-
 gdb/d-exp.y                           |  22 +-
 gdb/darwin-nat.c                      |   1 -
 gdb/dictionary.c                      |   4 +-
 gdb/disasm.c                          |   1 -
 gdb/dwarf2/cooked-index-entry.c       |   3 +-
 gdb/dwarf2/index-common.c             |  10 +-
 gdb/dwarf2/read.c                     |   4 +-
 gdb/eval.c                            |   1 -
 gdb/exec.c                            |   3 +-
 gdb/expprint.c                        |   1 -
 gdb/f-exp.y                           |   5 +-
 gdb/fbsd-nat.c                        |   2 +-
 gdb/findcmd.c                         |   7 +-
 gdb/gdb_wchar.h                       |   4 +-
 gdb/gnu-nat.c                         |   3 +-
 gdb/gnu-v2-abi.c                      |   3 +-
 gdb/go-exp.y                          |   9 +-
 gdb/go-lang.c                         |   3 +-
 gdb/go32-nat.c                        |   1 -
 gdb/guile/scm-cmd.c                   |   1 -
 gdb/i386-tdep.c                       |  25 ++-
 gdb/ia64-linux-tdep.c                 |   5 +-
 gdb/infcmd.c                          |   7 +-
 gdb/infrun.c                          |   3 +-
 gdb/language.c                        |   1 -
 gdb/linespec.c                        |  19 +-
 gdb/linux-fork.c                      |   3 +-
 gdb/linux-nat.c                       |   1 -
 gdb/linux-tdep.c                      |  17 +-
 gdb/linux-thread-db.c                 |   1 -
 gdb/location.c                        |  17 +-
 gdb/main.c                            |   3 +-
 gdb/maint.c                           |   5 +-
 gdb/mi/mi-cmd-break.c                 |   3 +-
 gdb/mi/mi-cmd-stack.c                 |   2 -
 gdb/mi/mi-cmd-var.c                   |   3 +-
 gdb/mi/mi-main.c                      |   1 -
 gdb/mi/mi-parse.c                     |  11 +-
 gdb/minsyms.c                         |   2 -
 gdb/minsyms.h                         |   2 +-
 gdb/nat/linux-osdata.c                |  15 +-
 gdb/netbsd-nat.c                      |   2 +-
 gdb/objc-lang.c                       |  13 +-
 gdb/or1k-tdep.c                       |   1 -
 gdb/p-exp.y                           |  17 +-
 gdb/p-lang.c                          |   1 -
 gdb/p-typeprint.c                     |   5 +-
 gdb/parse.c                           |   1 -
 gdb/ppc-linux-tdep.c                  |  13 +-
 gdb/printcmd.c                        |   1 -
 gdb/probe.c                           |   3 +-
 gdb/procfs.c                          |   5 +-
 gdb/producer.c                        |   4 +-
 gdb/python/py-mi.c                    |   6 +-
 gdb/python/py-micmd.c                 |   4 +-
 gdb/python/py-objfile.c               |   2 +-
 gdb/python/python.c                   |   1 -
 gdb/record.c                          |   9 +-
 gdb/remote-sim.c                      |   1 -
 gdb/remote.c                          |   7 +-
 gdb/riscv-tdep.c                      |   5 +-
 gdb/rust-lang.c                       |   3 +-
 gdb/s12z-tdep.c                       |   2 +-
 gdb/s390-tdep.c                       |   4 +-
 gdb/serial.c                          |   3 +-
 gdb/solib-rocm.c                      |   6 +-
 gdb/stabsread.c                       |   7 +-
 gdb/stack.c                           |   4 +-
 gdb/stap-probe.c                      |  23 +--
 gdb/symfile.c                         |   3 +-
 gdb/symtab.c                          |  17 +-
 gdb/thread.c                          |   5 +-
 gdb/tid-parse.c                       |   7 +-
 gdb/top.c                             |   1 -
 gdb/tracectf.c                        |   1 -
 gdb/tracepoint.c                      |   6 +-
 gdb/tui/tui-layout.c                  |   7 +-
 gdb/tui/tui-win.c                     |   3 +-
 gdb/tui/tui-winsource.c               |   3 +-
 gdb/typeprint.c                       |   5 +-
 gdb/unittests/command-def-selftests.c |   4 +-
 gdb/utils.c                           |  47 ++---
 gdb/valprint.c                        |   1 -
 gdb/value.c                           |   5 +-
 gdb/windows-nat.c                     |   6 +-
 gdb/xcoffread.c                       |   1 -
 gdb/xml-support.c                     |   5 +-
 gdbserver/gdbreplay.cc                |   1 -
 gdbserver/linux-low.cc                |   3 +-
 gdbserver/remote-utils.cc             |   7 +-
 gdbserver/server.cc                   |   9 +-
 gdbserver/thread-db.cc                |   3 +-
 gdbserver/tracepoint.cc               |   3 +-
 gdbsupport/common-defs.h              |   6 +
 gdbsupport/common-utils.cc            |  21 +-
 gdbsupport/gdb-safe-ctype.h           |  49 -----
 gdbsupport/pathstuff.cc               |   2 +-
 gnulib/configure                      |  25 +--
 gnulib/import/Makefile.am             |   7 +
 gnulib/import/Makefile.in             |  33 ++-
 gnulib/import/c-ctype.c               |  21 ++
 gnulib/import/c-ctype.h               | 366 ++++++++++++++++++++++++++++++++++
 gnulib/import/m4/gnulib-cache.m4      |   2 +
 gnulib/import/m4/gnulib-comp.m4       |   3 +
 gnulib/update-gnulib.sh               |   1 +
 137 files changed, 828 insertions(+), 561 deletions(-)
---
base-commit: c2729c37f10af09126b2916215cae425ae724f55
change-id: 20250805-gnulib-c-ctype-1b8fb88a6c5e

Best regards,
-- 
Tom Tromey <tromey@adacore.com>


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

* [PATCH 1/3] Import the c-ctype module from gnulib
  2025-08-06 13:13 [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h> Tom Tromey
@ 2025-08-06 13:13 ` Tom Tromey
  2025-08-06 13:13 ` [PATCH 2/3] Use c-ctype.h (not safe-ctype.h) in gdb Tom Tromey
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 16+ messages in thread
From: Tom Tromey @ 2025-08-06 13:13 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This arranges to import the c-ctype module from gnulib.  c-ctype is
similar ot safe-ctype, but doesn't poison the <ctype.h> APIs.

This patch should not result in any functional changes, as nothing
includes the new header yet.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33217
---
 gnulib/configure                 |  25 +--
 gnulib/import/Makefile.am        |   7 +
 gnulib/import/Makefile.in        |  33 +++-
 gnulib/import/c-ctype.c          |  21 +++
 gnulib/import/c-ctype.h          | 366 +++++++++++++++++++++++++++++++++++++++
 gnulib/import/m4/gnulib-cache.m4 |   2 +
 gnulib/import/m4/gnulib-comp.m4  |   3 +
 gnulib/update-gnulib.sh          |   1 +
 8 files changed, 438 insertions(+), 20 deletions(-)

diff --git a/gnulib/configure b/gnulib/configure
index cc7e8287d5a0a250e2b4f55c1c2fa270399793bd..0190336d79f3e401d83799891bd7fe83d0126917 100755
--- a/gnulib/configure
+++ b/gnulib/configure
@@ -7032,6 +7032,7 @@ fi
   # Code from module bind:
   # Code from module btowc:
   # Code from module builtin-expect:
+  # Code from module c-ctype:
   # Code from module c99:
   # Code from module canonicalize-lgpl:
   # Code from module chdir:
@@ -13813,8 +13814,8 @@ rm -f core conftest.err conftest.$ac_objext \
         LIBS=$save_LIBS
         test $gl_pthread_api = yes && break
       done
-      echo "$as_me:13816: gl_pthread_api=$gl_pthread_api" >&5
-      echo "$as_me:13817: LIBPTHREAD=$LIBPTHREAD" >&5
+      echo "$as_me:13817: gl_pthread_api=$gl_pthread_api" >&5
+      echo "$as_me:13818: LIBPTHREAD=$LIBPTHREAD" >&5
 
       gl_pthread_in_glibc=no
       # On Linux with glibc >= 2.34, libc contains the fully functional
@@ -13839,7 +13840,7 @@ rm -f conftest*
 
           ;;
       esac
-      echo "$as_me:13842: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
+      echo "$as_me:13843: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
 
       # Test for libpthread by looking for pthread_kill. (Not pthread_self,
       # since it is defined as a macro on OSF/1.)
@@ -13993,7 +13994,7 @@ fi
 
         fi
       fi
-      echo "$as_me:13996: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
+      echo "$as_me:13997: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
     fi
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5
 $as_echo_n "checking whether POSIX threads API is available... " >&6; }
@@ -17070,8 +17071,8 @@ rm -f core conftest.err conftest.$ac_objext \
         LIBS=$save_LIBS
         test $gl_pthread_api = yes && break
       done
-      echo "$as_me:17073: gl_pthread_api=$gl_pthread_api" >&5
-      echo "$as_me:17074: LIBPTHREAD=$LIBPTHREAD" >&5
+      echo "$as_me:17074: gl_pthread_api=$gl_pthread_api" >&5
+      echo "$as_me:17075: LIBPTHREAD=$LIBPTHREAD" >&5
 
       gl_pthread_in_glibc=no
       # On Linux with glibc >= 2.34, libc contains the fully functional
@@ -17096,7 +17097,7 @@ rm -f conftest*
 
           ;;
       esac
-      echo "$as_me:17099: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
+      echo "$as_me:17100: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
 
       # Test for libpthread by looking for pthread_kill. (Not pthread_self,
       # since it is defined as a macro on OSF/1.)
@@ -17250,7 +17251,7 @@ fi
 
         fi
       fi
-      echo "$as_me:17253: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
+      echo "$as_me:17254: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
     fi
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5
 $as_echo_n "checking whether POSIX threads API is available... " >&6; }
@@ -17476,8 +17477,8 @@ rm -f core conftest.err conftest.$ac_objext \
         LIBS=$save_LIBS
         test $gl_pthread_api = yes && break
       done
-      echo "$as_me:17479: gl_pthread_api=$gl_pthread_api" >&5
-      echo "$as_me:17480: LIBPTHREAD=$LIBPTHREAD" >&5
+      echo "$as_me:17480: gl_pthread_api=$gl_pthread_api" >&5
+      echo "$as_me:17481: LIBPTHREAD=$LIBPTHREAD" >&5
 
       gl_pthread_in_glibc=no
       # On Linux with glibc >= 2.34, libc contains the fully functional
@@ -17502,7 +17503,7 @@ rm -f conftest*
 
           ;;
       esac
-      echo "$as_me:17505: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
+      echo "$as_me:17506: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5
 
       # Test for libpthread by looking for pthread_kill. (Not pthread_self,
       # since it is defined as a macro on OSF/1.)
@@ -17656,7 +17657,7 @@ fi
 
         fi
       fi
-      echo "$as_me:17659: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
+      echo "$as_me:17660: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5
     fi
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5
 $as_echo_n "checking whether POSIX threads API is available... " >&6; }
diff --git a/gnulib/import/Makefile.am b/gnulib/import/Makefile.am
index 80b2bb49c081a15aa8f93625ce7a065efc5e6485..1548615f131a45a9209f667af46d4ec7c1d7b04d 100644
--- a/gnulib/import/Makefile.am
+++ b/gnulib/import/Makefile.am
@@ -36,6 +36,7 @@
 #  accept \
 #  alloca \
 #  bind \
+#  c-ctype \
 #  canonicalize-lgpl \
 #  chown \
 #  connect \
@@ -246,6 +247,12 @@ endif
 
 ## end   gnulib module btowc
 
+## begin gnulib module c-ctype
+
+libgnu_a_SOURCES += c-ctype.h c-ctype.c
+
+## end   gnulib module c-ctype
+
 ## begin gnulib module canonicalize-lgpl
 
 if GL_COND_OBJ_CANONICALIZE_LGPL
diff --git a/gnulib/import/Makefile.in b/gnulib/import/Makefile.in
index 9893d17c28b9401404f9798aee41033078100b5f..2e567c09d389fb85a6536df070afed786609ed92 100644
--- a/gnulib/import/Makefile.in
+++ b/gnulib/import/Makefile.in
@@ -50,6 +50,7 @@
 #  accept \
 #  alloca \
 #  bind \
+#  c-ctype \
 #  canonicalize-lgpl \
 #  chown \
 #  connect \
@@ -557,12 +558,13 @@ am__dirstamp = $(am__leading_dot)dirstamp
 @GL_COND_OBJ_WMEMPCPY_TRUE@	libgnu_a-wmempcpy.$(OBJEXT)
 am_libgnu_a_OBJECTS = $(am__objects_1) libgnu_a-openat-proc.$(OBJEXT) \
 	libgnu_a-basename-lgpl.$(OBJEXT) $(am__objects_2) \
-	$(am__objects_3) $(am__objects_4) $(am__objects_5) \
-	$(am__objects_6) $(am__objects_7) libgnu_a-cloexec.$(OBJEXT) \
-	$(am__objects_8) $(am__objects_9) $(am__objects_10) \
-	libgnu_a-count-one-bits.$(OBJEXT) $(am__objects_11) \
-	libgnu_a-dirname-lgpl.$(OBJEXT) libgnu_a-stripslash.$(OBJEXT) \
-	$(am__objects_12) $(am__objects_13) $(am__objects_14) \
+	$(am__objects_3) libgnu_a-c-ctype.$(OBJEXT) $(am__objects_4) \
+	$(am__objects_5) $(am__objects_6) $(am__objects_7) \
+	libgnu_a-cloexec.$(OBJEXT) $(am__objects_8) $(am__objects_9) \
+	$(am__objects_10) libgnu_a-count-one-bits.$(OBJEXT) \
+	$(am__objects_11) libgnu_a-dirname-lgpl.$(OBJEXT) \
+	libgnu_a-stripslash.$(OBJEXT) $(am__objects_12) \
+	$(am__objects_13) $(am__objects_14) \
 	libgnu_a-exitfail.$(OBJEXT) $(am__objects_15) \
 	$(am__objects_16) libgnu_a-fd-hook.$(OBJEXT) \
 	libgnu_a-fd-safer-flag.$(OBJEXT) \
@@ -2150,8 +2152,8 @@ MAINTAINERCLEANFILES =
 AM_CPPFLAGS = 
 AM_CFLAGS = 
 libgnu_a_SOURCES = $(am__append_1) openat-priv.h openat-proc.c \
-	basename-lgpl.c $(am__append_2) $(am__append_3) \
-	$(am__append_4) $(am__append_5) $(am__append_6) \
+	basename-lgpl.c $(am__append_2) $(am__append_3) c-ctype.h \
+	c-ctype.c $(am__append_4) $(am__append_5) $(am__append_6) \
 	$(am__append_7) cloexec.c $(am__append_8) $(am__append_9) \
 	$(am__append_10) count-one-bits.c $(am__append_11) \
 	dirname-lgpl.c stripslash.c $(am__append_12) $(am__append_13) \
@@ -2328,6 +2330,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnu_a-basename-lgpl.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnu_a-bind.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnu_a-btowc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnu_a-c-ctype.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnu_a-canonicalize-lgpl.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnu_a-chdir-long.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnu_a-chown.Po@am__quote@
@@ -2544,6 +2547,20 @@ libgnu_a-btowc.obj: btowc.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnu_a_CFLAGS) $(CFLAGS) -c -o libgnu_a-btowc.obj `if test -f 'btowc.c'; then $(CYGPATH_W) 'btowc.c'; else $(CYGPATH_W) '$(srcdir)/btowc.c'; fi`
 
+libgnu_a-c-ctype.o: c-ctype.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnu_a_CFLAGS) $(CFLAGS) -MT libgnu_a-c-ctype.o -MD -MP -MF $(DEPDIR)/libgnu_a-c-ctype.Tpo -c -o libgnu_a-c-ctype.o `test -f 'c-ctype.c' || echo '$(srcdir)/'`c-ctype.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libgnu_a-c-ctype.Tpo $(DEPDIR)/libgnu_a-c-ctype.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='c-ctype.c' object='libgnu_a-c-ctype.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnu_a_CFLAGS) $(CFLAGS) -c -o libgnu_a-c-ctype.o `test -f 'c-ctype.c' || echo '$(srcdir)/'`c-ctype.c
+
+libgnu_a-c-ctype.obj: c-ctype.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnu_a_CFLAGS) $(CFLAGS) -MT libgnu_a-c-ctype.obj -MD -MP -MF $(DEPDIR)/libgnu_a-c-ctype.Tpo -c -o libgnu_a-c-ctype.obj `if test -f 'c-ctype.c'; then $(CYGPATH_W) 'c-ctype.c'; else $(CYGPATH_W) '$(srcdir)/c-ctype.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libgnu_a-c-ctype.Tpo $(DEPDIR)/libgnu_a-c-ctype.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='c-ctype.c' object='libgnu_a-c-ctype.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnu_a_CFLAGS) $(CFLAGS) -c -o libgnu_a-c-ctype.obj `if test -f 'c-ctype.c'; then $(CYGPATH_W) 'c-ctype.c'; else $(CYGPATH_W) '$(srcdir)/c-ctype.c'; fi`
+
 libgnu_a-canonicalize-lgpl.o: canonicalize-lgpl.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnu_a_CFLAGS) $(CFLAGS) -MT libgnu_a-canonicalize-lgpl.o -MD -MP -MF $(DEPDIR)/libgnu_a-canonicalize-lgpl.Tpo -c -o libgnu_a-canonicalize-lgpl.o `test -f 'canonicalize-lgpl.c' || echo '$(srcdir)/'`canonicalize-lgpl.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libgnu_a-canonicalize-lgpl.Tpo $(DEPDIR)/libgnu_a-canonicalize-lgpl.Po
diff --git a/gnulib/import/c-ctype.c b/gnulib/import/c-ctype.c
new file mode 100644
index 0000000000000000000000000000000000000000..a247514cd6216f2ce4af76ad85c5b7c8ae366728
--- /dev/null
+++ b/gnulib/import/c-ctype.c
@@ -0,0 +1,21 @@
+/* Character handling in C locale.
+
+   Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file 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 Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#define C_CTYPE_INLINE _GL_EXTERN_INLINE
+#include "c-ctype.h"
diff --git a/gnulib/import/c-ctype.h b/gnulib/import/c-ctype.h
new file mode 100644
index 0000000000000000000000000000000000000000..1a4f603898fec8ace9c539e1839589a27f826745
--- /dev/null
+++ b/gnulib/import/c-ctype.h
@@ -0,0 +1,366 @@
+/* Character handling in C locale.
+
+   These functions work like the corresponding functions in <ctype.h>,
+   except that they have the C (POSIX) locale hardwired, whereas the
+   <ctype.h> functions' behaviour depends on the current locale set via
+   setlocale.
+
+   Copyright (C) 2000-2003, 2006, 2008-2022 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file 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 Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#ifndef C_CTYPE_H
+#define C_CTYPE_H
+
+#include <stdbool.h>
+
+#ifndef _GL_INLINE_HEADER_BEGIN
+ #error "Please include config.h first."
+#endif
+_GL_INLINE_HEADER_BEGIN
+#ifndef C_CTYPE_INLINE
+# define C_CTYPE_INLINE _GL_INLINE
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* The functions defined in this file assume the "C" locale and a character
+   set without diacritics (ASCII-US or EBCDIC-US or something like that).
+   Even if the "C" locale on a particular system is an extension of the ASCII
+   character set (like on BeOS, where it is UTF-8, or on AmigaOS, where it
+   is ISO-8859-1), the functions in this file recognize only the ASCII
+   characters.  */
+
+
+#if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+    && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+    && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+    && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+    && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+    && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+    && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+    && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+    && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+    && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+    && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+    && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+    && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+    && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+    && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+    && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+    && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+    && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+    && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+    && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+    && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+    && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+    && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)
+/* The character set is ASCII or one of its variants or extensions, not EBCDIC.
+   Testing the value of '\n' and '\r' is not relevant.  */
+# define C_CTYPE_ASCII 1
+#elif ! (' ' == '\x40' && '0' == '\xf0'                     \
+         && 'A' == '\xc1' && 'J' == '\xd1' && 'S' == '\xe2' \
+         && 'a' == '\x81' && 'j' == '\x91' && 's' == '\xa2')
+# error "Only ASCII and EBCDIC are supported"
+#endif
+
+#if 'A' < 0
+# error "EBCDIC and char is signed -- not supported"
+#endif
+
+/* Cases for control characters.  */
+
+#define _C_CTYPE_CNTRL \
+   case '\a': case '\b': case '\f': case '\n': \
+   case '\r': case '\t': case '\v': \
+   _C_CTYPE_OTHER_CNTRL
+
+/* ASCII control characters other than those with \-letter escapes.  */
+
+#if C_CTYPE_ASCII
+# define _C_CTYPE_OTHER_CNTRL \
+    case '\x00': case '\x01': case '\x02': case '\x03': \
+    case '\x04': case '\x05': case '\x06': case '\x0e': \
+    case '\x0f': case '\x10': case '\x11': case '\x12': \
+    case '\x13': case '\x14': case '\x15': case '\x16': \
+    case '\x17': case '\x18': case '\x19': case '\x1a': \
+    case '\x1b': case '\x1c': case '\x1d': case '\x1e': \
+    case '\x1f': case '\x7f'
+#else
+   /* Use EBCDIC code page 1047's assignments for ASCII control chars;
+      assume all EBCDIC code pages agree about these assignments.  */
+# define _C_CTYPE_OTHER_CNTRL \
+    case '\x00': case '\x01': case '\x02': case '\x03': \
+    case '\x07': case '\x0e': case '\x0f': case '\x10': \
+    case '\x11': case '\x12': case '\x13': case '\x18': \
+    case '\x19': case '\x1c': case '\x1d': case '\x1e': \
+    case '\x1f': case '\x26': case '\x27': case '\x2d': \
+    case '\x2e': case '\x32': case '\x37': case '\x3c': \
+    case '\x3d': case '\x3f'
+#endif
+
+/* Cases for lowercase hex letters, and lowercase letters, all offset by N.  */
+
+#define _C_CTYPE_LOWER_A_THRU_F_N(N) \
+   case 'a' + (N): case 'b' + (N): case 'c' + (N): case 'd' + (N): \
+   case 'e' + (N): case 'f' + (N)
+#define _C_CTYPE_LOWER_N(N) \
+   _C_CTYPE_LOWER_A_THRU_F_N(N): \
+   case 'g' + (N): case 'h' + (N): case 'i' + (N): case 'j' + (N): \
+   case 'k' + (N): case 'l' + (N): case 'm' + (N): case 'n' + (N): \
+   case 'o' + (N): case 'p' + (N): case 'q' + (N): case 'r' + (N): \
+   case 's' + (N): case 't' + (N): case 'u' + (N): case 'v' + (N): \
+   case 'w' + (N): case 'x' + (N): case 'y' + (N): case 'z' + (N)
+
+/* Cases for hex letters, digits, lower, punct, and upper.  */
+
+#define _C_CTYPE_A_THRU_F \
+   _C_CTYPE_LOWER_A_THRU_F_N (0): \
+   _C_CTYPE_LOWER_A_THRU_F_N ('A' - 'a')
+#define _C_CTYPE_DIGIT                     \
+   case '0': case '1': case '2': case '3': \
+   case '4': case '5': case '6': case '7': \
+   case '8': case '9'
+#define _C_CTYPE_LOWER _C_CTYPE_LOWER_N (0)
+#define _C_CTYPE_PUNCT \
+   case '!': case '"': case '#': case '$':  \
+   case '%': case '&': case '\'': case '(': \
+   case ')': case '*': case '+': case ',':  \
+   case '-': case '.': case '/': case ':':  \
+   case ';': case '<': case '=': case '>':  \
+   case '?': case '@': case '[': case '\\': \
+   case ']': case '^': case '_': case '`':  \
+   case '{': case '|': case '}': case '~'
+#define _C_CTYPE_UPPER _C_CTYPE_LOWER_N ('A' - 'a')
+
+
+/* Function definitions.  */
+
+/* Unlike the functions in <ctype.h>, which require an argument in the range
+   of the 'unsigned char' type, the functions here operate on values that are
+   in the 'unsigned char' range or in the 'char' range.  In other words,
+   when you have a 'char' value, you need to cast it before using it as
+   argument to a <ctype.h> function:
+
+         const char *s = ...;
+         if (isalpha ((unsigned char) *s)) ...
+
+   but you don't need to cast it for the functions defined in this file:
+
+         const char *s = ...;
+         if (c_isalpha (*s)) ...
+ */
+
+C_CTYPE_INLINE bool
+c_isalnum (int c)
+{
+  switch (c)
+    {
+    _C_CTYPE_DIGIT:
+    _C_CTYPE_LOWER:
+    _C_CTYPE_UPPER:
+      return true;
+    default:
+      return false;
+    }
+}
+
+C_CTYPE_INLINE bool
+c_isalpha (int c)
+{
+  switch (c)
+    {
+    _C_CTYPE_LOWER:
+    _C_CTYPE_UPPER:
+      return true;
+    default:
+      return false;
+    }
+}
+
+/* The function isascii is not locale dependent.
+   Its use in EBCDIC is questionable. */
+C_CTYPE_INLINE bool
+c_isascii (int c)
+{
+  switch (c)
+    {
+    case ' ':
+    _C_CTYPE_CNTRL:
+    _C_CTYPE_DIGIT:
+    _C_CTYPE_LOWER:
+    _C_CTYPE_PUNCT:
+    _C_CTYPE_UPPER:
+      return true;
+    default:
+      return false;
+    }
+}
+
+C_CTYPE_INLINE bool
+c_isblank (int c)
+{
+  return c == ' ' || c == '\t';
+}
+
+C_CTYPE_INLINE bool
+c_iscntrl (int c)
+{
+  switch (c)
+    {
+    _C_CTYPE_CNTRL:
+      return true;
+    default:
+      return false;
+    }
+}
+
+C_CTYPE_INLINE bool
+c_isdigit (int c)
+{
+  switch (c)
+    {
+    _C_CTYPE_DIGIT:
+      return true;
+    default:
+      return false;
+    }
+}
+
+C_CTYPE_INLINE bool
+c_isgraph (int c)
+{
+  switch (c)
+    {
+    _C_CTYPE_DIGIT:
+    _C_CTYPE_LOWER:
+    _C_CTYPE_PUNCT:
+    _C_CTYPE_UPPER:
+      return true;
+    default:
+      return false;
+    }
+}
+
+C_CTYPE_INLINE bool
+c_islower (int c)
+{
+  switch (c)
+    {
+    _C_CTYPE_LOWER:
+      return true;
+    default:
+      return false;
+    }
+}
+
+C_CTYPE_INLINE bool
+c_isprint (int c)
+{
+  switch (c)
+    {
+    case ' ':
+    _C_CTYPE_DIGIT:
+    _C_CTYPE_LOWER:
+    _C_CTYPE_PUNCT:
+    _C_CTYPE_UPPER:
+      return true;
+    default:
+      return false;
+    }
+}
+
+C_CTYPE_INLINE bool
+c_ispunct (int c)
+{
+  switch (c)
+    {
+    _C_CTYPE_PUNCT:
+      return true;
+    default:
+      return false;
+    }
+}
+
+C_CTYPE_INLINE bool
+c_isspace (int c)
+{
+  switch (c)
+    {
+    case ' ': case '\t': case '\n': case '\v': case '\f': case '\r':
+      return true;
+    default:
+      return false;
+    }
+}
+
+C_CTYPE_INLINE bool
+c_isupper (int c)
+{
+  switch (c)
+    {
+    _C_CTYPE_UPPER:
+      return true;
+    default:
+      return false;
+    }
+}
+
+C_CTYPE_INLINE bool
+c_isxdigit (int c)
+{
+  switch (c)
+    {
+    _C_CTYPE_DIGIT:
+    _C_CTYPE_A_THRU_F:
+      return true;
+    default:
+      return false;
+    }
+}
+
+C_CTYPE_INLINE int
+c_tolower (int c)
+{
+  switch (c)
+    {
+    _C_CTYPE_UPPER:
+      return c - 'A' + 'a';
+    default:
+      return c;
+    }
+}
+
+C_CTYPE_INLINE int
+c_toupper (int c)
+{
+  switch (c)
+    {
+    _C_CTYPE_LOWER:
+      return c - 'a' + 'A';
+    default:
+      return c;
+    }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+_GL_INLINE_HEADER_END
+
+#endif /* C_CTYPE_H */
diff --git a/gnulib/import/m4/gnulib-cache.m4 b/gnulib/import/m4/gnulib-cache.m4
index a5f8e300ffce0316c8bebc160756cbdfea60b062..0cf177add8e587d9b8156726a5d4eb279300b359 100644
--- a/gnulib/import/m4/gnulib-cache.m4
+++ b/gnulib/import/m4/gnulib-cache.m4
@@ -41,6 +41,7 @@
 #  accept \
 #  alloca \
 #  bind \
+#  c-ctype \
 #  canonicalize-lgpl \
 #  chown \
 #  connect \
@@ -96,6 +97,7 @@ gl_MODULES([
   accept
   alloca
   bind
+  c-ctype
   canonicalize-lgpl
   chown
   connect
diff --git a/gnulib/import/m4/gnulib-comp.m4 b/gnulib/import/m4/gnulib-comp.m4
index 94e2cfe1a52ae004983b0616b466f130ade9e8f5..bb68991d97a43e20e055fcc38a1e718f7c2f3093 100644
--- a/gnulib/import/m4/gnulib-comp.m4
+++ b/gnulib/import/m4/gnulib-comp.m4
@@ -54,6 +54,7 @@ AC_DEFUN([gl_EARLY],
   # Code from module bind:
   # Code from module btowc:
   # Code from module builtin-expect:
+  # Code from module c-ctype:
   # Code from module c99:
   # Code from module canonicalize-lgpl:
   # Code from module chdir:
@@ -1130,6 +1131,8 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/bind.c
   lib/btowc.c
   lib/c++defs.h
+  lib/c-ctype.c
+  lib/c-ctype.h
   lib/canonicalize-lgpl.c
   lib/cdefs.h
   lib/chdir-long.c
diff --git a/gnulib/update-gnulib.sh b/gnulib/update-gnulib.sh
index 18bb5eb63f2e07245c6c0e70e823d07cf757daec..9adc009f0cb023670c3e3aefd339947b8c98fba6 100755
--- a/gnulib/update-gnulib.sh
+++ b/gnulib/update-gnulib.sh
@@ -33,6 +33,7 @@ IMPORTED_GNULIB_MODULES="\
     accept \
     alloca \
     bind \
+    c-ctype \
     canonicalize-lgpl \
     chown \
     connect \

-- 
2.50.1


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

* [PATCH 2/3] Use c-ctype.h (not safe-ctype.h) in gdb
  2025-08-06 13:13 [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h> Tom Tromey
  2025-08-06 13:13 ` [PATCH 1/3] Import the c-ctype module from gnulib Tom Tromey
@ 2025-08-06 13:13 ` Tom Tromey
  2025-08-06 13:13 ` [PATCH 3/3] Use gnulib c-ctype module " Tom Tromey
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 16+ messages in thread
From: Tom Tromey @ 2025-08-06 13:13 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes gdb and related programs to use the gnulib c-ctype code
rather than safe-ctype.h.  The gdb-safe-ctype.h header is removed.

This changes common-defs.h to include the c-ctype header, making it
available everywhere in gdb.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33217
---
 gdb/c-exp.y                     | 18 +++++++--------
 gdb/c-lang.c                    | 10 ++++-----
 gdb/c-support.h                 | 10 ++++-----
 gdb/completer.c                 |  2 +-
 gdb/cp-name-parser.y            | 11 +++++----
 gdb/cp-support.c                |  9 ++++----
 gdb/dictionary.c                |  3 +--
 gdb/disasm.c                    |  1 -
 gdb/dwarf2/cooked-index-entry.c |  3 +--
 gdb/mi/mi-cmd-stack.c           |  1 -
 gdb/minsyms.c                   |  1 -
 gdb/minsyms.h                   |  2 +-
 gdb/or1k-tdep.c                 |  1 -
 gdb/printcmd.c                  |  1 -
 gdb/riscv-tdep.c                |  5 ++---
 gdb/tui/tui-layout.c            |  7 +++---
 gdb/tui/tui-winsource.c         |  3 +--
 gdb/utils.c                     | 46 ++++++++++++++++++--------------------
 gdb/xml-support.c               |  5 ++---
 gdbserver/linux-low.cc          |  3 +--
 gdbsupport/common-defs.h        |  6 +++++
 gdbsupport/common-utils.cc      | 21 +++++++++---------
 gdbsupport/gdb-safe-ctype.h     | 49 -----------------------------------------
 23 files changed, 78 insertions(+), 140 deletions(-)

diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 14d4b704ff1f5731804b1d3bab4c00649dac40ea..15682a5f33523c7321fd8c1131e5077d8e94f2a0 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -1969,13 +1969,13 @@ parse_number (struct parser_state *par_state,
 	  len -= 2;
 	}
       /* Handle suffixes: 'f' for float, 'l' for long double.  */
-      else if (len >= 1 && TOLOWER (buf[len - 1]) == 'f')
+      else if (len >= 1 && c_tolower (buf[len - 1]) == 'f')
 	{
 	  putithere->typed_val_float.type
 	    = parse_type (par_state)->builtin_float;
 	  len -= 1;
 	}
-      else if (len >= 1 && TOLOWER (buf[len - 1]) == 'l')
+      else if (len >= 1 && c_tolower (buf[len - 1]) == 'l')
 	{
 	  putithere->typed_val_float.type
 	    = parse_type (par_state)->builtin_long_double;
@@ -2181,9 +2181,9 @@ c_parse_escape (const char **ptr, struct obstack *output)
       if (output)
 	obstack_grow_str (output, "\\x");
       ++tokptr;
-      if (!ISXDIGIT (*tokptr))
+      if (!c_isxdigit (*tokptr))
 	error (_("\\x escape without a following hex digit"));
-      while (ISXDIGIT (*tokptr))
+      while (c_isxdigit (*tokptr))
 	{
 	  if (output)
 	    obstack_1grow (output, *tokptr);
@@ -2206,7 +2206,7 @@ c_parse_escape (const char **ptr, struct obstack *output)
 	if (output)
 	  obstack_grow_str (output, "\\");
 	for (i = 0;
-	     i < 3 && ISDIGIT (*tokptr) && *tokptr != '8' && *tokptr != '9';
+	     i < 3 && c_isdigit (*tokptr) && *tokptr != '8' && *tokptr != '9';
 	     ++i)
 	  {
 	    if (output)
@@ -2231,9 +2231,9 @@ c_parse_escape (const char **ptr, struct obstack *output)
 	    obstack_1grow (output, *tokptr);
 	  }
 	++tokptr;
-	if (!ISXDIGIT (*tokptr))
+	if (!c_isxdigit (*tokptr))
 	  error (_("\\%c escape without a following hex digit"), c);
-	for (i = 0; i < len && ISXDIGIT (*tokptr); ++i)
+	for (i = 0; i < len && c_isxdigit (*tokptr); ++i)
 	  {
 	    if (output)
 	      obstack_1grow (output, *tokptr);
@@ -2818,7 +2818,7 @@ lex_one_token (struct parser_state *par_state, bool *is_quoted_name)
 	    size_t len = strlen ("selector");
 
 	    if (strncmp (p, "selector", len) == 0
-		&& (p[len] == '\0' || ISSPACE (p[len])))
+		&& (p[len] == '\0' || c_isspace (p[len])))
 	      {
 		pstate->lexptr = p + len;
 		return SELECTOR;
@@ -2827,7 +2827,7 @@ lex_one_token (struct parser_state *par_state, bool *is_quoted_name)
 	      goto parse_string;
 	  }
 
-	while (ISSPACE (*p))
+	while (c_isspace (*p))
 	  p++;
 	size_t len = strlen ("entry");
 	if (strncmp (p, "entry", len) == 0 && !c_ident_is_alnum (p[len])
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 9fccc1f761452cc6cb33644a28869a659ab26398..7fff11a76f75c71f569bf1583ed1c1cd9c09e48f 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -408,7 +408,7 @@ convert_ucn (const char *p, const char *limit, const char *dest_charset,
   gdb_byte data[4];
   int i;
 
-  for (i = 0; i < length && p < limit && ISXDIGIT (*p); ++i, ++p)
+  for (i = 0; i < length && p < limit && c_isxdigit (*p); ++i, ++p)
     result = (result << 4) + fromhex (*p);
 
   for (i = 3; i >= 0; --i)
@@ -450,7 +450,7 @@ convert_octal (struct type *type, const char *p,
   unsigned long value = 0;
 
   for (i = 0;
-       i < 3 && p < limit && ISDIGIT (*p) && *p != '8' && *p != '9';
+       i < 3 && p < limit && c_isdigit (*p) && *p != '8' && *p != '9';
        ++i)
     {
       value = 8 * value + fromhex (*p);
@@ -473,7 +473,7 @@ convert_hex (struct type *type, const char *p,
 {
   unsigned long value = 0;
 
-  while (p < limit && ISXDIGIT (*p))
+  while (p < limit && c_isxdigit (*p))
     {
       value = 16 * value + fromhex (*p);
       ++p;
@@ -518,7 +518,7 @@ convert_escape (struct type *type, const char *dest_charset,
 
     case 'x':
       advance ();
-      if (!ISXDIGIT (*p))
+      if (!c_isxdigit (*p))
 	error (_("\\x used with no following hex digits."));
       p = convert_hex (type, p, limit, output);
       break;
@@ -540,7 +540,7 @@ convert_escape (struct type *type, const char *dest_charset,
 	int length = *p == 'u' ? 4 : 8;
 
 	advance ();
-	if (!ISXDIGIT (*p))
+	if (!c_isxdigit (*p))
 	  error (_("\\u used with no following hex digits"));
 	p = convert_ucn (p, limit, dest_charset, output, length);
       }
diff --git a/gdb/c-support.h b/gdb/c-support.h
index 47f40661a0905ebc722ef82f243ca724bb0fdf19..5fd1118e592f3b1ecbb1e5535fe430abbbec48a9 100644
--- a/gdb/c-support.h
+++ b/gdb/c-support.h
@@ -19,9 +19,7 @@
 #ifndef GDB_C_SUPPORT_H
 #define GDB_C_SUPPORT_H
 
-#include "safe-ctype.h"
-
-/* Like ISALPHA, but also returns true for the union of all UTF-8
+/* Like isalpha, but also returns true for the union of all UTF-8
    multi-byte sequence bytes and non-ASCII characters in
    extended-ASCII charsets (e.g., Latin1).  I.e., returns true if the
    high bit is set.  Note that not all UTF-8 ranges are allowed in C++
@@ -32,15 +30,15 @@
 static inline bool
 c_ident_is_alpha (unsigned char ch)
 {
-  return ISALPHA (ch) || ch >= 0x80;
+  return c_isalpha (ch) || ch >= 0x80;
 }
 
-/* Similarly, but Like ISALNUM.  */
+/* Similarly, but Like isalnum.  */
 
 static inline bool
 c_ident_is_alnum (unsigned char ch)
 {
-  return ISALNUM (ch) || ch >= 0x80;
+  return c_isalnum (ch) || ch >= 0x80;
 }
 
 #endif /* GDB_C_SUPPORT_H */
diff --git a/gdb/completer.c b/gdb/completer.c
index deecbc209f7d2308edd86ae42589ac112e717365..b919b4c4dc35c10473c7b8988881857a1cb71d20 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -3006,7 +3006,7 @@ gdb_printable_part (char *pathname)
 
   temp = strrchr (pathname, '/');
 #if defined (__MSDOS__)
-  if (temp == 0 && ISALPHA ((unsigned char)pathname[0]) && pathname[1] == ':')
+  if (temp == 0 && c_isalpha (pathname[0]) && pathname[1] == ':')
     temp = pathname + 1;
 #endif
 
diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y
index cafd6b2367abd73005bee62b66521e1a03c5fc7b..7221b785211d44d8407c45f75a46251caad18104 100644
--- a/gdb/cp-name-parser.y
+++ b/gdb/cp-name-parser.y
@@ -39,7 +39,6 @@
 
 
 #include <unistd.h>
-#include "gdbsupport/gdb-safe-ctype.h"
 #include "demangle.h"
 #include "cp-support.h"
 #include "c-support.h"
@@ -1362,7 +1361,7 @@ cpname_state::parse_number (const char *p, int len, int parsed_float,
 
       /* See if it has `f' or `l' suffix (float or long double).  */
 
-      c = TOLOWER (p[len - 1]);
+      c = c_tolower (p[len - 1]);
 
       if (c == 'f')
       	{
@@ -1374,7 +1373,7 @@ cpname_state::parse_number (const char *p, int len, int parsed_float,
 	  len--;
 	  type = make_builtin_type ("long double");
 	}
-      else if (ISDIGIT (c) || c == '.')
+      else if (c_isdigit (c) || c == '.')
 	type = make_builtin_type ("double");
       else
 	return ERROR;
@@ -1439,10 +1438,10 @@ cpname_state::parse_number (const char *p, int len, int parsed_float,
   for (int off = 0; off < len; ++off)
     {
       int dig;
-      if (ISDIGIT (p[off]))
+      if (c_isdigit (p[off]))
 	dig = p[off] - '0';
       else
-	dig = TOLOWER (p[off]) - 'a' + 10;
+	dig = c_tolower (p[off]) - 'a' + 10;
       if (dig >= base)
 	return ERROR;
       value *= base;
@@ -1769,7 +1768,7 @@ yylex (YYSTYPE *lvalp, cpname_state *state)
 	      }
 	    /* We will take any letters or digits.  parse_number will
 	       complain if past the radix, or if L or U are not final.  */
-	    else if (! ISALNUM (*p))
+	    else if (! c_isalnum (*p))
 	      break;
 	    if (no_tick.has_value ())
 	      no_tick->push_back (*p);
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index cab711051dc16af867e0c8e47493936a0a10d8e6..d31fbbfe50128832c7c766f1092a6e1d426fac28 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -35,7 +35,6 @@
 #include "namespace.h"
 #include <signal.h>
 #include "gdbsupport/gdb_setjmp.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 #include "gdbsupport/selftest.h"
 #include "gdbsupport/gdb-sigmask.h"
 #include <atomic>
@@ -105,7 +104,7 @@ static int
 cp_already_canonical (const char *string)
 {
   /* Identifier start character [a-zA-Z_].  */
-  if (!ISIDST (string[0]))
+  if (!c_isalpha (string[0]) || string[0] == '_')
     return 0;
 
   /* These are the only two identifiers which canonicalize to other
@@ -117,7 +116,7 @@ cp_already_canonical (const char *string)
     return 0;
 
   /* Identifier character [a-zA-Z0-9_].  */
-  while (ISIDNUM (string[1]))
+  while (c_isalpha (string[1]) || c_isdigit (string[1]) || string[1] == '_')
     string++;
 
   if (string[1] == '\0')
@@ -1135,7 +1134,7 @@ cp_find_first_component_aux (const char *name, int permissive)
 	      && startswith (name + index, CP_OPERATOR_STR))
 	    {
 	      index += CP_OPERATOR_LEN;
-	      while (ISSPACE(name[index]))
+	      while (c_isspace(name[index]))
 		++index;
 	      switch (name[index])
 		{
@@ -2349,7 +2348,7 @@ find_toplevel_char (const char *s, char c)
 	      scan += CP_OPERATOR_LEN;
 	      if (*scan == c)
 		return scan;
-	      while (ISSPACE (*scan))
+	      while (c_isspace (*scan))
 		{
 		  ++scan;
 		  if (*scan == c)
diff --git a/gdb/dictionary.c b/gdb/dictionary.c
index 28e900d9c07a9c39c89a8aa3dffb90d7a1b635ac..17c9b448f592cf4ed5b8308c89d2ea8844d42c9e 100644
--- a/gdb/dictionary.c
+++ b/gdb/dictionary.c
@@ -25,7 +25,6 @@
 #include "symtab.h"
 #include "buildsym.h"
 #include "dictionary.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 #include "gdbsupport/unordered_map.h"
 #include "language.h"
 
@@ -772,7 +771,7 @@ language_defn::search_name_hash (const char *string0) const
 
 	      if (c == 'B' && string[3] == '_')
 		{
-		  for (string += 4; ISDIGIT (*string); ++string)
+		  for (string += 4; c_isdigit (*string); ++string)
 		    ;
 		  continue;
 		}
diff --git a/gdb/disasm.c b/gdb/disasm.c
index b7311923618509537de01a9f25357ee3b3df6636..c8e830ed471cb66e4f1f102e4c1bd1bab229609b 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -28,7 +28,6 @@
 #include "cli/cli-cmds.h"
 #include "dis-asm.h"
 #include "source.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 #include <algorithm>
 #include <optional>
 #include "valprint.h"
diff --git a/gdb/dwarf2/cooked-index-entry.c b/gdb/dwarf2/cooked-index-entry.c
index 863ddd6499c4578e2156f89872adb7ab09297b0b..a5e3fcb6caaad517f4b7a2033c234c7688ee70bc 100644
--- a/gdb/dwarf2/cooked-index-entry.c
+++ b/gdb/dwarf2/cooked-index-entry.c
@@ -19,7 +19,6 @@
 
 #include "dwarf2/cooked-index-entry.h"
 #include "dwarf2/tag.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 #include "gdbsupport/selftest.h"
 
 /* See cooked-index-entry.h.  */
@@ -57,7 +56,7 @@ cooked_index_entry::compare (const char *stra, const char *strb,
 	 template functions" section in the manual.  */
       if (c == '<')
 	return '\0';
-      return TOLOWER ((unsigned char) c);
+      return c_tolower (c);
     };
 
   unsigned char a = munge (*stra);
diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c
index cc26747cfa0e3a4d04b1103daa52b75c18251cc8..9ee2d27b70e40b4d6e89a1b4205b9b1bcf635244 100644
--- a/gdb/mi/mi-cmd-stack.c
+++ b/gdb/mi/mi-cmd-stack.c
@@ -32,7 +32,6 @@
 #include <ctype.h>
 #include "mi-parse.h"
 #include <optional>
-#include "gdbsupport/gdb-safe-ctype.h"
 #include "inferior.h"
 
 enum what_to_list { locals, arguments, all };
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 4a6459a6f2d2f5543c511c4e01788a6e7b430b41..2cf3d9d1c683ad875d9185160c3f4995d416da95 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -52,7 +52,6 @@
 #include "cli/cli-utils.h"
 #include "gdbsupport/symbol.h"
 #include <algorithm>
-#include "gdbsupport/gdb-safe-ctype.h"
 #include "gdbsupport/parallel-for.h"
 #include "inferior.h"
 
diff --git a/gdb/minsyms.h b/gdb/minsyms.h
index 709faa5e8f4ce3de303ef2bc0c99babadcf3b9f3..dcab475bcd31e32bcee0cc7f9fc3f00d46667259 100644
--- a/gdb/minsyms.h
+++ b/gdb/minsyms.h
@@ -195,7 +195,7 @@ unsigned int msymbol_hash_iw (const char *);
    requirements.  */
 
 #define SYMBOL_HASH_NEXT(hash, c)			\
-  ((hash) * 67 + TOLOWER ((unsigned char) (c)) - 113)
+  ((hash) * 67 + c_tolower (c) - 113)
 
 \f
 
diff --git a/gdb/or1k-tdep.c b/gdb/or1k-tdep.c
index 27748401f6f8c72596de7f766f3b50aea6f5bcaa..2db207dafdd1439fbc0f8490c20bdcfdcc8b4e02 100644
--- a/gdb/or1k-tdep.c
+++ b/gdb/or1k-tdep.c
@@ -29,7 +29,6 @@
 #include "gdbtypes.h"
 #include "target.h"
 #include "regcache.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 #include "reggroups.h"
 #include "arch-utils.h"
 #include "frame-unwind.h"
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 19fbc20074e03bf1787fa1a43e373768d447c5ee..f0487479f6875c51151db6cb70280548e994b52b 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -54,7 +54,6 @@
 #include "source.h"
 #include "gdbsupport/byte-vector.h"
 #include <optional>
-#include "gdbsupport/gdb-safe-ctype.h"
 #include "inferior.h"
 
 /* Chain containing all defined memory-tag subcommands.  */
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index f5b85230e71114eac7b112ba26fd0ac0b5e2ef13..ea8c475afa1cd94b9017cdc72187b41df549ce94 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -56,7 +56,6 @@
 #include "arch/riscv.h"
 #include "record-full.h"
 #include "riscv-ravenscar-thread.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 
 #include <vector>
 
@@ -4183,9 +4182,9 @@ riscv_print_insn (bfd_vma addr, struct disassemble_info *info)
 static int
 riscv_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
 {
-  return (ISDIGIT (*s) /* Literal number.  */
+  return (c_isdigit (*s) /* Literal number.  */
 	  || *s == '(' /* Register indirection.  */
-	  || ISALPHA (*s)); /* Register value.  */
+	  || c_isalpha (*s)); /* Register value.  */
 }
 
 /* String that appears before a register name in a SystemTap register
diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 558055d4edd9c2aa08cc8af29d285abc927430f4..95d20fbf22cf82d9852bd8a451a8c2bccd09826e 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -37,7 +37,6 @@
 #include "tui/tui-layout.h"
 #include "tui/tui-source.h"
 #include "gdb_curses.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 
 /* The layouts.  */
 static std::vector<std::unique_ptr<tui_layout_split>> layouts;
@@ -381,14 +380,14 @@ tui_register_window (const char *name, window_factory &&factory)
 
   for (const char &c : name_copy)
     {
-      if (ISSPACE (c))
+      if (c_isspace (c))
 	error (_("invalid whitespace character in window name"));
 
-      if (!ISALNUM (c) && strchr ("-_.", c) == nullptr)
+      if (!c_isalnum (c) && strchr ("-_.", c) == nullptr)
 	error (_("invalid character '%c' in window name"), c);
     }
 
-  if (!ISALPHA (name_copy[0]))
+  if (!c_isalpha (name_copy[0]))
     error (_("window name must start with a letter, not '%c'"), name_copy[0]);
 
   /* We already check above for all the builtin window names.  If we get
diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c
index a545c4870e1e8d2128ffd1676514c359f0537212..fe2e0fadd33a6bfa6d14246d5c91fb21ed484357 100644
--- a/gdb/tui/tui-winsource.c
+++ b/gdb/tui/tui-winsource.c
@@ -26,7 +26,6 @@
 #include "value.h"
 #include "source.h"
 #include "objfiles.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 
 #include "tui/tui.h"
 #include "tui/tui-data.h"
@@ -109,7 +108,7 @@ tui_copy_source_line (const char **ptr, int *length)
 	}
       else if (c == '\t')
 	process_tab ();
-      else if (ISCNTRL (c))
+      else if (c_iscntrl (c))
 	{
 	  result.push_back ('^');
 	  result.push_back (c + 0100);
diff --git a/gdb/utils.c b/gdb/utils.c
index 10d3d51e481b789a4f060c6071139d4c01c976bd..c1a36025b6cfe70f997e750b8175d86bd9a8deb6 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -75,7 +75,6 @@
 #include "gdbsupport/scope-exit.h"
 #include "gdbarch.h"
 #include "cli-out.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 #include "bt-utils.h"
 #include "gdbsupport/buildargv.h"
 #include "pager.h"
@@ -1008,7 +1007,7 @@ parse_escape (struct gdbarch *gdbarch, const char **string_ptr)
 	  while (++count < 3)
 	    {
 	      c = (**string_ptr);
-	      if (ISDIGIT (c) && c != '8' && c != '9')
+	      if (c_isdigit (c) && c != '8' && c != '9')
 		{
 		  (*string_ptr)++;
 		  i *= 8;
@@ -2053,7 +2052,7 @@ fprintf_symbol (struct ui_file *stream, const char *name,
 static bool
 valid_identifier_name_char (int ch)
 {
-  return (ISALNUM (ch) || ch == '_');
+  return (c_isalnum (ch) || ch == '_');
 }
 
 /* Skip to end of token, or to END, whatever comes first.  Input is
@@ -2063,7 +2062,7 @@ static const char *
 cp_skip_operator_token (const char *token, const char *end)
 {
   const char *p = token;
-  while (p != end && !ISSPACE (*p) && *p != '(')
+  while (p != end && !c_isspace (*p) && *p != '(')
     {
       if (valid_identifier_name_char (*p))
 	{
@@ -2117,9 +2116,9 @@ cp_skip_operator_token (const char *token, const char *end)
 static void
 skip_ws (const char *&string1, const char *&string2, const char *end_str2)
 {
-  while (ISSPACE (*string1))
+  while (c_isspace (*string1))
     string1++;
-  while (string2 < end_str2 && ISSPACE (*string2))
+  while (string2 < end_str2 && c_isspace (*string2))
     string2++;
 }
 
@@ -2183,7 +2182,7 @@ skip_template_parameter_list (const char **name)
       /* Skip any whitespace that might occur after the closing of the
 	 parameter list, but only if it is the end of parameter list.  */
       const char *q = p;
-      while (ISSPACE (*q))
+      while (c_isspace (*q))
 	++q;
       if (*q == '>')
 	p = q;
@@ -2215,8 +2214,8 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
   while (1)
     {
       if (skip_spaces
-	  || ((ISSPACE (*string1) && !valid_identifier_name_char (*string2))
-	      || (ISSPACE (*string2) && !valid_identifier_name_char (*string1))))
+	  || ((c_isspace (*string1) && !valid_identifier_name_char (*string2))
+	      || (c_isspace (*string2) && !valid_identifier_name_char (*string1))))
 	{
 	  skip_ws (string1, string2, end_str2);
 	  skip_spaces = false;
@@ -2249,7 +2248,7 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
 	  if (match_for_lcd != NULL && abi_start != string1)
 	    match_for_lcd->mark_ignored_range (abi_start, string1);
 
-	  while (ISSPACE (*string1))
+	  while (c_isspace (*string1))
 	    string1++;
 	}
 
@@ -2316,9 +2315,9 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
 	  string1++;
 	  string2++;
 
-	  while (ISSPACE (*string1))
+	  while (c_isspace (*string1))
 	    string1++;
-	  while (string2 < end_str2 && ISSPACE (*string2))
+	  while (string2 < end_str2 && c_isspace (*string2))
 	    string2++;
 	  continue;
 	}
@@ -2418,14 +2417,13 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
       if (case_sensitivity == case_sensitive_on && *string1 != *string2)
 	break;
       if (case_sensitivity == case_sensitive_off
-	  && (TOLOWER ((unsigned char) *string1)
-	      != TOLOWER ((unsigned char) *string2)))
+	  && c_tolower (*string1) != c_tolower (*string2))
 	break;
 
       /* If we see any non-whitespace, non-identifier-name character
 	 (any of "()<>*&" etc.), then skip spaces the next time
 	 around.  */
-      if (!ISSPACE (*string1) && !valid_identifier_name_char (*string1))
+      if (!c_isspace (*string1) && !valid_identifier_name_char (*string1))
 	skip_spaces = true;
 
       string1++;
@@ -3138,16 +3136,16 @@ strcmp_iw_ordered (const char *string1, const char *string2)
 
       while (*string1 != '\0' && *string2 != '\0')
 	{
-	  while (ISSPACE (*string1))
+	  while (c_isspace (*string1))
 	    string1++;
-	  while (ISSPACE (*string2))
+	  while (c_isspace (*string2))
 	    string2++;
 
 	  switch (case_pass)
 	  {
 	    case case_sensitive_off:
-	      c1 = TOLOWER ((unsigned char) *string1);
-	      c2 = TOLOWER ((unsigned char) *string2);
+	      c1 = c_tolower (*string1);
+	      c2 = c_tolower (*string2);
 	      break;
 	    case case_sensitive_on:
 	      c1 = *string1;
@@ -3256,17 +3254,17 @@ string_to_core_addr (const char *my_string)
 {
   CORE_ADDR addr = 0;
 
-  if (my_string[0] == '0' && TOLOWER (my_string[1]) == 'x')
+  if (my_string[0] == '0' && c_tolower (my_string[1]) == 'x')
     {
       /* Assume that it is in hex.  */
       int i;
 
       for (i = 2; my_string[i] != '\0'; i++)
 	{
-	  if (ISDIGIT (my_string[i]))
+	  if (c_isdigit (my_string[i]))
 	    addr = (my_string[i] - '0') + (addr * 16);
-	  else if (ISXDIGIT (my_string[i]))
-	    addr = (TOLOWER (my_string[i]) - 'a' + 0xa) + (addr * 16);
+	  else if (c_isxdigit (my_string[i]))
+	    addr = (c_tolower (my_string[i]) - 'a' + 0xa) + (addr * 16);
 	  else
 	    error (_("invalid hex \"%s\""), my_string);
 	}
@@ -3278,7 +3276,7 @@ string_to_core_addr (const char *my_string)
 
       for (i = 0; my_string[i] != '\0'; i++)
 	{
-	  if (ISDIGIT (my_string[i]))
+	  if (c_isdigit (my_string[i]))
 	    addr = (my_string[i] - '0') + (addr * 10);
 	  else
 	    error (_("invalid decimal \"%s\""), my_string);
diff --git a/gdb/xml-support.c b/gdb/xml-support.c
index 08524f85309dc8af7ab2d3f74f1929d28984194f..ebf6ea6b966c4007bee9066d4fb6defdeba17a10 100644
--- a/gdb/xml-support.c
+++ b/gdb/xml-support.c
@@ -21,7 +21,6 @@
 #include "xml-builtin.h"
 #include "xml-support.h"
 #include "gdbsupport/filestuff.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 #include <vector>
 #include <string>
 
@@ -430,10 +429,10 @@ gdb_xml_parser::end_element (const XML_Char *name)
 	  body = scope->body.c_str ();
 
 	  /* Strip leading and trailing whitespace.  */
-	  while (length > 0 && ISSPACE (body[length - 1]))
+	  while (length > 0 && c_isspace (body[length - 1]))
 	    length--;
 	  scope->body.erase (length);
-	  while (*body && ISSPACE (*body))
+	  while (*body && c_isspace (*body))
 	    body++;
 	}
 
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 39642705b0d8bc614e7da84f0d0e1c34cd045b12..6d0a7a363719982886c4d1104a7f5b7b6a4d7235 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -46,7 +46,6 @@
 #include <langinfo.h>
 #include <iconv.h>
 #include "gdbsupport/filestuff.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 #include "tracepoint.h"
 #include <inttypes.h>
 #include "gdbsupport/common-inferior.h"
@@ -6990,7 +6989,7 @@ replace_non_ascii (char *dest, const char *name)
   const char *result = dest;
   while (*name != '\0')
     {
-      if (!ISPRINT (*name))
+      if (!c_isprint (*name))
 	*dest++ = '?';
       else
 	*dest++ = *name;
diff --git a/gdbsupport/common-defs.h b/gdbsupport/common-defs.h
index 8d7e2a9353c198adbcb63f5473634702a3c4e563..6f58914ccd5855a3df08b503baf65a40c6e85708 100644
--- a/gdbsupport/common-defs.h
+++ b/gdbsupport/common-defs.h
@@ -222,6 +222,12 @@
 /* Pull in gdb::unique_xmalloc_ptr.  */
 #include "gdbsupport/gdb_unique_ptr.h"
 
+/* Note that there's no simple way to enforce the use of the c-ctype
+   functions.  We can't poison the <ctype.h> functions (see
+   safe-ctype.h) because that will provoke errors from libstdc++
+   headers.  */
+#include "c-ctype.h"
+
 /* sbrk on macOS is not useful for our purposes, since sbrk(0) always
    returns the same value.  brk/sbrk on macOS is just an emulation
    that always returns a pointer to a 4MB section reserved for
diff --git a/gdbsupport/common-utils.cc b/gdbsupport/common-utils.cc
index 266d836b3c69899af3118ba0d8c58f9a1089140e..5c7ba313996ac8521d0329d623ba71283b2f1071 100644
--- a/gdbsupport/common-utils.cc
+++ b/gdbsupport/common-utils.cc
@@ -19,7 +19,6 @@
 
 #include "common-utils.h"
 #include "host-defs.h"
-#include "gdbsupport/gdb-safe-ctype.h"
 #include "gdbsupport/gdb-xfree.h"
 
 void *
@@ -180,7 +179,7 @@ extract_string_maybe_quoted (const char **arg)
   /* Parse p similarly to gdb_argv buildargv function.  */
   while (*p != '\0')
     {
-      if (ISSPACE (*p) && !squote && !dquote && !bsquote)
+      if (c_isspace (*p) && !squote && !dquote && !bsquote)
 	break;
       else
 	{
@@ -254,21 +253,21 @@ make_quoted_string (const char *str)
 static int
 is_digit_in_base (unsigned char digit, int base)
 {
-  if (!ISALNUM (digit))
+  if (!c_isalnum (digit))
     return 0;
   if (base <= 10)
-    return (ISDIGIT (digit) && digit < base + '0');
+    return (c_isdigit (digit) && digit < base + '0');
   else
-    return (ISDIGIT (digit) || TOLOWER (digit) < base - 10 + 'a');
+    return (c_isdigit (digit) || c_tolower (digit) < base - 10 + 'a');
 }
 
 static int
 digit_to_int (unsigned char c)
 {
-  if (ISDIGIT (c))
+  if (c_isdigit (c))
     return c - '0';
   else
-    return TOLOWER (c) - 'a' + 10;
+    return c_tolower (c) - 'a' + 10;
 }
 
 /* As for strtoul, but for ULONGEST results.  */
@@ -282,7 +281,7 @@ strtoulst (const char *num, const char **trailer, int base)
   int i = 0;
 
   /* Skip leading whitespace.  */
-  while (ISSPACE (num[i]))
+  while (c_isspace (num[i]))
     i++;
 
   /* Handle prefixes.  */
@@ -349,7 +348,7 @@ skip_spaces (char *chp)
 {
   if (chp == NULL)
     return NULL;
-  while (*chp && ISSPACE (*chp))
+  while (*chp && c_isspace (*chp))
     chp++;
   return chp;
 }
@@ -361,7 +360,7 @@ skip_spaces (const char *chp)
 {
   if (chp == NULL)
     return NULL;
-  while (*chp && ISSPACE (*chp))
+  while (*chp && c_isspace (*chp))
     chp++;
   return chp;
 }
@@ -373,7 +372,7 @@ skip_to_space (const char *chp)
 {
   if (chp == NULL)
     return NULL;
-  while (*chp && !ISSPACE (*chp))
+  while (*chp && !c_isspace (*chp))
     chp++;
   return chp;
 }
diff --git a/gdbsupport/gdb-safe-ctype.h b/gdbsupport/gdb-safe-ctype.h
deleted file mode 100644
index 36b78f58ca8ae569c8bae37dcb3157351d00cc43..0000000000000000000000000000000000000000
--- a/gdbsupport/gdb-safe-ctype.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Wrapper around libiberty's safe-ctype.h for GDB, the GNU debugger.
-
-   Copyright (C) 2019-2025 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 GDBSUPPORT_GDB_SAFE_CTYPE_H
-#define GDBSUPPORT_GDB_SAFE_CTYPE_H
-
-/* After safe-ctype.h is included, we can no longer use the host's
-   ctype routines.  Trying to do so results in compile errors.  Code
-   that uses safe-ctype.h that wants to refer to the locale-dependent
-   ctype functions must call these wrapper versions instead.
-   When compiling in C++ mode, also include <locale> before "safe-ctype.h"
-   which also defines is* functions.  */
-
-static inline int
-gdb_isprint (int ch)
-{
-  return isprint (ch);
-}
-
-/* readline.h defines these symbols too, but we want libiberty's
-   versions.  */
-#undef ISALPHA
-#undef ISALNUM
-#undef ISDIGIT
-#undef ISLOWER
-#undef ISPRINT
-#undef ISUPPER
-#undef ISXDIGIT
-
-#include <locale>
-#include "safe-ctype.h"
-
-#endif /* GDBSUPPORT_GDB_SAFE_CTYPE_H */

-- 
2.50.1


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

* [PATCH 3/3] Use gnulib c-ctype module in gdb
  2025-08-06 13:13 [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h> Tom Tromey
  2025-08-06 13:13 ` [PATCH 1/3] Import the c-ctype module from gnulib Tom Tromey
  2025-08-06 13:13 ` [PATCH 2/3] Use c-ctype.h (not safe-ctype.h) in gdb Tom Tromey
@ 2025-08-06 13:13 ` Tom Tromey
  2025-08-06 19:46 ` [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h> Simon Marchi
  2025-10-14 13:00 ` Guinevere Larsen
  4 siblings, 0 replies; 16+ messages in thread
From: Tom Tromey @ 2025-08-06 13:13 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

PR ada/33217 points out that gdb incorrectly calls the <ctype.h>
functions.  In particular, gdb feels free to pass a 'char' like:

    char *str = ...;
    ... isdigit (*str)

This is incorrect as isdigit only accepts EOF and values that can be
represented as 'unsigned char' -- that is, a cast is needed here to
avoid undefined behavior when 'char' is signed and a character in the
string might be sign-extended.  (As an aside, I think this API seems
obviously bad, but unfortunately this is what the standard says, and
some systems check this.)

Rather than adding casts everywhere, this changes all the code in gdb
that uses any <ctype.h> API to instead call the corresponding c-ctype
function.

Now, c-ctype has some limitations compared to <ctype.h>.  It works as
if the C locale is in effect, so in theory some non-ASCII characters
may be misclassified.  This would only affect a subset of character
sets, though, and in most places I think ASCII is sufficient -- for
example the many places in gdb that check for whitespace.
Furthermore, in practice most users are using UTF-8-based locales,
where these functions aren't really informative for non-ASCII
characters anyway; see the existing workarounds in gdb/c-support.h.

Note that safe-ctype.h cannot be used because it causes conflicts with
readline.h.  And, we canot poison the <ctype.h> identifiers as this
provokes errors from some libstdc++ headers.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33217
---
 gdb/aarch64-linux-tdep.c              |  9 ++--
 gdb/ada-exp.y                         |  5 +-
 gdb/ada-lang.c                        | 87 +++++++++++++++++------------------
 gdb/ada-lex.l                         | 23 +++++----
 gdb/ada-typeprint.c                   |  3 +-
 gdb/ada-valprint.c                    |  5 +-
 gdb/arm-linux-tdep.c                  |  9 ++--
 gdb/arm-tdep.c                        |  1 -
 gdb/auto-load.c                       |  3 +-
 gdb/break-catch-exec.c                |  4 +-
 gdb/break-catch-fork.c                |  2 +-
 gdb/break-catch-syscall.c             |  3 +-
 gdb/break-catch-throw.c               |  3 +-
 gdb/break-cond-parse.c                |  4 +-
 gdb/breakpoint.c                      |  7 ++-
 gdb/btrace.c                          |  5 +-
 gdb/c-exp.y                           |  1 -
 gdb/c-lang.c                          |  1 -
 gdb/charset.c                         |  1 -
 gdb/cli/cli-cmds.c                    | 16 +++----
 gdb/cli/cli-decode.c                  |  9 ++--
 gdb/cli/cli-dump.c                    |  1 -
 gdb/cli/cli-option.c                  |  4 +-
 gdb/cli/cli-script.c                  |  7 ++-
 gdb/cli/cli-setshow.c                 |  3 +-
 gdb/cli/cli-utils.c                   | 27 ++++++-----
 gdb/coff-pe-read.c                    |  3 +-
 gdb/coffread.c                        |  7 ++-
 gdb/d-exp.y                           | 22 ++++-----
 gdb/darwin-nat.c                      |  1 -
 gdb/dictionary.c                      |  1 -
 gdb/dwarf2/index-common.c             | 10 ++--
 gdb/dwarf2/read.c                     |  4 +-
 gdb/eval.c                            |  1 -
 gdb/exec.c                            |  3 +-
 gdb/expprint.c                        |  1 -
 gdb/f-exp.y                           |  5 +-
 gdb/fbsd-nat.c                        |  2 +-
 gdb/findcmd.c                         |  7 ++-
 gdb/gdb_wchar.h                       |  4 +-
 gdb/gnu-nat.c                         |  3 +-
 gdb/gnu-v2-abi.c                      |  3 +-
 gdb/go-exp.y                          |  9 ++--
 gdb/go-lang.c                         |  3 +-
 gdb/go32-nat.c                        |  1 -
 gdb/guile/scm-cmd.c                   |  1 -
 gdb/i386-tdep.c                       | 25 +++++-----
 gdb/ia64-linux-tdep.c                 |  5 +-
 gdb/infcmd.c                          |  7 ++-
 gdb/infrun.c                          |  3 +-
 gdb/language.c                        |  1 -
 gdb/linespec.c                        | 19 ++++----
 gdb/linux-fork.c                      |  3 +-
 gdb/linux-nat.c                       |  1 -
 gdb/linux-tdep.c                      | 17 ++++---
 gdb/linux-thread-db.c                 |  1 -
 gdb/location.c                        | 17 ++++---
 gdb/main.c                            |  3 +-
 gdb/maint.c                           |  5 +-
 gdb/mi/mi-cmd-break.c                 |  3 +-
 gdb/mi/mi-cmd-stack.c                 |  1 -
 gdb/mi/mi-cmd-var.c                   |  3 +-
 gdb/mi/mi-main.c                      |  1 -
 gdb/mi/mi-parse.c                     | 11 ++---
 gdb/minsyms.c                         |  1 -
 gdb/nat/linux-osdata.c                | 15 +++---
 gdb/netbsd-nat.c                      |  2 +-
 gdb/objc-lang.c                       | 13 +++---
 gdb/p-exp.y                           | 17 ++++---
 gdb/p-lang.c                          |  1 -
 gdb/p-typeprint.c                     |  5 +-
 gdb/parse.c                           |  1 -
 gdb/ppc-linux-tdep.c                  | 13 +++---
 gdb/probe.c                           |  3 +-
 gdb/procfs.c                          |  5 +-
 gdb/producer.c                        |  4 +-
 gdb/python/py-mi.c                    |  6 +--
 gdb/python/py-micmd.c                 |  4 +-
 gdb/python/py-objfile.c               |  2 +-
 gdb/python/python.c                   |  1 -
 gdb/record.c                          |  9 ++--
 gdb/remote-sim.c                      |  1 -
 gdb/remote.c                          |  7 ++-
 gdb/rust-lang.c                       |  3 +-
 gdb/s12z-tdep.c                       |  2 +-
 gdb/s390-tdep.c                       |  4 +-
 gdb/serial.c                          |  3 +-
 gdb/solib-rocm.c                      |  6 +--
 gdb/stabsread.c                       |  7 ++-
 gdb/stack.c                           |  4 +-
 gdb/stap-probe.c                      | 23 +++++----
 gdb/symfile.c                         |  3 +-
 gdb/symtab.c                          | 17 ++++---
 gdb/thread.c                          |  5 +-
 gdb/tid-parse.c                       |  7 ++-
 gdb/top.c                             |  1 -
 gdb/tracectf.c                        |  1 -
 gdb/tracepoint.c                      |  6 +--
 gdb/tui/tui-win.c                     |  3 +-
 gdb/typeprint.c                       |  5 +-
 gdb/unittests/command-def-selftests.c |  4 +-
 gdb/utils.c                           |  1 -
 gdb/valprint.c                        |  1 -
 gdb/value.c                           |  5 +-
 gdb/windows-nat.c                     |  6 +--
 gdb/xcoffread.c                       |  1 -
 gdbserver/gdbreplay.cc                |  1 -
 gdbserver/remote-utils.cc             |  7 ++-
 gdbserver/server.cc                   |  9 ++--
 gdbserver/thread-db.cc                |  3 +-
 gdbserver/tracepoint.cc               |  3 +-
 gdbsupport/pathstuff.cc               |  2 +-
 112 files changed, 312 insertions(+), 401 deletions(-)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index dd35eaff9143a6d0fecf9dc44d3c27dd591ca0d1..f1daea63b91d2ab6c73f0282eea3133937455363 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -46,7 +46,6 @@
 #include "parser-defs.h"
 #include "user-regs.h"
 #include "xml-syscall.h"
-#include <ctype.h>
 
 #include "record-full.h"
 #include "linux-record.h"
@@ -1666,9 +1665,9 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
 static int
 aarch64_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
 {
-  return (*s == '#' || isdigit (*s) /* Literal number.  */
+  return (*s == '#' || c_isdigit (*s) /* Literal number.  */
 	  || *s == '[' /* Register indirection.  */
-	  || isalpha (*s)); /* Register value.  */
+	  || c_isalpha (*s)); /* Register value.  */
 }
 
 /* This routine is used to parse a special token in AArch64's assembly.
@@ -1699,7 +1698,7 @@ aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
       start = tmp;
 
       /* Register name.  */
-      while (isalnum (*tmp))
+      while (c_isalnum (*tmp))
 	++tmp;
 
       if (*tmp != ',')
@@ -1727,7 +1726,7 @@ aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
       else if (*tmp == '+')
 	++tmp;
 
-      if (!isdigit (*tmp))
+      if (!c_isdigit (*tmp))
 	return {};
 
       displacement = strtol (tmp, &endp, 10);
diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index 1546ae950b004d3c2fdea42bc0b1ee30fa67b1be..5f0b3ae3247a30463098a11f5e4191085607a538 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -35,7 +35,6 @@
 
 %{
 
-#include <ctype.h>
 #include "gdbsupport/unordered_map.h"
 #include "expression.h"
 #include "value.h"
@@ -1380,7 +1379,7 @@ write_object_renaming (struct parser_state *par_state,
 	[[fallthrough]];
       case 'S':
 	renaming_expr += 1;
-	if (isdigit (*renaming_expr))
+	if (c_isdigit (*renaming_expr))
 	  {
 	    char *next;
 	    long val = strtol (renaming_expr, &next, 10);
@@ -1888,7 +1887,7 @@ ada_parse_state::find_completion_bounds ()
   const char *end = pstate->lexptr;
   /* First the end of the prefix.  Here we stop at the token start or
      at '.' or space.  */
-  for (; end > m_original_expr && end[-1] != '.' && !isspace (end[-1]); --end)
+  for (; end > m_original_expr && end[-1] != '.' && !c_isspace (end[-1]); --end)
     {
       /* Nothing.  */
     }
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 329d11479895fa5da6aaa837405a624dec86860e..438430de27cdaeb893cbf6458ea2f8f6f9531741 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -18,7 +18,6 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
-#include <ctype.h>
 #include "event-top.h"
 #include "exceptions.h"
 #include "extract-store-integer.h"
@@ -875,7 +874,7 @@ is_compiler_suffix (const char *str)
 {
   gdb_assert (*str == '[');
   ++str;
-  while (*str != '\0' && isalpha (*str))
+  while (*str != '\0' && c_isalpha (*str))
     ++str;
   /* We accept a missing "]" in order to support completion.  */
   return *str == '\0' || (str[0] == ']' && str[1] == '\0');
@@ -1167,7 +1166,7 @@ ada_encode (const char *decoded, bool fold)
 static int
 is_lower_alphanum (const char c)
 {
-  return (isdigit (c) || (isalpha (c) && islower (c)));
+  return (c_isdigit (c) || (c_isalpha (c) && c_islower (c)));
 }
 
 /* ENCODED is the linkage name of a symbol and LEN contains its length.
@@ -1185,11 +1184,11 @@ is_lower_alphanum (const char c)
 static void
 ada_remove_trailing_digits (const char *encoded, int *len)
 {
-  if (*len > 1 && isdigit (encoded[*len - 1]))
+  if (*len > 1 && c_isdigit (encoded[*len - 1]))
     {
       int i = *len - 2;
 
-      while (i > 0 && isdigit (encoded[i]))
+      while (i > 0 && c_isdigit (encoded[i]))
 	i--;
       if (i >= 0 && encoded[i] == '.')
 	*len = i;
@@ -1220,7 +1219,7 @@ ada_remove_po_subprogram_suffix (const char *encoded, int *len)
 
   if (*len > 1
       && encoded[*len - 1] == 'N'
-      && (isdigit (encoded[*len - 2]) || islower (encoded[*len - 2])))
+      && (c_isdigit (encoded[*len - 2]) || c_islower (encoded[*len - 2])))
     *len = *len - 1;
 }
 
@@ -1232,7 +1231,7 @@ static int
 remove_compiler_suffix (const char *encoded, int *len)
 {
   int offset = *len - 1;
-  while (offset > 0 && isalpha (encoded[offset]))
+  while (offset > 0 && c_isalpha (encoded[offset]))
     --offset;
   if (offset > 0 && encoded[offset] == '.')
     {
@@ -1252,7 +1251,7 @@ convert_hex (const char *str, int n, uint32_t *out)
 
   for (int i = 0; i < n; ++i)
     {
-      if (!isxdigit (str[i]))
+      if (!c_isxdigit (str[i]))
 	return false;
       result <<= 4;
       result |= fromhex (str[i]);
@@ -1384,11 +1383,11 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide)
 
   /* Remove trailing __{digit}+ or trailing ${digit}+.  */
 
-  if (len0 > 1 && isdigit (encoded[len0 - 1]))
+  if (len0 > 1 && c_isdigit (encoded[len0 - 1]))
     {
       i = len0 - 2;
-      while ((i >= 0 && isdigit (encoded[i]))
-	     || (i >= 1 && encoded[i] == '_' && isdigit (encoded[i - 1])))
+      while ((i >= 0 && c_isdigit (encoded[i]))
+	     || (i >= 1 && encoded[i] == '_' && c_isdigit (encoded[i - 1])))
 	i -= 1;
       if (i > 1 && encoded[i] == '_' && encoded[i - 1] == '_')
 	len0 = i - 1;
@@ -1399,7 +1398,7 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide)
   /* The first few characters that are not alphabetic are not part
      of any encoding we use, so we can copy them over verbatim.  */
 
-  for (i = 0; i < len0 && !isalpha (encoded[i]); i += 1)
+  for (i = 0; i < len0 && !c_isalpha (encoded[i]); i += 1)
     decoded.push_back (encoded[i]);
 
   at_start_name = 1;
@@ -1415,7 +1414,7 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide)
 	      int op_len = strlen (ada_opname_table[k].encoded);
 	      if ((strncmp (ada_opname_table[k].encoded + 1, encoded + i + 1,
 			    op_len - 1) == 0)
-		  && !isalnum (encoded[i + op_len]))
+		  && !c_isalnum (encoded[i + op_len]))
 		{
 		  decoded.append (ada_opname_table[k].decoded);
 		  at_start_name = 0;
@@ -1440,11 +1439,11 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide)
 
       if (len0 - i > 5 && encoded [i] == '_' && encoded [i+1] == '_'
 	  && encoded [i+2] == 'B' && encoded [i+3] == '_'
-	  && isdigit (encoded [i+4]))
+	  && c_isdigit (encoded [i+4]))
 	{
 	  int k = i + 5;
 	  
-	  while (k < len0 && isdigit (encoded[k]))
+	  while (k < len0 && c_isdigit (encoded[k]))
 	    k++;  /* Skip any extra digit.  */
 
 	  /* Double-check that the "__B_{DIGITS}+" sequence we found
@@ -1467,11 +1466,11 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide)
 	 internally generated.  */
 
       if (len0 - i > 3 && encoded [i] == '_' && encoded[i+1] == 'E'
-	  && isdigit (encoded[i+2]))
+	  && c_isdigit (encoded[i+2]))
 	{
 	  int k = i + 3;
 
-	  while (k < len0 && isdigit (encoded[k]))
+	  while (k < len0 && c_isdigit (encoded[k]))
 	    k++;
 
 	  if (k < len0
@@ -1505,7 +1504,7 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide)
 	    i++;
 	}
 
-      if (wide && i < len0 + 3 && encoded[i] == 'U' && isxdigit (encoded[i + 1]))
+      if (wide && i < len0 + 3 && encoded[i] == 'U' && c_isxdigit (encoded[i + 1]))
 	{
 	  if (convert_from_hex_encoded (decoded, &encoded[i + 1], 2))
 	    {
@@ -1513,7 +1512,7 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide)
 	      continue;
 	    }
 	}
-      else if (wide && i < len0 + 5 && encoded[i] == 'W' && isxdigit (encoded[i + 1]))
+      else if (wide && i < len0 + 5 && encoded[i] == 'W' && c_isxdigit (encoded[i + 1]))
 	{
 	  if (convert_from_hex_encoded (decoded, &encoded[i + 1], 4))
 	    {
@@ -1522,7 +1521,7 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide)
 	    }
 	}
       else if (wide && i < len0 + 10 && encoded[i] == 'W' && encoded[i + 1] == 'W'
-	       && isxdigit (encoded[i + 2]))
+	       && c_isxdigit (encoded[i + 2]))
 	{
 	  if (convert_from_hex_encoded (decoded, &encoded[i + 2], 8))
 	    {
@@ -1531,7 +1530,7 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide)
 	    }
 	}
 
-      if (encoded[i] == 'X' && i != 0 && isalnum (encoded[i - 1]))
+      if (encoded[i] == 'X' && i != 0 && c_isalnum (encoded[i - 1]))
 	{
 	  /* This is a X[bn]* sequence not separated from the previous
 	     part of the name with a non-alpha-numeric character (in other
@@ -1568,7 +1567,7 @@ ada_decode (const char *encoded, bool wrap, bool operators, bool wide)
   if (operators)
     {
       for (i = 0; i < decoded.length(); ++i)
-	if (isupper (decoded[i]) || decoded[i] == ' ')
+	if (c_isupper (decoded[i]) || decoded[i] == ' ')
 	  goto Suppress;
     }
 
@@ -5732,10 +5731,10 @@ is_name_suffix (const char *str)
 
   /* Skip optional leading __[0-9]+.  */
 
-  if (len > 3 && str[0] == '_' && str[1] == '_' && isdigit (str[2]))
+  if (len > 3 && str[0] == '_' && str[1] == '_' && c_isdigit (str[2]))
     {
       str += 3;
-      while (isdigit (str[0]))
+      while (c_isdigit (str[0]))
 	str += 1;
     }
   
@@ -5744,7 +5743,7 @@ is_name_suffix (const char *str)
   if (str[0] == '.' || str[0] == '$')
     {
       matching = str + 1;
-      while (isdigit (matching[0]))
+      while (c_isdigit (matching[0]))
 	matching += 1;
       if (matching[0] == '\0')
 	return 1;
@@ -5755,7 +5754,7 @@ is_name_suffix (const char *str)
   if (len > 3 && str[0] == '_' && str[1] == '_' && str[2] == '_')
     {
       matching = str + 3;
-      while (isdigit (matching[0]))
+      while (c_isdigit (matching[0]))
 	matching += 1;
       if (matching[0] == '\0')
 	return 1;
@@ -5784,10 +5783,10 @@ is_name_suffix (const char *str)
 #endif
 
   /* _E[0-9]+[bs]$ */
-  if (len > 3 && str[0] == '_' && str [1] == 'E' && isdigit (str[2]))
+  if (len > 3 && str[0] == '_' && str [1] == 'E' && c_isdigit (str[2]))
     {
       matching = str + 3;
-      while (isdigit (matching[0]))
+      while (c_isdigit (matching[0]))
 	matching += 1;
       if ((matching[0] == 'b' || matching[0] == 's')
 	  && matching [1] == '\0')
@@ -5837,17 +5836,17 @@ is_name_suffix (const char *str)
 	    return 1;
 	  return 0;
 	}
-      if (!isdigit (str[2]))
+      if (!c_isdigit (str[2]))
 	return 0;
       for (k = 3; str[k] != '\0'; k += 1)
-	if (!isdigit (str[k]) && str[k] != '_')
+	if (!c_isdigit (str[k]) && str[k] != '_')
 	  return 0;
       return 1;
     }
-  if (str[0] == '$' && isdigit (str[1]))
+  if (str[0] == '$' && c_isdigit (str[1]))
     {
       for (k = 2; str[k] != '\0'; k += 1)
-	if (!isdigit (str[k]) && str[k] != '_')
+	if (!c_isdigit (str[k]) && str[k] != '_')
 	  return 0;
       return 1;
     }
@@ -5870,7 +5869,7 @@ is_valid_name_for_wild_match (const char *name0)
     return 0;
 
   for (i=0; decoded_name[i] != '\0'; i++)
-    if (isalpha (decoded_name[i]) && !islower (decoded_name[i]))
+    if (c_isalpha (decoded_name[i]) && !c_islower (decoded_name[i]))
       return 0;
 
   return 1;
@@ -6094,7 +6093,7 @@ ada_lookup_name_info::matches
 	 angle bracket notation.  */
       const char *tmp;
 
-      for (tmp = sym_name; *tmp != '\0' && !isupper (*tmp); tmp++);
+      for (tmp = sym_name; *tmp != '\0' && !c_isupper (*tmp); tmp++);
       if (*tmp != '\0')
 	match = false;
     }
@@ -6209,7 +6208,7 @@ ada_is_ignored_field (struct type *type, int field_num)
       {
 	/* Wrapper field.  */
       }
-    else if (isupper (name[0]))
+    else if (c_isupper (name[0]))
       return 1;
   }
 
@@ -6720,14 +6719,14 @@ ada_scan_number (const char str[], int k, LONGEST * R, int *new_k)
 {
   ULONGEST RU;
 
-  if (!isdigit (str[k]))
+  if (!c_isdigit (str[k]))
     return 0;
 
   /* Do it the hard way so as not to make any assumption about
      the relationship of unsigned long (%lu scan format code) and
      LONGEST.  */
   RU = 0;
-  while (isdigit (str[k]))
+  while (c_isdigit (str[k]))
     {
       RU = RU * 10 + (str[k] - '0');
       k += 1;
@@ -7384,10 +7383,10 @@ field_alignment (struct type *type, int f)
 
   len = strlen (name);
 
-  if (!isdigit (name[len - 1]))
+  if (!c_isdigit (name[len - 1]))
     return 1;
 
-  if (isdigit (name[len - 2]))
+  if (c_isdigit (name[len - 2]))
     align_offset = len - 2;
   else
     align_offset = len - 1;
@@ -8969,7 +8968,7 @@ ada_unqualify_enum_name (const char *name)
     {
       while ((tmp = strstr (name, "__")) != NULL)
 	{
-	  if (isdigit (tmp[2]))
+	  if (c_isdigit (tmp[2]))
 	    break;
 	  else
 	    name = tmp + 2;
@@ -9012,7 +9011,7 @@ ada_enum_name (const char *name)
       else
 	return name;
 
-      if (isascii (v) && isprint (v))
+      if (c_isascii (v) && c_isprint (v))
 	storage = string_printf ("'%c'", v);
       else if (name[1] == 'U')
 	storage = string_printf ("'[\"%02x\"]'", v);
@@ -12536,7 +12535,7 @@ catch_ada_exception_command_split (const char *args,
 
   args = skip_spaces (args);
   if (startswith (args, "if")
-      && (isspace (args[2]) || args[2] == '\0'))
+      && (c_isspace (args[2]) || args[2] == '\0'))
     {
       args += 2;
       args = skip_spaces (args);
@@ -12813,7 +12812,7 @@ catch_ada_assert_command_split (const char *args, std::string &cond_string)
 
   /* Check whether a condition was provided.  */
   if (startswith (args, "if")
-      && (isspace (args[2]) || args[2] == '\0'))
+      && (c_isspace (args[2]) || args[2] == '\0'))
     {
       args += 2;
       args = skip_spaces (args);
@@ -13217,7 +13216,7 @@ do_full_match (const char *symbol_search_name,
 	      && symbol_search_name[1] == '_')
 	    {
 	      symbol_search_name += 2;
-	      while (isdigit (*symbol_search_name))
+	      while (c_isdigit (*symbol_search_name))
 		++symbol_search_name;
 	      if (symbol_search_name[0] == '_'
 		  && symbol_search_name[1] == '_')
diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l
index 0cfa0c8c551d084027a24b560202055968c558a7..eec80cfb207308f4543f2924f0e46ab2b8c7d0e3 100644
--- a/gdb/ada-lex.l
+++ b/gdb/ada-lex.l
@@ -335,7 +335,6 @@ false		{ return FALSEKEYWORD; }
 .		{ error (_("Invalid character '%s' in expression."), yytext); }
 %%
 
-#include <ctype.h>
 /* Initialize the lexer for processing new expression. */
 
 static void
@@ -355,7 +354,7 @@ canonicalizeNumeral (char *s1, const char *s2)
     {
       if (*s2 != '_')
 	{
-	  *s1 = tolower(*s2);
+	  *s1 = c_tolower(*s2);
 	  s1 += 1;
 	}
     }
@@ -411,7 +410,7 @@ processInt (struct parser_state *par_state, const char *base0,
     exp = strtol(exp0, (char **) NULL, 10);
 
   gdb_mpz result;
-  while (isxdigit (*num0))
+  while (c_isxdigit (*num0))
     {
       int dig = fromhex (*num0);
       if (dig >= base)
@@ -527,7 +526,7 @@ processId (const char *name0, int len)
   struct stoken result;
 
   result.ptr = name;
-  while (len > 0 && isspace (name0[len-1]))
+  while (len > 0 && c_isspace (name0[len-1]))
     len -= 1;
 
   if (name0[0] == '<' || strstr (name0, "___") != NULL)
@@ -549,12 +548,12 @@ processId (const char *name0, int len)
 	}
       else if (in_quotes)
 	name[i++] = name0[i0++];
-      else if (isalnum (name0[i0]))
+      else if (c_isalnum (name0[i0]))
 	{
-	  name[i] = tolower (name0[i0]);
+	  name[i] = c_tolower (name0[i0]);
 	  i += 1; i0 += 1;
 	}
-      else if (isspace (name0[i0]))
+      else if (c_isspace (name0[i0]))
 	i0 += 1;
       else if (name0[i0] == '\'')
 	{
@@ -634,10 +633,10 @@ find_dot_all (const char *str)
 
 	do
 	  i += 1;
-	while (isspace (str[i]));
+	while (c_isspace (str[i]));
 
 	if (strncasecmp (str + i, "all", 3) == 0
-	    && !isalnum (str[i + 3]) && str[i + 3] != '_')
+	    && !c_isalnum (str[i + 3]) && str[i + 3] != '_')
 	  return i0;
       }
   return -1;
@@ -653,7 +652,7 @@ subseqMatch (const char *subseq, const char *str)
     return 1;
   else if (str[0] == '\0')
     return 0;
-  else if (tolower (subseq[0]) == tolower (str[0]))
+  else if (c_tolower (subseq[0]) == c_tolower (str[0]))
     return subseqMatch (subseq+1, str+1) || subseqMatch (subseq, str+1);
   else
     return subseqMatch (subseq, str+1);
@@ -690,7 +689,7 @@ processAttribute (const char *str)
 {
   gdb_assert (*str == '\'');
   ++str;
-  while (isspace (*str))
+  while (c_isspace (*str))
     ++str;
 
   int len = strlen (str);
@@ -749,7 +748,7 @@ static void
 rewind_to_char (int ch)
 {
   pstate->lexptr -= yyleng;
-  while (toupper (*pstate->lexptr) != toupper (ch))
+  while (c_toupper (*pstate->lexptr) != c_toupper (ch))
     pstate->lexptr -= 1;
   yyrestart (NULL);
 }
diff --git a/gdb/ada-typeprint.c b/gdb/ada-typeprint.c
index defd828934e6e1b5096738bb895871ab9ecd4139..5829a9b4ef365a64795e97e8bf892d4932779b5c 100644
--- a/gdb/ada-typeprint.c
+++ b/gdb/ada-typeprint.c
@@ -23,7 +23,6 @@
 #include "cli/cli-style.h"
 #include "typeprint.h"
 #include "ada-lang.h"
-#include <ctype.h>
 
 static int print_selected_record_field_types (struct type *, struct type *,
 					      int, int,
@@ -70,7 +69,7 @@ decoded_type_name (struct type *type)
       if (s == name_buffer)
 	return name_buffer;
 
-      if (!islower (s[1]))
+      if (!c_islower (s[1]))
 	return NULL;
 
       for (s = q = name_buffer; *s != '\0'; q += 1)
diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c
index 7c6826e49e2039af8ef5e58c5f272266b2e3eba9..c198fa519f86066c22a8448df8ddb864f58ce51f 100644
--- a/gdb/ada-valprint.c
+++ b/gdb/ada-valprint.c
@@ -17,7 +17,6 @@
    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 <ctype.h>
 #include "event-top.h"
 #include "extract-store-integer.h"
 #include "gdbtypes.h"
@@ -265,10 +264,10 @@ ada_emit_char (int c, struct type *type, struct ui_file *stream,
   /* If this character fits in the normal ASCII range, and is
      a printable character, then print the character as if it was
      an ASCII character, even if this is a wide character.
-     The UCHAR_MAX check is necessary because the isascii function
+     The UCHAR_MAX check is necessary because the c_isascii function
      requires that its argument have a value of an unsigned char,
      or EOF (EOF is obviously not printable).  */
-  if (c <= UCHAR_MAX && isascii (c) && isprint (c))
+  if (c <= UCHAR_MAX && c_isascii (c) && c_isprint (c))
     {
       if (c == quoter && c == '"')
 	gdb_printf (stream, "\"\"");
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index 2f034afcd8047109d89b384b506063cdb97d15c6..5f48467d97dba06bb21fb399934e6b9860d1dae0 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -56,7 +56,6 @@
 #include "stap-probe.h"
 #include "parser-defs.h"
 #include "user-regs.h"
-#include <ctype.h>
 #include "elf/common.h"
 
 /* Under ARM GNU/Linux the traditional way of performing a breakpoint
@@ -1162,10 +1161,10 @@ arm_linux_displaced_step_copy_insn (struct gdbarch *gdbarch,
 static int
 arm_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
 {
-  return (*s == '#' || *s == '$' || isdigit (*s) /* Literal number.  */
+  return (*s == '#' || *s == '$' || c_isdigit (*s) /* Literal number.  */
 	  || *s == '[' /* Register indirection or
 			  displacement.  */
-	  || isalpha (*s)); /* Register value.  */
+	  || c_isalpha (*s)); /* Register value.  */
 }
 
 /* This routine is used to parse a special token in ARM's assembly.
@@ -1197,7 +1196,7 @@ arm_stap_parse_special_token (struct gdbarch *gdbarch,
       start = tmp;
 
       /* Register name.  */
-      while (isalnum (*tmp))
+      while (c_isalnum (*tmp))
 	++tmp;
 
       if (*tmp != ',')
@@ -1207,7 +1206,7 @@ arm_stap_parse_special_token (struct gdbarch *gdbarch,
       regname = (char *) alloca (len + 2);
 
       offset = 0;
-      if (isdigit (*start))
+      if (c_isdigit (*start))
 	{
 	  /* If we are dealing with a register whose name begins with a
 	     digit, it means we should prefix the name with the letter
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index a7648250af6d6d30242c2245957c15ba924261d1..d7603dc9614208ea89e7e6c3640e63727a59bd30 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -18,7 +18,6 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
-#include <ctype.h>
 
 #include "extract-store-integer.h"
 #include "frame.h"
diff --git a/gdb/auto-load.c b/gdb/auto-load.c
index 114a7d56448e00d0adcc424edebf95cd8cbc0bc8..8817bd12cb0fee636bc0d43d3d139100cc8954f9 100644
--- a/gdb/auto-load.c
+++ b/gdb/auto-load.c
@@ -17,7 +17,6 @@
    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 <ctype.h>
 #include "auto-load.h"
 #include "gdbsupport/gdb_vecs.h"
 #include "progspace.h"
@@ -1045,7 +1044,7 @@ execute_script_contents (struct auto_load_pspace_info *pspace_info,
       buf = name_holder.c_str ();
       for (p = buf; *p != '\0'; ++p)
 	{
-	  if (isspace (*p))
+	  if (c_isspace (*p))
 	    break;
 	}
       /* We don't allow nameless scripts, they're not helpful to the user.  */
diff --git a/gdb/break-catch-exec.c b/gdb/break-catch-exec.c
index 570018c53e3e7d26e140434b8e44a71a79eb0d60..9bfdb442f441e34e8991ba4857d64e22ebbbcfc1 100644
--- a/gdb/break-catch-exec.c
+++ b/gdb/break-catch-exec.c
@@ -164,7 +164,7 @@ ep_parse_optional_if_clause (const char **arg)
 {
   const char *cond_string;
 
-  if (((*arg)[0] != 'i') || ((*arg)[1] != 'f') || !isspace ((*arg)[2]))
+  if (((*arg)[0] != 'i') || ((*arg)[1] != 'f') || !c_isspace ((*arg)[2]))
     return NULL;
 
   /* Skip the "if" keyword.  */
@@ -204,7 +204,7 @@ catch_exec_command_1 (const char *arg, int from_tty,
      First, check if there's an if clause.  */
   cond_string = ep_parse_optional_if_clause (&arg);
 
-  if ((*arg != '\0') && !isspace (*arg))
+  if ((*arg != '\0') && !c_isspace (*arg))
     error (_("Junk at end of arguments."));
 
   std::unique_ptr<exec_catchpoint> c
diff --git a/gdb/break-catch-fork.c b/gdb/break-catch-fork.c
index c8a63301f2b924f173299fc00e4dbf5775f389b7..535040c90f74ba88ddd68bd5d3f7c39bc2295b47 100644
--- a/gdb/break-catch-fork.c
+++ b/gdb/break-catch-fork.c
@@ -221,7 +221,7 @@ catch_fork_command_1 (const char *arg, int from_tty,
      First, check if there's an if clause.  */
   cond_string = ep_parse_optional_if_clause (&arg);
 
-  if ((*arg != '\0') && !isspace (*arg))
+  if ((*arg != '\0') && !c_isspace (*arg))
     error (_("Junk at end of arguments."));
 
   /* If this target supports it, create a fork or vfork catchpoint
diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
index 96f22a173fc9364210b6822789687619d36947c1..fad76e718d02225ac9a14112d09531c538071eaa 100644
--- a/gdb/break-catch-syscall.c
+++ b/gdb/break-catch-syscall.c
@@ -17,7 +17,6 @@
    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 <ctype.h>
 #include "breakpoint.h"
 #include "inferior.h"
 #include "cli/cli-utils.h"
@@ -369,7 +368,7 @@ catch_syscall_split_args (const char *arg)
       /* Skip whitespace.  */
       arg = skip_spaces (arg);
 
-      for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
+      for (i = 0; i < 127 && arg[i] && !c_isspace (arg[i]); ++i)
 	cur_name[i] = arg[i];
       cur_name[i] = '\0';
       arg += i;
diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
index 6da38ebfd70639d55fc487c28e714cc4ad027f0f..1a45d7c7498c6c90890327d0e516ade31887110a 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -18,7 +18,6 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "arch-utils.h"
-#include <ctype.h>
 #include "breakpoint.h"
 #include "exceptions.h"
 #include "inferior.h"
@@ -420,7 +419,7 @@ catch_exception_event (enum exception_event_kind ex_event,
 
   cond_string = ep_parse_optional_if_clause (&arg);
 
-  if ((*arg != '\0') && !isspace (*arg))
+  if ((*arg != '\0') && !c_isspace (*arg))
     error (_("Junk at end of arguments."));
 
   if (ex_event != EX_EVENT_THROW
diff --git a/gdb/break-cond-parse.c b/gdb/break-cond-parse.c
index 31b534371f1a846d2c5c8c799ee525ea80521dc7..b7713446e56f79846f66e6a65abf5a9a116ab371 100644
--- a/gdb/break-cond-parse.c
+++ b/gdb/break-cond-parse.c
@@ -66,12 +66,12 @@ find_next_token (const char **curr, parse_direction direction)
     {
       gdb_assert (direction == parse_direction::backward);
 
-      while (isspace (**curr))
+      while (c_isspace (**curr))
 	--(*curr);
 
       tok_end = *curr;
 
-      while (!isspace (**curr))
+      while (!c_isspace (**curr))
 	--(*curr);
 
       tok_start = (*curr) + 1;
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f795d7b9931359d07bc08abdd082604a7b41e59c..813388859b3100378e96347b176e65bdebaa45bf 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -18,7 +18,6 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "arch-utils.h"
-#include <ctype.h>
 #include "event-top.h"
 #include "exceptions.h"
 #include "gdbsupport/gdb_vecs.h"
@@ -1288,7 +1287,7 @@ condition_completer (struct cmd_list_element *cmd,
 	{
 	  tracker.advance_custom_word_point_by (1);
 	  /* We don't support completion of history indices.  */
-	  if (!isdigit (text[1]))
+	  if (!c_isdigit (text[1]))
 	    complete_internalvar (tracker, &text[1]);
 	  return;
 	}
@@ -10465,7 +10464,7 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
       int len;
 
       len = exp_end - exp_start;
-      while (len > 0 && isspace (exp_start[len - 1]))
+      while (len > 0 && c_isspace (exp_start[len - 1]))
 	len--;
       error (_("Cannot watch constant value `%.*s'."), len, exp_start);
     }
@@ -14128,7 +14127,7 @@ strace_command (const char *arg, int from_tty)
 
   /* Decide if we are dealing with a static tracepoint marker (`-m'),
      or with a normal static tracepoint.  */
-  if (arg && startswith (arg, "-m") && isspace (arg[2]))
+  if (arg && startswith (arg, "-m") && c_isspace (arg[2]))
     {
       ops = &strace_marker_breakpoint_ops;
       locspec = new_linespec_location_spec (&arg,
diff --git a/gdb/btrace.c b/gdb/btrace.c
index b23de887abef7fd950970c490d2430d296f6d78a..3d43261280fbea110bbd2e1d747d3118a0e6801d 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -39,7 +39,6 @@
 #include "record-btrace.h"
 
 #include <inttypes.h>
-#include <ctype.h>
 #include <algorithm>
 #include <string>
 
@@ -3258,7 +3257,7 @@ get_uint (const char **arg)
   begin = *arg;
   pos = skip_spaces (begin);
 
-  if (!isdigit (*pos))
+  if (!c_isdigit (*pos))
     error (_("Expected positive number, got: %s."), pos);
 
   number = strtoul (pos, &end, 10);
@@ -3277,7 +3276,7 @@ get_context_size (const char **arg)
 {
   const char *pos = skip_spaces (*arg);
 
-  if (!isdigit (*pos))
+  if (!c_isdigit (*pos))
     error (_("Expected positive number, got: %s."), pos);
 
   char *end;
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 15682a5f33523c7321fd8c1131e5077d8e94f2a0..5553ce81beb593f958fb0a894906530b3a08728f 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -35,7 +35,6 @@
 
 %{
 
-#include <ctype.h>
 #include "expression.h"
 #include "value.h"
 #include "parser-defs.h"
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 7fff11a76f75c71f569bf1583ed1c1cd9c09e48f..e8e66a6e19f6e449b576fad71b1ea8d5715b6952 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -33,7 +33,6 @@
 #include "cp-abi.h"
 #include "cp-support.h"
 #include "gdbsupport/gdb_obstack.h"
-#include <ctype.h>
 #include "gdbcore.h"
 #include "gdbarch.h"
 #include "c-exp.h"
diff --git a/gdb/charset.c b/gdb/charset.c
index 259362563b23675dce00d4147b927f26db34543c..fe725efcfd17f92aaec827dd4c9f3e24b1989940 100644
--- a/gdb/charset.c
+++ b/gdb/charset.c
@@ -24,7 +24,6 @@
 #include "charset-list.h"
 #include "gdbsupport/environ.h"
 #include "arch-utils.h"
-#include <ctype.h>
 
 #ifdef USE_WIN32API
 #include <windows.h>
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index a15a04a27fd50973052a30f410b717e9c91c1423..d3536547c337bff8a38f8a319fd341ddb27fdbcf 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -301,8 +301,8 @@ with_command_completer_1 (const char *set_cmd_prefix,
      command as if it was a "set" command.  */
   if (delim == text
       || delim == nullptr
-      || !isspace (delim[-1])
-      || !(isspace (delim[2]) || delim[2] == '\0'))
+      || !c_isspace (delim[-1])
+      || !(c_isspace (delim[2]) || delim[2] == '\0'))
     {
       std::string new_text = std::string (set_cmd_prefix) + text;
       tracker.advance_custom_word_point_by (-(int) strlen (set_cmd_prefix));
@@ -785,14 +785,14 @@ source_command (const char *args, int from_tty)
 	  if (args[0] != '-')
 	    break;
 
-	  if (args[1] == 'v' && isspace (args[2]))
+	  if (args[1] == 'v' && c_isspace (args[2]))
 	    {
 	      source_verbose = 1;
 
 	      /* Skip passed -v.  */
 	      args = &args[3];
 	    }
-	  else if (args[1] == 's' && isspace (args[2]))
+	  else if (args[1] == 's' && c_isspace (args[2]))
 	    {
 	      search_path = 1;
 
@@ -1184,7 +1184,7 @@ pipe_command_completer (struct cmd_list_element *ignore,
     delimiter = opts.delimiter.c_str ();
 
   /* Check if we're past option values already.  */
-  if (text > org_text && !isspace (text[-1]))
+  if (text > org_text && !c_isspace (text[-1]))
     return;
 
   const char *delim = strstr (text, delimiter);
@@ -1669,7 +1669,7 @@ disassemble_command (const char *arg, int from_tty)
       if (*p == '\0')
 	error (_("Missing modifier."));
 
-      while (*p && ! isspace (*p))
+      while (*p && ! c_isspace (*p))
 	{
 	  switch (*p++)
 	    {
@@ -1938,8 +1938,8 @@ alias_command_completer (struct cmd_list_element *ignore,
      typing COMMAND DEFAULT-ARGS...  */
   if (delim != text
       && delim != nullptr
-      && isspace (delim[-1])
-      && (isspace (delim[1]) || delim[1] == '\0'))
+      && c_isspace (delim[-1])
+      && (c_isspace (delim[1]) || delim[1] == '\0'))
     {
       std::string new_text = std::string (delim + 1);
 
diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index 48a34667c37ca708693a5d9f7af4734af8ccf4a9..2b30a6e04fb7b9ec732765ace102091f4a7ab511 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -16,7 +16,6 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "symtab.h"
-#include <ctype.h>
 #include "gdbsupport/gdb_regex.h"
 #include "completer.h"
 #include "ui-out.h"
@@ -2053,8 +2052,8 @@ print_doc_line (struct ui_file *stream, const char *str,
   if (for_value_prefix)
     {
       char &c = (*line_buffer)[0];
-      if (islower (c))
-	c = toupper (c);
+      if (c_islower (c))
+	c = c_toupper (c);
       if (line_buffer->back () == '.')
 	line_buffer->pop_back ();
     }
@@ -2227,7 +2226,7 @@ valid_cmd_char_p (int c)
   /* Alas "42" is a legitimate user-defined command.
      In the interests of not breaking anything we preserve that.  */
 
-  return isalnum (c) || c == '-' || c == '_' || c == '.';
+  return c_isalnum (c) || c == '-' || c == '_' || c == '.';
 }
 
 /* See command.h.  */
@@ -2491,7 +2490,7 @@ lookup_cmd (const char **line, struct cmd_list_element *list,
     }
   else
     {
-      if (c->type == set_cmd && **line != '\0' && !isspace (**line))
+      if (c->type == set_cmd && **line != '\0' && !c_isspace (**line))
 	error (_("Argument must be preceded by space."));
 
       /* We've got something.  It may still not be what the caller
diff --git a/gdb/cli/cli-dump.c b/gdb/cli/cli-dump.c
index afbbea6cd5861469a0667869507a7a2904ac9999..3cdd9a334d3cc3c4af22944eeaa6390bfd28dac2 100644
--- a/gdb/cli/cli-dump.c
+++ b/gdb/cli/cli-dump.c
@@ -23,7 +23,6 @@
 #include "cli/cli-cmds.h"
 #include "value.h"
 #include "completer.h"
-#include <ctype.h>
 #include "target.h"
 #include "readline/tilde.h"
 #include "gdbcore.h"
diff --git a/gdb/cli/cli-option.c b/gdb/cli/cli-option.c
index a30261e5c0fb4896686338872b4aa842d4d43d45..5da8c737c430e215518faad6abc07b1bdd580f5b 100644
--- a/gdb/cli/cli-option.c
+++ b/gdb/cli/cli-option.c
@@ -227,7 +227,7 @@ parse_option (gdb::array_view<const option_def_group> options_group,
 	      match = &o;
 	      match_ctx = grp.ctx;
 
-	      if ((isspace (arg[len]) || arg[len] == '\0')
+	      if ((c_isspace (arg[len]) || arg[len] == '\0')
 		  && strlen (o.name) == len)
 		break; /* Exact match.  */
 	    }
@@ -635,7 +635,7 @@ complete_options (completion_tracker &tracker,
 	      if (ov
 		  && !tracker.have_completions ()
 		  && **args == '\0'
-		  && *args > text && !isspace ((*args)[-1]))
+		  && *args > text && !c_isspace ((*args)[-1]))
 		{
 		  tracker.advance_custom_word_point_by
 		    (*args - text);
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index 3ea80a50f38798ffef10dad3d7f6a355b88ce471..048d3914ffd88f55fad149d7f6793efa923e9f17 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -19,7 +19,6 @@
 
 #include "event-top.h"
 #include "value.h"
-#include <ctype.h>
 
 #include "ui-out.h"
 #include "top.h"
@@ -829,7 +828,7 @@ locate_arg (const char *p)
   while ((p = strchr (p, '$')))
     {
       if (startswith (p, "$arg")
-	  && (isdigit (p[4]) || p[4] == 'c'))
+	  && (c_isdigit (p[4]) || p[4] == 'c'))
 	return p;
       p++;
     }
@@ -1324,9 +1323,9 @@ validate_comname (const char **comname)
 
   /* Find the last word of the argument.  */
   p = *comname + strlen (*comname);
-  while (p > *comname && isspace (p[-1]))
+  while (p > *comname && c_isspace (p[-1]))
     p--;
-  while (p > *comname && !isspace (p[-1]))
+  while (p > *comname && !c_isspace (p[-1]))
     p--;
   last_word = p;
 
diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c
index 4d4695f9456d2968b87324b9cb59fed2cfe43368..8528ac52148bbf705f6a0d21ab1b1e563f144a05 100644
--- a/gdb/cli/cli-setshow.c
+++ b/gdb/cli/cli-setshow.c
@@ -17,7 +17,6 @@
 
 #include "readline/tilde.h"
 #include "value.h"
-#include <ctype.h>
 #include "arch-utils.h"
 #include "observable.h"
 #include "interps.h"
@@ -49,7 +48,7 @@ parse_auto_binary_operation (const char *arg)
     {
       int length = strlen (arg);
 
-      while (isspace (arg[length - 1]) && length > 0)
+      while (c_isspace (arg[length - 1]) && length > 0)
 	length--;
 
       /* Note that "o" is ambiguous.  */
diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c
index 23706e00d3af23beb5903900c80695c798c480f9..d0ca594671d04e140978fc56411a24c27976049c 100644
--- a/gdb/cli/cli-utils.c
+++ b/gdb/cli/cli-utils.c
@@ -20,7 +20,6 @@
 #include "cli/cli-utils.h"
 #include "value.h"
 
-#include <ctype.h>
 
 /* See documentation in cli-utils.h.  */
 
@@ -46,7 +45,7 @@ get_ulongest (const char **pp, int trailer)
 	  /* Internal variable.  Make a copy of the name, so we can
 	     null-terminate it to pass to lookup_internalvar().  */
 	  const char *start = ++p;
-	  while (isalnum (*p) || *p == '_')
+	  while (c_isalnum (*p) || *p == '_')
 	    p++;
 	  std::string varname (start, p - start);
 	  if (!get_internalvar_integer (lookup_internalvar (varname.c_str ()),
@@ -67,7 +66,7 @@ get_ulongest (const char **pp, int trailer)
       p = end;
     }
 
-  if (!(isspace (*p) || *p == '\0' || *p == trailer))
+  if (!(c_isspace (*p) || *p == '\0' || *p == trailer))
     error (_("Trailing junk at: %s"), p);
   p = skip_spaces (p);
   *pp = p;
@@ -111,7 +110,7 @@ get_number_trailer (const char **pp, int trailer)
 	  const char *start = ++p;
 	  LONGEST longest_val;
 
-	  while (isalnum (*p) || *p == '_')
+	  while (c_isalnum (*p) || *p == '_')
 	    p++;
 	  varname = (char *) alloca (p - start + 1);
 	  strncpy (varname, start, p - start);
@@ -136,7 +135,7 @@ get_number_trailer (const char **pp, int trailer)
 	/* There is no number here.  (e.g. "cond a == b").  */
 	{
 	  /* Skip non-numeric token.  */
-	  while (*p && !isspace((int) *p))
+	  while (*p && !c_isspace((int) *p))
 	    ++p;
 	  /* Return zero, which caller must interpret as error.  */
 	  retval = 0;
@@ -144,10 +143,10 @@ get_number_trailer (const char **pp, int trailer)
       else
 	retval = atoi (p1);
     }
-  if (!(isspace (*p) || *p == '\0' || *p == trailer))
+  if (!(c_isspace (*p) || *p == '\0' || *p == trailer))
     {
       /* Trailing junk: return 0 and let caller print error msg.  */
-      while (!(isspace (*p) || *p == '\0' || *p == trailer))
+      while (!(c_isspace (*p) || *p == '\0' || *p == trailer))
 	++p;
       retval = 0;
     }
@@ -262,8 +261,8 @@ number_or_range_parser::get_number ()
 	 option rather than an incomplete range, so check for end of
 	 string as well.  */
       if (m_cur_tok[0] == '-'
-	  && !(isspace (m_cur_tok[-1])
-	       && (isalpha (m_cur_tok[1])
+	  && !(c_isspace (m_cur_tok[-1])
+	       && (c_isalpha (m_cur_tok[1])
 		   || m_cur_tok[1] == '-'
 		   || m_cur_tok[1] == '\0')))
 	{
@@ -293,7 +292,7 @@ number_or_range_parser::get_number ()
     }
   else
     {
-      if (isdigit (*(m_cur_tok + 1)))
+      if (c_isdigit (*(m_cur_tok + 1)))
 	error (_("negative value"));
       if (*(m_cur_tok + 1) == '$')
 	{
@@ -330,9 +329,9 @@ number_or_range_parser::finished () const
      integer, convenience var or negative convenience var.  */
   return (m_cur_tok == NULL || *m_cur_tok == '\0'
 	  || (!m_in_range
-	      && !(isdigit (*m_cur_tok) || *m_cur_tok == '$')
+	      && !(c_isdigit (*m_cur_tok) || *m_cur_tok == '$')
 	      && !(*m_cur_tok == '-'
-		   && (isdigit (m_cur_tok[1]) || m_cur_tok[1] == '$'))));
+		   && (c_isdigit (m_cur_tok[1]) || m_cur_tok[1] == '$'))));
 }
 
 /* Accept a number and a string-form list of numbers such as is 
@@ -370,7 +369,7 @@ number_is_in_list (const char *list, int number)
 const char *
 remove_trailing_whitespace (const char *start, const char *s)
 {
-  while (s > start && isspace (*(s - 1)))
+  while (s > start && c_isspace (*(s - 1)))
     --s;
 
   return s;
@@ -420,7 +419,7 @@ int
 check_for_argument (const char **str, const char *arg, int arg_len)
 {
   if (strncmp (*str, arg, arg_len) == 0
-      && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
+      && ((*str)[arg_len] == '\0' || c_isspace ((*str)[arg_len])))
     {
       *str += arg_len;
       *str = skip_spaces (*str);
diff --git a/gdb/coff-pe-read.c b/gdb/coff-pe-read.c
index 0061007b6fd27168483d4b6a6004f76818263230..9255555231f85c61c9001a79eba69243f999e29e 100644
--- a/gdb/coff-pe-read.c
+++ b/gdb/coff-pe-read.c
@@ -35,7 +35,6 @@
 #include "gdbsupport/common-utils.h"
 #include "coff/internal.h"
 
-#include <ctype.h>
 
 /* Internal section information */
 
@@ -189,7 +188,7 @@ add_pe_forwarded_sym (minimal_symbol_reader &reader,
       int i;
 
       for (i = 0; i < forward_dll_name_len; i++)
-	forward_qualified_name[i] = tolower (forward_qualified_name[i]);
+	forward_qualified_name[i] = c_tolower (forward_qualified_name[i]);
       msymbol = lookup_minimal_symbol (current_program_space,
 				       forward_qualified_name.c_str ());
     }
diff --git a/gdb/coffread.c b/gdb/coffread.c
index db18c43a505548720364560fc12c53e550acba77..06f235727bb6884d61b7daa76b99c77b3ac30e7a 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -25,7 +25,6 @@
 
 #include "bfd.h"
 #include "gdbsupport/gdb_obstack.h"
-#include <ctype.h>
 
 #include "coff/internal.h"
 #include "libcoff.h"
@@ -336,7 +335,7 @@ coff_locate_sections (bfd *abfd, asection *sectp, void *csip)
       /* We can have multiple .stab sections if linked with
 	 --split-by-reloc.  */
       for (s = name + sizeof ".stab" - 1; *s != '\0'; s++)
-	if (!isdigit (*s))
+	if (!c_isdigit (*s))
 	  break;
       if (*s == '\0')
 	csi->stabsects->push_back (sectp);
@@ -525,9 +524,9 @@ is_import_fixup_symbol (struct coff_symbol *cs,
   /* The name must start with "__fu<digits>__".  */
   if (!startswith (cs->c_name, "__fu"))
     return 0;
-  if (! isdigit (cs->c_name[4]))
+  if (! c_isdigit (cs->c_name[4]))
     return 0;
-  for (i = 5; cs->c_name[i] != '\0' && isdigit (cs->c_name[i]); i++)
+  for (i = 5; cs->c_name[i] != '\0' && c_isdigit (cs->c_name[i]); i++)
     /* Nothing, just incrementing index past all digits.  */;
   if (cs->c_name[i] != '_' || cs->c_name[i + 1] != '_')
     return 0;
diff --git a/gdb/d-exp.y b/gdb/d-exp.y
index e0ee75858b4188fc7a218efb697159b8b59a8e2e..e5931f9dd29193fcd329d375b1f27e388e35b5ce 100644
--- a/gdb/d-exp.y
+++ b/gdb/d-exp.y
@@ -38,7 +38,6 @@
 
 %{
 
-#include <ctype.h>
 #include "expression.h"
 #include "value.h"
 #include "parser-defs.h"
@@ -684,15 +683,15 @@ parse_number (struct parser_state *ps, const char *p,
       len = strlen (s);
 
       /* Check suffix for `i' , `fi' or `li' (idouble, ifloat or ireal).  */
-      if (len >= 1 && tolower (s[len - 1]) == 'i')
+      if (len >= 1 && c_tolower (s[len - 1]) == 'i')
 	{
-	  if (len >= 2 && tolower (s[len - 2]) == 'f')
+	  if (len >= 2 && c_tolower (s[len - 2]) == 'f')
 	    {
 	      putithere->typed_val_float.type
 		= parse_d_type (ps)->builtin_ifloat;
 	      len -= 2;
 	    }
-	  else if (len >= 2 && tolower (s[len - 2]) == 'l')
+	  else if (len >= 2 && c_tolower (s[len - 2]) == 'l')
 	    {
 	      putithere->typed_val_float.type
 		= parse_d_type (ps)->builtin_ireal;
@@ -706,13 +705,13 @@ parse_number (struct parser_state *ps, const char *p,
 	    }
 	}
       /* Check suffix for `f' or `l'' (float or real).  */
-      else if (len >= 1 && tolower (s[len - 1]) == 'f')
+      else if (len >= 1 && c_tolower (s[len - 1]) == 'f')
 	{
 	  putithere->typed_val_float.type
 	    = parse_d_type (ps)->builtin_float;
 	  len -= 1;
 	}
-      else if (len >= 1 && tolower (s[len - 1]) == 'l')
+      else if (len >= 1 && c_tolower (s[len - 1]) == 'l')
 	{
 	  putithere->typed_val_float.type
 	    = parse_d_type (ps)->builtin_real;
@@ -1133,8 +1132,8 @@ lex_one_token (struct parser_state *par_state)
 	    /* Hex exponents start with 'p', because 'e' is a valid hex
 	       digit and thus does not indicate a floating point number
 	       when the radix is hex.  */
-	    if ((!hex && !got_e && tolower (p[0]) == 'e')
-		|| (hex && !got_e && tolower (p[0] == 'p')))
+	    if ((!hex && !got_e && c_tolower (p[0]) == 'e')
+		|| (hex && !got_e && c_tolower (p[0] == 'p')))
 	      got_dot = got_e = 1;
 	    /* A '.' always indicates a decimal floating point number
 	       regardless of the radix.  If we have a '..' then its the
@@ -1142,7 +1141,8 @@ lex_one_token (struct parser_state *par_state)
 	    else if (!got_dot && (p[0] == '.' && p[1] != '.'))
 		got_dot = 1;
 	    /* This is the sign of the exponent, not the end of the number.  */
-	    else if (got_e && (tolower (p[-1]) == 'e' || tolower (p[-1]) == 'p')
+	    else if (got_e && (c_tolower (p[-1]) == 'e'
+			       || c_tolower (p[-1]) == 'p')
 		     && (*p == '-' || *p == '+'))
 	      continue;
 	    /* We will take any letters or digits, ignoring any embedded '_'.
@@ -1167,9 +1167,9 @@ lex_one_token (struct parser_state *par_state)
 	const char *p = &tokstart[1];
 	size_t len = strlen ("entry");
 
-	while (isspace (*p))
+	while (c_isspace (*p))
 	  p++;
-	if (strncmp (p, "entry", len) == 0 && !isalnum (p[len])
+	if (strncmp (p, "entry", len) == 0 && !c_isalnum (p[len])
 	    && p[len] != '_')
 	  {
 	    pstate->lexptr = &p[len];
diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index 7acf63948597dcb63539721f5cda76a03476b62f..e73b5a1395bc22805d693f9f68398b300c791794 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -47,7 +47,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <signal.h>
-#include <ctype.h>
 #include <sys/sysctl.h>
 #include <sys/proc.h>
 #include <libproc.h>
diff --git a/gdb/dictionary.c b/gdb/dictionary.c
index 17c9b448f592cf4ed5b8308c89d2ea8844d42c9e..e53331bed4575e0515f2967a66f737fbfa7971f0 100644
--- a/gdb/dictionary.c
+++ b/gdb/dictionary.c
@@ -20,7 +20,6 @@
    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 <ctype.h>
 #include "gdbsupport/gdb_obstack.h"
 #include "symtab.h"
 #include "buildsym.h"
diff --git a/gdb/dwarf2/index-common.c b/gdb/dwarf2/index-common.c
index c24c8fc6c27bb4cc02410c0b79a766b1cc42dd68..a314ce7b0e298762243c4eb88adb6f68e9f3ab7b 100644
--- a/gdb/dwarf2/index-common.c
+++ b/gdb/dwarf2/index-common.c
@@ -31,7 +31,7 @@ mapped_index_string_hash (int index_version, const void *p)
   while ((c = *str++) != 0)
     {
       if (index_version >= 5)
-	c = tolower (c);
+	c = c_tolower (c);
       r = r * 67 + c - 113;
     }
 
@@ -45,12 +45,12 @@ dwarf5_djb_hash (const char *str_)
 {
   const unsigned char *str = (const unsigned char *) str_;
 
-  /* Note: tolower here ignores UTF-8, which isn't fully compliant.
+  /* Note: c_tolower here ignores UTF-8, which isn't fully compliant.
      See http://dwarfstd.org/ShowIssue.php?issue=161027.1.  */
 
   uint32_t hash = 5381;
   while (int c = *str++)
-    hash = hash * 33 + tolower (c);
+    hash = hash * 33 + c_tolower (c);
   return hash;
 }
 
@@ -59,11 +59,11 @@ dwarf5_djb_hash (const char *str_)
 uint32_t
 dwarf5_djb_hash (std::string_view str)
 {
-  /* Note: tolower here ignores UTF-8, which isn't fully compliant.
+  /* Note: c_tolower here ignores UTF-8, which isn't fully compliant.
      See http://dwarfstd.org/ShowIssue.php?issue=161027.1.  */
 
   uint32_t hash = 5381;
   for (char c : str)
-    hash = hash * 33 + tolower (c & 0xff);
+    hash = hash * 33 + c_tolower (c & 0xff);
   return hash;
 }
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index ec8d376a7f2d9be22951cc78e5f3eab3edad21bb..edbd2a266b10cd489ddf129e64d36cd105fe59e2 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -13396,7 +13396,7 @@ ada_get_gnat_encoded_number (const char *encoding, int &k, gdb_mpz *result)
 {
   /* The next character should be an underscore ('_') followed
      by a digit.  */
-  if (encoding[k] != '_' || !isdigit (encoding[k + 1]))
+  if (encoding[k] != '_' || !c_isdigit (encoding[k + 1]))
     return false;
 
   /* Skip the underscore.  */
@@ -13404,7 +13404,7 @@ ada_get_gnat_encoded_number (const char *encoding, int &k, gdb_mpz *result)
   int start = k;
 
   /* Determine the number of digits for our number.  */
-  while (isdigit (encoding[k]))
+  while (c_isdigit (encoding[k]))
     k++;
   if (k == start)
     return false;
diff --git a/gdb/eval.c b/gdb/eval.c
index 539b700ad8ff08206efde54e6365fe5296aa7b05..4b6a4795616afea2c4446d1d040f952456911e84 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -38,7 +38,6 @@
 #include "gdbsupport/gdb_obstack.h"
 #include "objfiles.h"
 #include "typeprint.h"
-#include <ctype.h>
 #include "expop.h"
 #include "c-exp.h"
 #include "inferior.h"
diff --git a/gdb/exec.c b/gdb/exec.c
index c2a1f8a7adaa06768017fd8736d40ec671d467bb..ac58778245c0173f31ab37c3d4b18df8cb183820 100644
--- a/gdb/exec.c
+++ b/gdb/exec.c
@@ -42,7 +42,6 @@
 #include "readline/tilde.h"
 #include "gdbcore.h"
 
-#include <ctype.h>
 #include <sys/stat.h>
 #include "solib.h"
 #include <algorithm>
@@ -1015,7 +1014,7 @@ set_section_command (const char *args, int from_tty)
     error (_("Must specify section name and its virtual address"));
 
   /* Parse out section name.  */
-  for (secname = args; !isspace (*args); args++);
+  for (secname = args; !c_isspace (*args); args++);
   unsigned seclen = args - secname;
 
   /* Parse out new virtual address.  */
diff --git a/gdb/expprint.c b/gdb/expprint.c
index c87be741a12ee2d92ae4a5ffcde298f3cc427f90..a32b7acc4b36a9ddd0e21131a84ce8aaa73b0c5b 100644
--- a/gdb/expprint.c
+++ b/gdb/expprint.c
@@ -33,7 +33,6 @@
 #include "expop.h"
 #include "ada-exp.h"
 
-#include <ctype.h>
 
 /* Meant to be used in debug sessions, so don't export it in a header file.  */
 extern void ATTRIBUTE_USED debug_exp (struct expression *exp);
diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index 44ea11b650818fde2f21ebcc0558e0f75aa3acdb..53621b37a6a2b5ee8766139f2370e0b260795ca1 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -48,7 +48,6 @@
 #include "language.h"
 #include "f-lang.h"
 #include "block.h"
-#include <ctype.h>
 #include <algorithm>
 #include "type-stack.h"
 #include "f-exp.h"
@@ -1061,8 +1060,8 @@ parse_number (struct parser_state *par_state,
   while (len-- > 0)
     {
       c = *p++;
-      if (isupper (c))
-	c = tolower (c);
+      if (c_isupper (c))
+	c = c_tolower (c);
       if (len == 0 && c == 'l')
 	long_p = 1;
       else if (len == 0 && c == 'u')
diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
index 935b9479e6807b80a7df0e8359aa0bd90eb0116e..81bd6d98469b69e43ffd8bff8e10e62234008320 100644
--- a/gdb/fbsd-nat.c
+++ b/gdb/fbsd-nat.c
@@ -304,7 +304,7 @@ fbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
       if (pid == 0)
 	error (_("No current process: you must name one."));
     }
-  else if (built_argv.count () == 1 && isdigit (built_argv[0][0]))
+  else if (built_argv.count () == 1 && c_isdigit (built_argv[0][0]))
     pid = strtol (built_argv[0], NULL, 10);
   else
     error (_("Invalid arguments."));
diff --git a/gdb/findcmd.c b/gdb/findcmd.c
index 4e478779b6731e3d753e3cab36d5b9b5c0d62b7d..03c3fccad8675c220af16047341220d2f93c8abb 100644
--- a/gdb/findcmd.c
+++ b/gdb/findcmd.c
@@ -18,7 +18,6 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "arch-utils.h"
-#include <ctype.h>
 #include "cli/cli-cmds.h"
 #include "value.h"
 #include "target.h"
@@ -76,12 +75,12 @@ parse_find_args (const char *args, ULONGEST *max_countp,
     {
       ++s;
 
-      while (*s != '\0' && *s != '/' && !isspace (*s))
+      while (*s != '\0' && *s != '/' && !c_isspace (*s))
 	{
-	  if (isdigit (*s))
+	  if (c_isdigit (*s))
 	    {
 	      max_count = atoi (s);
-	      while (isdigit (*s))
+	      while (c_isdigit (*s))
 		++s;
 	      continue;
 	    }
diff --git a/gdb/gdb_wchar.h b/gdb/gdb_wchar.h
index 417d5bab739575bf427fffe55faa49ef97d21ea3..9db0d5e043a7c8b743fc1136418812410d3883db 100644
--- a/gdb/gdb_wchar.h
+++ b/gdb/gdb_wchar.h
@@ -113,8 +113,8 @@ typedef char gdb_wchar_t;
 typedef int gdb_wint_t;
 
 #define gdb_wcslen strlen
-#define gdb_iswprint isprint
-#define gdb_iswxdigit isxdigit
+#define gdb_iswprint c_isprint
+#define gdb_iswxdigit c_isxdigit
 #define gdb_btowc /* empty */
 #define gdb_WEOF EOF
 
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index dd639fec8a91343033ea621f08c87a90c04b1a4a..33391ba35f2bc85629817002303884ac4fda2088 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -50,7 +50,6 @@ extern "C"
 }
 
 
-#include <ctype.h>
 #include <setjmp.h>
 #include <signal.h>
 #include <sys/ptrace.h>
@@ -2926,7 +2925,7 @@ set_sig_thread_cmd (const char *args, int from_tty)
 {
   struct inf *inf = cur_inf ();
 
-  if (!args || (!isdigit (*args) && strcmp (args, "none") != 0))
+  if (!args || (!c_isdigit (*args) && strcmp (args, "none") != 0))
     error (_("Illegal argument to \"set signal-thread\" command.\n"
 	     "Should be a thread ID, or \"none\"."));
 
diff --git a/gdb/gnu-v2-abi.c b/gdb/gnu-v2-abi.c
index 924678819a7f4bfd37af0cef37d35f95d6cbce3c..1fbc41d2c39cb4416714d89354d23dfc863c9f4b 100644
--- a/gdb/gnu-v2-abi.c
+++ b/gdb/gnu-v2-abi.c
@@ -26,7 +26,6 @@
 #include "gdb-demangle.h"
 #include "cp-abi.h"
 #include "cp-support.h"
-#include <ctype.h>
 
 static cp_abi_ops gnu_v2_abi_ops;
 
@@ -46,7 +45,7 @@ static enum ctor_kinds
 gnuv2_is_constructor_name (const char *name)
 {
   if ((name[0] == '_' && name[1] == '_'
-       && (isdigit (name[2]) || strchr ("Qt", name[2])))
+       && (c_isdigit (name[2]) || strchr ("Qt", name[2])))
       || startswith (name, "__ct__"))
     return complete_object_ctor;
   else
diff --git a/gdb/go-exp.y b/gdb/go-exp.y
index 8823503a2c9301915cba2c55fa0b9a993152cf60..b74c18596fb4de4672042ccaa7317ae5a62bb3f3 100644
--- a/gdb/go-exp.y
+++ b/gdb/go-exp.y
@@ -51,7 +51,6 @@
 
 %{
 
-#include <ctype.h>
 #include "expression.h"
 #include "value.h"
 #include "parser-defs.h"
@@ -663,13 +662,13 @@ parse_number (struct parser_state *par_state,
 
       /* Handle suffixes: 'f' for float32, 'l' for long double.
 	 FIXME: This appears to be an extension -- do we want this?  */
-      if (len >= 1 && tolower (p[len - 1]) == 'f')
+      if (len >= 1 && c_tolower (p[len - 1]) == 'f')
 	{
 	  putithere->typed_val_float.type
 	    = builtin_go_types->builtin_float32;
 	  len--;
 	}
-      else if (len >= 1 && tolower (p[len - 1]) == 'l')
+      else if (len >= 1 && c_tolower (p[len - 1]) == 'l')
 	{
 	  putithere->typed_val_float.type
 	    = parse_type (par_state)->builtin_long_double;
@@ -1113,9 +1112,9 @@ lex_one_token (struct parser_state *par_state)
 	const char *p = &tokstart[1];
 	size_t len = strlen ("entry");
 
-	while (isspace (*p))
+	while (c_isspace (*p))
 	  p++;
-	if (strncmp (p, "entry", len) == 0 && !isalnum (p[len])
+	if (strncmp (p, "entry", len) == 0 && !c_isalnum (p[len])
 	    && p[len] != '_')
 	  {
 	    par_state->lexptr = &p[len];
diff --git a/gdb/go-lang.c b/gdb/go-lang.c
index bad2ccfc35a67b27452d3e46941ba3ca4bdf9b52..23ffedb042ab3a170ac37c84b4ccf9bdbaa2b863 100644
--- a/gdb/go-lang.c
+++ b/gdb/go-lang.c
@@ -41,7 +41,6 @@
 #include "parser-defs.h"
 #include "gdbarch.h"
 
-#include <ctype.h>
 
 /* The main function in the main package.  */
 static const char GO_MAIN_MAIN[] = "main.main";
@@ -292,7 +291,7 @@ unpack_mangled_go_symbol (const char *mangled_name,
   while (p > buf)
     {
       int current = *(const unsigned char *) --p;
-      int current_is_digit = isdigit (current);
+      int current_is_digit = c_isdigit (current);
 
       if (saw_digit)
 	{
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index 4d8e6c9fee0d36b02f2251fb77113d6abe275915..ab13b57411490e725965c3393ca8f9df558bcd1a 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -103,7 +103,6 @@
 #include "cli/cli-utils.h"
 #include "inf-child.h"
 
-#include <ctype.h>
 #include <unistd.h>
 #include <sys/utsname.h>
 #include <io.h>
diff --git a/gdb/guile/scm-cmd.c b/gdb/guile/scm-cmd.c
index 19fb742f7f166e2c130e956b32cd150b07410799..ef4c9d6b011e70788f828d5097b56055a284c553 100644
--- a/gdb/guile/scm-cmd.c
+++ b/gdb/guile/scm-cmd.c
@@ -20,7 +20,6 @@
 /* See README file in this directory for implementation notes, coding
    conventions, et.al.  */
 
-#include <ctype.h>
 #include "charset.h"
 #include "cli/cli-cmds.h"
 #include "cli/cli-decode.h"
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index f97c98e6a40ecba246771af59e7ea5525ae7288b..5588b1fbb0337580faf968d91479351c87fc46d7 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -61,7 +61,6 @@
 #include "stap-probe.h"
 #include "user-regs.h"
 #include "expression.h"
-#include <ctype.h>
 #include <algorithm>
 #include <unordered_set>
 #include "producer.h"
@@ -3879,9 +3878,9 @@ int
 i386_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
 {
   return (*s == '$' /* Literal number.  */
-	  || (isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement.  */
+	  || (c_isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement.  */
 	  || (*s == '(' && s[1] == '%') /* Register indirection.  */
-	  || (*s == '%' && isalpha (s[1]))); /* Register access.  */
+	  || (*s == '%' && c_isalpha (s[1]))); /* Register access.  */
 }
 
 /* Helper function for i386_stap_parse_special_token.
@@ -3898,7 +3897,7 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
 {
   const char *s = p->arg;
 
-  if (isdigit (*s) || *s == '-' || *s == '+')
+  if (c_isdigit (*s) || *s == '-' || *s == '+')
     {
       bool got_minus[3];
       int i;
@@ -3916,7 +3915,7 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
 	  got_minus[0] = true;
 	}
 
-      if (!isdigit ((unsigned char) *s))
+      if (!c_isdigit (*s))
 	return {};
 
       displacements[0] = strtol (s, &endp, 10);
@@ -3937,7 +3936,7 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
 	  got_minus[1] = true;
 	}
 
-      if (!isdigit ((unsigned char) *s))
+      if (!c_isdigit (*s))
 	return {};
 
       displacements[1] = strtol (s, &endp, 10);
@@ -3958,7 +3957,7 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
 	  got_minus[2] = true;
 	}
 
-      if (!isdigit ((unsigned char) *s))
+      if (!c_isdigit (*s))
 	return {};
 
       displacements[2] = strtol (s, &endp, 10);
@@ -3970,7 +3969,7 @@ i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
       s += 2;
       start = s;
 
-      while (isalnum (*s))
+      while (c_isalnum (*s))
 	++s;
 
       if (*s++ != ')')
@@ -4031,7 +4030,7 @@ i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
 {
   const char *s = p->arg;
 
-  if (isdigit (*s) || *s == '(' || *s == '-' || *s == '+')
+  if (c_isdigit (*s) || *s == '(' || *s == '-' || *s == '+')
     {
       bool offset_minus = false;
       long offset = 0;
@@ -4049,10 +4048,10 @@ i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
 	  offset_minus = true;
 	}
 
-      if (offset_minus && !isdigit (*s))
+      if (offset_minus && !c_isdigit (*s))
 	return {};
 
-      if (isdigit (*s))
+      if (c_isdigit (*s))
 	{
 	  char *endp;
 
@@ -4066,7 +4065,7 @@ i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
       s += 2;
       start = s;
 
-      while (isalnum (*s))
+      while (c_isalnum (*s))
 	++s;
 
       if (*s != ',' || s[1] != '%')
@@ -4082,7 +4081,7 @@ i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
       s += 2;
       start = s;
 
-      while (isalnum (*s))
+      while (c_isalnum (*s))
 	++s;
 
       len_index = s - start;
diff --git a/gdb/ia64-linux-tdep.c b/gdb/ia64-linux-tdep.c
index 6afffeea4e3bda9c39fd713e2bc9a890ead48d8a..8b4e1f95291bf1c4c1972ebca1acb412a83abf55 100644
--- a/gdb/ia64-linux-tdep.c
+++ b/gdb/ia64-linux-tdep.c
@@ -29,7 +29,6 @@
 #include "solib-svr4-linux.h"
 #include "regset.h"
 
-#include <ctype.h>
 
 /* The sigtramp code is in a non-readable (executable-only) region
    of memory called the ``gate page''.  The addresses in question
@@ -128,9 +127,9 @@ ia64_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
 static int
 ia64_linux_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
 {
-  return ((isdigit (*s) && s[1] == '[' && s[2] == 'r') /* Displacement.  */
+  return ((c_isdigit (*s) && s[1] == '[' && s[2] == 'r') /* Displacement.  */
 	  || *s == 'r' /* Register value.  */
-	  || isdigit (*s));  /* Literal number.  */
+	  || c_isdigit (*s));  /* Literal number.  */
 }
 
 /* Core file support. */
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 8978c8a63038d1db39168cc47c49e738863e7f36..4a8aadd0bb145f38e3798a0b0832404e0a4d2ebe 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -39,7 +39,6 @@
 #include "reggroups.h"
 #include "block.h"
 #include "solib.h"
-#include <ctype.h>
 #include "observable.h"
 #include "target-descriptions.h"
 #include "user-regs.h"
@@ -209,7 +208,7 @@ strip_bg_char (const char *args, int *bg_char_p)
   if (p[-1] == '&')
     {
       p--;
-      while (p > args && isspace (p[-1]))
+      while (p > args && c_isspace (p[-1]))
 	p--;
 
       *bg_char_p = 1;
@@ -2307,12 +2306,12 @@ registers_info (const char *addr_exp, int fpregs)
 	 resembling a register following it.  */
       if (addr_exp[0] == '$')
 	addr_exp++;
-      if (isspace ((*addr_exp)) || (*addr_exp) == '\0')
+      if (c_isspace ((*addr_exp)) || (*addr_exp) == '\0')
 	error (_("Missing register name"));
 
       /* Find the start/end of this register name/num/group.  */
       start = addr_exp;
-      while ((*addr_exp) != '\0' && !isspace ((*addr_exp)))
+      while ((*addr_exp) != '\0' && !c_isspace ((*addr_exp)))
 	addr_exp++;
       end = addr_exp;
 
diff --git a/gdb/infrun.c b/gdb/infrun.c
index e0e9ffa4caf82e790ff983e744280e57bad1ac45..293abd01f21af2599697e60c292f9a359d3cce5b 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -22,7 +22,6 @@
 #include "cli/cli-style.h"
 #include "displaced-stepping.h"
 #include "infrun.h"
-#include <ctype.h>
 #include "exceptions.h"
 #include "symtab.h"
 #include "frame.h"
@@ -9823,7 +9822,7 @@ handle_command (const char *args, int from_tty)
   for (char *arg : built_argv)
     {
       wordlen = strlen (arg);
-      for (digits = 0; isdigit (arg[digits]); digits++)
+      for (digits = 0; c_isdigit (arg[digits]); digits++)
 	{;
 	}
       allsigs = 0;
diff --git a/gdb/language.c b/gdb/language.c
index 80f9b0185a6c2d62e4253acf4445f591b4d8852f..dd2198268dd671b3ed6488c15e1becfa4e39d74e 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -28,7 +28,6 @@
    return data out of a "language-specific" struct pointer that is set
    whenever the working language changes.  That would be a lot faster.  */
 
-#include <ctype.h>
 #include "symtab.h"
 #include "gdbtypes.h"
 #include "value.h"
diff --git a/gdb/linespec.c b/gdb/linespec.c
index b59c0553c34c1344678b6ce92baeffe00420dd1f..9f1824def5a81ed2222f009270bf3cbf245e5205 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -35,7 +35,6 @@
 #include "interps.h"
 #include "target.h"
 #include "arch-utils.h"
-#include <ctype.h>
 #include "cli/cli-utils.h"
 #include "filenames.h"
 #include "ada-lang.h"
@@ -459,7 +458,7 @@ linespec_lexer_lex_number (linespec_parser *parser, linespec_token *tokenp)
       ++(parser->lexer.stream);
     }
 
-  while (isdigit (*parser->lexer.stream))
+  while (c_isdigit (*parser->lexer.stream))
     {
       ++tokenp->data.string.length;
       ++(parser->lexer.stream);
@@ -468,7 +467,7 @@ linespec_lexer_lex_number (linespec_parser *parser, linespec_token *tokenp)
   /* If the next character in the input buffer is not a space, comma,
      quote, or colon, this input does not represent a number.  */
   if (*parser->lexer.stream != '\0'
-      && !isspace (*parser->lexer.stream) && *parser->lexer.stream != ','
+      && !c_isspace (*parser->lexer.stream) && *parser->lexer.stream != ','
       && *parser->lexer.stream != ':'
       && !strchr (linespec_quote_characters, *parser->lexer.stream))
     {
@@ -512,7 +511,7 @@ linespec_lexer_lex_keyword (const char *p)
 	      if (i == FORCE_KEYWORD_INDEX && p[len] == '\0')
 		return linespec_keywords[i];
 
-	      if (!isspace (p[len]))
+	      if (!c_isspace (p[len]))
 		continue;
 
 	      if (i == FORCE_KEYWORD_INDEX)
@@ -524,7 +523,7 @@ linespec_lexer_lex_keyword (const char *p)
 		      int nextlen = strlen (linespec_keywords[j]);
 
 		      if (strncmp (p, linespec_keywords[j], nextlen) == 0
-			  && isspace (p[nextlen]))
+			  && c_isspace (p[nextlen]))
 			return linespec_keywords[i];
 		    }
 		}
@@ -538,7 +537,7 @@ linespec_lexer_lex_keyword (const char *p)
 		      int nextlen = strlen (linespec_keywords[j]);
 
 		      if (strncmp (p, linespec_keywords[j], nextlen) == 0
-			  && isspace (p[nextlen]))
+			  && c_isspace (p[nextlen]))
 			return NULL;
 		    }
 		}
@@ -763,7 +762,7 @@ linespec_lexer_lex_string (linespec_parser *parser)
 
       while (1)
 	{
-	  if (isspace (*parser->lexer.stream))
+	  if (c_isspace (*parser->lexer.stream))
 	    {
 	      p = skip_spaces (parser->lexer.stream);
 	      /* When we get here we know we've found something followed by
@@ -841,14 +840,14 @@ linespec_lexer_lex_string (linespec_parser *parser)
 		{
 		  const char *op = parser->lexer.stream;
 
-		  while (op > start && isspace (op[-1]))
+		  while (op > start && c_isspace (op[-1]))
 		    op--;
 		  if (op - start >= CP_OPERATOR_LEN)
 		    {
 		      op -= CP_OPERATOR_LEN;
 		      if (strncmp (op, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0
 			  && (op == start
-			      || !(isalnum (op[-1]) || op[-1] == '_')))
+			      || !(c_isalnum (op[-1]) || op[-1] == '_')))
 			{
 			  /* This is an operator name.  Keep going.  */
 			  ++(parser->lexer.stream);
@@ -1642,7 +1641,7 @@ linespec_parse_line_offset (const char *string)
   else
     line_offset.sign = LINE_OFFSET_NONE;
 
-  if (*string != '\0' && !isdigit (*string))
+  if (*string != '\0' && !c_isdigit (*string))
     error (_("malformed line offset: \"%s\""), start);
 
   /* Right now, we only allow base 10 for offsets.  */
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index 9e986d8d7ca90c81b52f4818d0478fff3f137311..0171259bea51e78917ab0e4e11c89e4aff15f8ac 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -37,7 +37,6 @@
 #include "gdbsupport/eintr.h"
 #include "target/waitstatus.h"
 #include <dirent.h>
-#include <ctype.h>
 
 #include <list>
 
@@ -421,7 +420,7 @@ fork_save_infrun_state (struct fork_info *fp)
       /* Now find actual file positions.  */
       rewinddir (d);
       while ((de = readdir (d)) != NULL)
-	if (isdigit (de->d_name[0]))
+	if (c_isdigit (de->d_name[0]))
 	  {
 	    tmp = strtol (&de->d_name[0], NULL, 10);
 	    fp->filepos[tmp] = call_lseek (tmp, 0, SEEK_CUR);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index f3179279d92f3a85845ec104130713186a33a95f..a443aeb4aeb5f92e3cfa37c538b2d2d104b181fc 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -42,7 +42,6 @@
 #include "elf-bfd.h"
 #include "gregset.h"
 #include "gdbcore.h"
-#include <ctype.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include "inf-loop.h"
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 5c4bbf665637748ef279870f55f9057b5f0ac5f7..a9d5f83c69ed83b59ee82bc13830466b0a7177b8 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -46,7 +46,6 @@
 #include "cli/cli-style.h"
 #include "gdbsupport/unordered_map.h"
 
-#include <ctype.h>
 
 /* This enum represents the values that the user can choose when
    informing the Linux kernel about which memory mappings will be
@@ -483,7 +482,7 @@ read_mapping (const char *line)
 
   p = skip_spaces (p);
   const char *permissions_start = p;
-  while (*p && !isspace (*p))
+  while (*p && !c_isspace (*p))
     p++;
   mapping.permissions = std::string (permissions_start,
 				     (size_t) (p - permissions_start));
@@ -492,7 +491,7 @@ read_mapping (const char *line)
 
   p = skip_spaces (p);
   const char *device_start = p;
-  while (*p && !isspace (*p))
+  while (*p && !c_isspace (*p))
     p++;
   mapping.device = {device_start, (size_t) (p - device_start)};
 
@@ -836,7 +835,7 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
   char filename[100];
   fileio_error target_errno;
 
-  if (args && isdigit (args[0]))
+  if (args && c_isdigit (args[0]))
     {
       char *tem;
 
@@ -2227,7 +2226,7 @@ linux_fill_prpsinfo (struct elf_internal_linux_prpsinfo *p)
      specifically under the entry of `/proc/[pid]/stat'.  */
 
   /* Getting rid of the PID, since we already have it.  */
-  while (isdigit (*proc_stat))
+  while (c_isdigit (*proc_stat))
     ++proc_stat;
 
   proc_stat = skip_spaces (proc_stat);
@@ -2299,10 +2298,10 @@ linux_fill_prpsinfo (struct elf_internal_linux_prpsinfo *p)
     {
       /* Advancing the pointer to the beginning of the UID.  */
       tmpstr += sizeof ("Uid:");
-      while (*tmpstr != '\0' && !isdigit (*tmpstr))
+      while (*tmpstr != '\0' && !c_isdigit (*tmpstr))
 	++tmpstr;
 
-      if (isdigit (*tmpstr))
+      if (c_isdigit (*tmpstr))
 	p->pr_uid = strtol (tmpstr, &tmpstr, 10);
     }
 
@@ -2312,10 +2311,10 @@ linux_fill_prpsinfo (struct elf_internal_linux_prpsinfo *p)
     {
       /* Advancing the pointer to the beginning of the GID.  */
       tmpstr += sizeof ("Gid:");
-      while (*tmpstr != '\0' && !isdigit (*tmpstr))
+      while (*tmpstr != '\0' && !c_isdigit (*tmpstr))
 	++tmpstr;
 
-      if (isdigit (*tmpstr))
+      if (c_isdigit (*tmpstr))
 	p->pr_gid = strtol (tmpstr, &tmpstr, 10);
     }
 
diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c
index 8d49508d1ab822a4acaa3cba8a94749e0a33449a..82bfe0802234896ba0f0a6f914b74885895a9ff4 100644
--- a/gdb/linux-thread-db.c
+++ b/gdb/linux-thread-db.c
@@ -43,7 +43,6 @@
 #include "auto-load.h"
 #include "cli/cli-utils.h"
 #include <signal.h>
-#include <ctype.h>
 #include "nat/linux-namespaces.h"
 #include <algorithm>
 #include "gdbsupport/pathstuff.h"
diff --git a/gdb/location.c b/gdb/location.c
index 378fafc60f7d28b043370196ba88cf8e231129bd..197c47bbe47e9f3da2916f00ee5c70093c33f484 100644
--- a/gdb/location.c
+++ b/gdb/location.c
@@ -26,7 +26,6 @@
 #include "probe.h"
 #include "cp-support.h"
 
-#include <ctype.h>
 #include <string.h>
 
 static std::string
@@ -408,15 +407,15 @@ explicit_location_spec_lex_one (const char **inp,
      whitespace or comma.  */
   if (*start == '-' || *start == '+')
     {
-      while (*inp[0] != '\0' && *inp[0] != ',' && !isspace (*inp[0]))
+      while (*inp[0] != '\0' && *inp[0] != ',' && !c_isspace (*inp[0]))
 	++(*inp);
     }
   else
     {
       /* Handle numbers first, stopping at the next whitespace or ','.  */
-      while (isdigit (*inp[0]))
+      while (c_isdigit (*inp[0]))
 	++(*inp);
-      if (*inp[0] == '\0' || isspace (*inp[0]) || *inp[0] == ',')
+      if (*inp[0] == '\0' || c_isspace (*inp[0]) || *inp[0] == ',')
 	return gdb::unique_xmalloc_ptr<char> (savestring (start,
 							  *inp - start));
 
@@ -425,7 +424,7 @@ explicit_location_spec_lex_one (const char **inp,
       *inp = start;
       while ((*inp)[0]
 	     && (*inp)[0] != ','
-	     && !(isspace ((*inp)[0])
+	     && !(c_isspace ((*inp)[0])
 		  || linespec_lexer_lex_keyword (&(*inp)[1])))
 	{
 	  /* Special case: C++ operator,.  */
@@ -454,14 +453,14 @@ is_cp_operator (const char *start, const char *comma)
     {
       const char *p = comma;
 
-      while (p > start && isspace (p[-1]))
+      while (p > start && c_isspace (p[-1]))
 	p--;
       if (p - start >= CP_OPERATOR_LEN)
 	{
 	  p -= CP_OPERATOR_LEN;
 	  if (strncmp (p, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0
 	      && (p == start
-		  || !(isalnum (p[-1]) || p[-1] == '_')))
+		  || !(c_isalnum (p[-1]) || p[-1] == '_')))
 	    {
 	      return true;
 	    }
@@ -624,7 +623,7 @@ string_to_explicit_location_spec (const char **argp,
   if (argp == NULL
       || *argp == NULL
       || *argp[0] != '-'
-      || !isalpha ((*argp)[1])
+      || !c_isalpha ((*argp)[1])
       || ((*argp)[0] == '-' && (*argp)[1] == 'p'))
     return NULL;
 
@@ -728,7 +727,7 @@ string_to_explicit_location_spec (const char **argp,
 	}
       /* Only emit an "invalid argument" error for options
 	 that look like option strings.  */
-      else if (opt.get ()[0] == '-' && !isdigit (opt.get ()[1]))
+      else if (opt.get ()[0] == '-' && !c_isdigit (opt.get ()[1]))
 	{
 	  if (completion_info == NULL)
 	    error (_("invalid explicit location argument, \"%s\""), opt.get ());
diff --git a/gdb/main.c b/gdb/main.c
index bb8ddc37c010bbdfc9ccb2c4dd3c21522d1e3001..f151428b9c729388ae621d96d02d7625d7d9b65b 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -29,7 +29,6 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <ctype.h>
 #include "gdbsupport/event-loop.h"
 #include "ui-out.h"
 
@@ -1253,7 +1252,7 @@ captured_main_1 (struct captured_main_args *context)
 	 If pid_or_core_arg's first character is a digit, try attach
 	 first and then corefile.  Otherwise try just corefile.  */
 
-      if (isdigit (pid_or_core_arg[0]))
+      if (c_isdigit (pid_or_core_arg[0]))
 	{
 	  ret = catch_command_errors (attach_command, pid_or_core_arg,
 				      !batch_flag);
diff --git a/gdb/maint.c b/gdb/maint.c
index 78dea22541f1e3753eeeedf254ea66ccdedbfc88..2d5a44185ef1a7a981f454bcc94341f9a5c5e4da 100644
--- a/gdb/maint.c
+++ b/gdb/maint.c
@@ -21,7 +21,6 @@
 
 
 #include "arch-utils.h"
-#include <ctype.h>
 #include <cmath>
 #include <signal.h>
 #include "command.h"
@@ -571,9 +570,9 @@ maintenance_translate_address (const char *arg, int from_tty)
   sect = NULL;
   p = arg;
 
-  if (!isdigit (*p))
+  if (!c_isdigit (*p))
     {				/* See if we have a valid section name.  */
-      while (*p && !isspace (*p))	/* Find end of section name.  */
+      while (*p && !c_isspace (*p))	/* Find end of section name.  */
 	p++;
       if (*p == '\000')		/* End of command?  */
 	error (_("Need to specify section name and address"));
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index e4cb2e7d335601a1357baae6c669b93fe89fc363..1cb8435451387246c714eaaba3c1ed8f12e4e047 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -28,7 +28,6 @@
 #include "language.h"
 #include "location.h"
 #include "linespec.h"
-#include <ctype.h>
 #include "tracepoint.h"
 
 enum
@@ -133,7 +132,7 @@ mi_argv_to_format (const char *const *argv, int argc)
 	  result += "\\\"";
 	  break;
 	default:
-	  if (isprint (argv[0][i]))
+	  if (c_isprint (argv[0][i]))
 	    result += argv[0][i];
 	  else
 	    {
diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c
index 9ee2d27b70e40b4d6e89a1b4205b9b1bcf635244..5974f7ac08d2f9e93ef8d92b5ecebe0540e256a0 100644
--- a/gdb/mi/mi-cmd-stack.c
+++ b/gdb/mi/mi-cmd-stack.c
@@ -29,7 +29,6 @@
 #include "valprint.h"
 #include "mi-getopt.h"
 #include "extension.h"
-#include <ctype.h>
 #include "mi-parse.h"
 #include <optional>
 #include "inferior.h"
diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c
index 9cbb85722b3d81d4c1096f1245d988c4f7818405..09d6107c11bf7e8eef72655c3c867ef6ab8bc460 100644
--- a/gdb/mi/mi-cmd-var.c
+++ b/gdb/mi/mi-cmd-var.c
@@ -25,7 +25,6 @@
 #include "varobj.h"
 #include "language.h"
 #include "value.h"
-#include <ctype.h>
 #include "mi-getopt.h"
 #include "gdbthread.h"
 #include "mi-parse.h"
@@ -109,7 +108,7 @@ mi_cmd_var_create (const char *command, const char *const *argv, int argc)
       gen_name = varobj_gen_name ();
       name = gen_name.c_str ();
     }
-  else if (!isalpha (name[0]))
+  else if (!c_isalpha (name[0]))
     error (_("-var-create: name of object must begin with a letter"));
 
   if (strcmp (frame, "*") == 0)
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 789e6fa4ad5b7c6d55736028b889ed1b85df776b..bcc32f9bfea912e69d1282d15fae724f4b9d83e0 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -52,7 +52,6 @@
 #include <optional>
 #include "gdbsupport/byte-vector.h"
 
-#include <ctype.h>
 #include "gdbsupport/run-time-clock.h"
 #include <chrono>
 #include "progspace-and-thread.h"
diff --git a/gdb/mi/mi-parse.c b/gdb/mi/mi-parse.c
index 0af90cb711bf482ad526031f5f64a3846da7e0c8..58bdf4a4066bfc3590741fe16fc530bcee380469 100644
--- a/gdb/mi/mi-parse.c
+++ b/gdb/mi/mi-parse.c
@@ -22,7 +22,6 @@
 #include "mi-cmds.h"
 #include "mi-parse.h"
 
-#include <ctype.h>
 #include "cli/cli-utils.h"
 #include "language.h"
 
@@ -61,7 +60,7 @@ mi_parse_escape (const char **string_ptr)
 	  while (++count < 3)
 	    {
 	      c = (**string_ptr);
-	      if (isdigit (c) && c != '8' && c != '9')
+	      if (c_isdigit (c) && c != '8' && c != '9')
 		{
 		  (*string_ptr)++;
 		  i *= 8;
@@ -162,7 +161,7 @@ mi_parse::parse_argv ()
 		return;
 	      }
 	    /* Insist on trailing white space.  */
-	    if (chp[1] != '\0' && !isspace (chp[1]))
+	    if (chp[1] != '\0' && !c_isspace (chp[1]))
 	      {
 		freeargv (argv);
 		return;
@@ -193,7 +192,7 @@ mi_parse::parse_argv ()
 	    int len;
 	    const char *start = chp;
 
-	    while (*chp != '\0' && !isspace (*chp))
+	    while (*chp != '\0' && !c_isspace (*chp))
 	      {
 		chp++;
 	      }
@@ -313,7 +312,7 @@ mi_parse::mi_parse (const char *cmd, std::string *token)
   {
     const char *tmp = chp + 1;	/* discard ``-'' */
 
-    for (; *chp && !isspace (*chp); chp++)
+    for (; *chp && !c_isspace (*chp); chp++)
       ;
     this->command = make_unique_xstrndup (tmp, chp - tmp);
   }
@@ -391,7 +390,7 @@ mi_parse::mi_parse (const char *cmd, std::string *token)
       else
 	break;
 
-      if (*chp != '\0' && !isspace (*chp))
+      if (*chp != '\0' && !c_isspace (*chp))
 	error (_("Invalid value for the '%s' option"), option);
       chp = skip_spaces (chp);
     }
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 2cf3d9d1c683ad875d9185160c3f4995d416da95..19163cf08a0070fef642c4b33afcf387196ad07f 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -36,7 +36,6 @@
    to figure out what full symbol table entries need to be read in.  */
 
 
-#include <ctype.h>
 #include "maint.h"
 #include "symtab.h"
 #include "bfd.h"
diff --git a/gdb/nat/linux-osdata.c b/gdb/nat/linux-osdata.c
index b52a8ed5f363391850c88769cc3d71c0fe84bc91..0a309b863d3c483d5fad2300adf894b5844573a1 100644
--- a/gdb/nat/linux-osdata.c
+++ b/gdb/nat/linux-osdata.c
@@ -21,7 +21,6 @@
 
 #include <sys/types.h>
 #include <sys/sysinfo.h>
-#include <ctype.h>
 #include <utmp.h>
 #include <time.h>
 #include <unistd.h>
@@ -205,7 +204,7 @@ get_cores_used_by_process (PID_T pid, int *cores, const int num_cores)
 	  PID_T tid;
 	  int core;
 
-	  if (!isdigit (dp->d_name[0])
+	  if (!c_isdigit (dp->d_name[0])
 	      || NAMELEN (dp) > MAX_PID_T_STRLEN)
 	    continue;
 
@@ -310,7 +309,7 @@ linux_xfer_osdata_processes ()
 	  std::string cores_str;
 	  int i;
 
-	  if (!isdigit (dp->d_name[0])
+	  if (!c_isdigit (dp->d_name[0])
 	      || NAMELEN (dp) > MAX_PID_T_STRLEN)
 	    continue;
 
@@ -419,7 +418,7 @@ linux_xfer_osdata_processgroups ()
 	{
 	  PID_T pid, pgid;
 
-	  if (!isdigit (dp->d_name[0])
+	  if (!c_isdigit (dp->d_name[0])
 	      || NAMELEN (dp) > MAX_PID_T_STRLEN)
 	    continue;
 
@@ -483,7 +482,7 @@ linux_xfer_osdata_threads ()
 	  struct stat statbuf;
 	  char procentry[sizeof ("/proc/4294967295")];
 
-	  if (!isdigit (dp->d_name[0])
+	  if (!c_isdigit (dp->d_name[0])
 	      || NAMELEN (dp) > sizeof ("4294967295") - 1)
 	    continue;
 
@@ -513,7 +512,7 @@ linux_xfer_osdata_threads ()
 		      PID_T tid;
 		      int core;
 
-		      if (!isdigit (dp2->d_name[0])
+		      if (!c_isdigit (dp2->d_name[0])
 			  || NAMELEN (dp2) > sizeof ("4294967295") - 1)
 			continue;
 
@@ -633,7 +632,7 @@ linux_xfer_osdata_fds ()
 	  struct stat statbuf;
 	  char procentry[sizeof ("/proc/4294967295")];
 
-	  if (!isdigit (dp->d_name[0])
+	  if (!c_isdigit (dp->d_name[0])
 	      || NAMELEN (dp) > sizeof ("4294967295") - 1)
 	    continue;
 
@@ -662,7 +661,7 @@ linux_xfer_osdata_fds ()
 		      char buf[1000];
 		      ssize_t rslt;
 
-		      if (!isdigit (dp2->d_name[0]))
+		      if (!c_isdigit (dp2->d_name[0]))
 			continue;
 
 		      std::string fdname
diff --git a/gdb/netbsd-nat.c b/gdb/netbsd-nat.c
index 060134f7b201639d382592696cab5a977d06ade6..207e69cfdc55186f36ad7b00a9084238c5d1b21b 100644
--- a/gdb/netbsd-nat.c
+++ b/gdb/netbsd-nat.c
@@ -318,7 +318,7 @@ nbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
       if (pid == 0)
 	error (_("No current process: you must name one."));
     }
-  else if (built_argv.count () == 1 && isdigit (built_argv[0][0]))
+  else if (built_argv.count () == 1 && c_isdigit (built_argv[0][0]))
     pid = strtol (built_argv[0], NULL, 10);
   else
     error (_("Invalid arguments."));
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 6bba8d33af97ac579c520310a266314418cca6da..492020df8dcff0b6375215aadd10c2f95fd6ebaa 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -46,7 +46,6 @@
 #include "cli/cli-utils.h"
 #include "c-exp.h"
 
-#include <ctype.h>
 #include <algorithm>
 
 struct objc_object {
@@ -850,9 +849,9 @@ parse_selector (char *method, char **selector)
 
   for (;;)
     {
-      if (isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
+      if (c_isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
 	*s1++ = *s2;
-      else if (isspace (*s2))
+      else if (c_isspace (*s2))
 	;
       else if ((*s2 == '\0') || (*s2 == '\''))
 	break;
@@ -914,7 +913,7 @@ parse_method (char *method, char *type, char **theclass,
   s1++;
 
   nclass = s1;
-  while (isalnum (*s1) || (*s1 == '_'))
+  while (c_isalnum (*s1) || (*s1 == '_'))
     s1++;
   
   s2 = s1;
@@ -925,7 +924,7 @@ parse_method (char *method, char *type, char **theclass,
       s2++;
       s2 = skip_spaces (s2);
       ncategory = s2;
-      while (isalnum (*s2) || (*s2 == '_'))
+      while (c_isalnum (*s2) || (*s2 == '_'))
 	s2++;
       *s2++ = '\0';
     }
@@ -938,9 +937,9 @@ parse_method (char *method, char *type, char **theclass,
 
   for (;;)
     {
-      if (isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
+      if (c_isalnum (*s2) || (*s2 == '_') || (*s2 == ':'))
 	*s1++ = *s2;
-      else if (isspace (*s2))
+      else if (c_isspace (*s2))
 	;
       else if (*s2 == ']')
 	break;
diff --git a/gdb/p-exp.y b/gdb/p-exp.y
index cbf6b449343fb0962ac3bc2cb14fe0c2731146e7..4422fc8cad49ece57e3e384707bc33ed05d5fc29 100644
--- a/gdb/p-exp.y
+++ b/gdb/p-exp.y
@@ -43,7 +43,6 @@
    Probably also lots of other problems, less well defined PM.  */
 %{
 
-#include <ctype.h>
 #include "expression.h"
 #include "value.h"
 #include "parser-defs.h"
@@ -817,13 +816,13 @@ parse_number (struct parser_state *par_state,
     {
       /* Handle suffixes: 'f' for float, 'l' for long double.
 	 FIXME: This appears to be an extension -- do we want this?  */
-      if (len >= 1 && tolower (p[len - 1]) == 'f')
+      if (len >= 1 && c_tolower (p[len - 1]) == 'f')
 	{
 	  putithere->typed_val_float.type
 	    = parse_type (par_state)->builtin_float;
 	  len--;
 	}
-      else if (len >= 1 && tolower (p[len - 1]) == 'l')
+      else if (len >= 1 && c_tolower (p[len - 1]) == 'l')
 	{
 	  putithere->typed_val_float.type
 	    = parse_type (par_state)->builtin_long_double;
@@ -1089,9 +1088,9 @@ yylex (void)
   if (explen > 2)
     for (const auto &token : tokentab3)
       if (strncasecmp (tokstart, token.oper, 3) == 0
-	  && (!isalpha (token.oper[0]) || explen == 3
-	      || (!isalpha (tokstart[3])
-		  && !isdigit (tokstart[3]) && tokstart[3] != '_')))
+	  && (!c_isalpha (token.oper[0]) || explen == 3
+	      || (!c_isalpha (tokstart[3])
+		  && !c_isdigit (tokstart[3]) && tokstart[3] != '_')))
 	{
 	  pstate->lexptr += 3;
 	  yylval.opcode = token.opcode;
@@ -1102,9 +1101,9 @@ yylex (void)
   if (explen > 1)
     for (const auto &token : tokentab2)
       if (strncasecmp (tokstart, token.oper, 2) == 0
-	  && (!isalpha (token.oper[0]) || explen == 2
-	      || (!isalpha (tokstart[2])
-		  && !isdigit (tokstart[2]) && tokstart[2] != '_')))
+	  && (!c_isalpha (token.oper[0]) || explen == 2
+	      || (!c_isalpha (tokstart[2])
+		  && !c_isdigit (tokstart[2]) && tokstart[2] != '_')))
 	{
 	  pstate->lexptr += 2;
 	  yylval.opcode = token.opcode;
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index 3ded1524bde5330a7733e26d1874c6208d669eb5..1dc1a34663cbcf2d11f44f1ffbbbfb8d8bd6ea0d 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -30,7 +30,6 @@
 #include "p-lang.h"
 #include "valprint.h"
 #include "value.h"
-#include <ctype.h>
 #include "c-lang.h"
 #include "gdbarch.h"
 #include "cli/cli-style.h"
diff --git a/gdb/p-typeprint.c b/gdb/p-typeprint.c
index 7994ccfc77dece2d5a1fc3dcc2be8465abfb63ba..8b5f2b548a5a8bbad9bab920b7a8c43c97310f8b 100644
--- a/gdb/p-typeprint.c
+++ b/gdb/p-typeprint.c
@@ -30,7 +30,6 @@
 #include "p-lang.h"
 #include "typeprint.h"
 #include "gdb-demangle.h"
-#include <ctype.h>
 #include "cli/cli-style.h"
 
 /* See language.h.  */
@@ -138,13 +137,13 @@ pascal_language::type_print_method_args (const char *physname,
     {
       gdb_puts (" (", stream);
       /* We must demangle this.  */
-      while (isdigit (physname[0]))
+      while (c_isdigit (physname[0]))
 	{
 	  int len = 0;
 	  int i, j;
 	  char *argname;
 
-	  while (isdigit (physname[len]))
+	  while (c_isdigit (physname[len]))
 	    {
 	      len++;
 	    }
diff --git a/gdb/parse.c b/gdb/parse.c
index 6ad4e712a77025ea3821325b27c07043b758e24a..e24a0d01d54997eb4f5e55e6a28b162525d9f28e 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -29,7 +29,6 @@
    during the process of parsing; the lower levels of the tree always
    come first in the result.  */
 
-#include <ctype.h>
 #include "arch-utils.h"
 #include "symtab.h"
 #include "gdbtypes.h"
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index 5067b89cbe0ffb446681493c93eb333315b8a000..6156b19adeb802319324b8392dd1084831f642d3 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -61,7 +61,6 @@
 #include "cli/cli-utils.h"
 #include "parser-defs.h"
 #include "user-regs.h"
-#include <ctype.h>
 #include "elf-bfd.h"
 #include "producer.h"
 #include "target-float.h"
@@ -1710,10 +1709,10 @@ static int
 ppc_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
 {
   return (*s == 'i' /* Literal number.  */
-	  || (isdigit (*s) && s[1] == '('
-	      && isdigit (s[2])) /* Displacement.  */
-	  || (*s == '(' && isdigit (s[1])) /* Register indirection.  */
-	  || isdigit (*s)); /* Register value.  */
+	  || (c_isdigit (*s) && s[1] == '('
+	      && c_isdigit (s[2])) /* Displacement.  */
+	  || (*s == '(' && c_isdigit (s[1])) /* Register indirection.  */
+	  || c_isdigit (*s)); /* Register value.  */
 }
 
 /* Implementation of `gdbarch_stap_parse_special_token', as defined in
@@ -1723,7 +1722,7 @@ static expr::operation_up
 ppc_stap_parse_special_token (struct gdbarch *gdbarch,
 			      struct stap_parse_info *p)
 {
-  if (isdigit (*p->arg))
+  if (c_isdigit (*p->arg))
     {
       /* This temporary pointer is needed because we have to do a lookahead.
 	  We could be dealing with a register displacement, and in such case
@@ -1732,7 +1731,7 @@ ppc_stap_parse_special_token (struct gdbarch *gdbarch,
       char *regname;
       int len;
 
-      while (isdigit (*s))
+      while (c_isdigit (*s))
 	++s;
 
       if (*s == '(')
diff --git a/gdb/probe.c b/gdb/probe.c
index 6679f39cc67c44b25e1e443f770e6e8518cdfbeb..c2b8270a476be3fb421782ddc939a2b239ac0fe5 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -33,7 +33,6 @@
 #include "ax.h"
 #include "ax-gdb.h"
 #include "location.h"
-#include <ctype.h>
 #include <algorithm>
 #include <optional>
 
@@ -826,7 +825,7 @@ probe_is_linespec_by_keyword (const char **linespecp, const char *const *keyword
       const char *keyword = *csp;
       size_t len = strlen (keyword);
 
-      if (strncmp (s, keyword, len) == 0 && isspace (s[len]))
+      if (strncmp (s, keyword, len) == 0 && c_isspace (s[len]))
 	{
 	  *linespecp += len + 1;
 	  return 1;
diff --git a/gdb/procfs.c b/gdb/procfs.c
index a10574af629526f31e7ccfafbea6eddddafd6f63..ca7ecbbe190d5231e1ff761ffdbae3ac3c43ad26 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -38,7 +38,6 @@
 #include <sys/syscall.h>
 #include "gdbsupport/gdb_wait.h"
 #include <signal.h>
-#include <ctype.h>
 #include "gdb_bfd.h"
 #include "auxv.h"
 #include "procfs.h"
@@ -3304,7 +3303,7 @@ procfs_target::info_proc (const char *args, enum info_proc_what what)
   gdb_argv built_argv (args);
   for (char *arg : built_argv)
     {
-      if (isdigit (arg[0]))
+      if (c_isdigit (arg[0]))
 	{
 	  pid = strtoul (arg, &tmp, 10);
 	  if (*tmp == '/')
@@ -3415,7 +3414,7 @@ proc_trace_syscalls (const char *args, int from_tty, int entry_or_exit, int mode
     error_no_arg (_("system call to trace"));
 
   pi = find_procinfo_or_die (inferior_ptid.pid (), 0);
-  if (isdigit (args[0]))
+  if (c_isdigit (args[0]))
     {
       const int syscallnum = atoi (args);
 
diff --git a/gdb/producer.c b/gdb/producer.c
index 5d754faedb8a3c8b0da0ac2bc9129ac043feb511..71e1b92e95e7ece6b5f0825ad5b4a6a17eafdca7 100644
--- a/gdb/producer.c
+++ b/gdb/producer.c
@@ -66,9 +66,9 @@ producer_is_gcc (const char *producer, int *major, int *minor)
 	 "GNU Fortran 4.8.2 20140120 (Red Hat 4.8.2-16) -mtune=generic ..."
 	 "GNU C++14 5.0.0 20150123 (experimental)"
       */
-      while (*cs && !isspace (*cs))
+      while (*cs && !c_isspace (*cs))
 	cs++;
-      if (*cs && isspace (*cs))
+      if (*cs && c_isspace (*cs))
 	cs++;
       if (sscanf (cs, "%d.%d", major, minor) == 2)
 	return 1;
diff --git a/gdb/python/py-mi.c b/gdb/python/py-mi.c
index 9b871d42c9266421649d5a1aab8e2dd51f350f9e..b2ab4e20e41d9d260c6fcc51a2a1bf2b73f07797 100644
--- a/gdb/python/py-mi.c
+++ b/gdb/python/py-mi.c
@@ -218,11 +218,11 @@ py_object_to_mi_key (PyObject *key_obj)
   {
     gdb_assert (name != nullptr);
 
-    if (*name == '\0' || !isalpha (*name))
+    if (*name == '\0' || !c_isalpha (*name))
       return false;
 
     for (; *name != '\0'; ++name)
-      if (!isalnum (*name) && *name != '_' && *name != '-')
+      if (!c_isalnum (*name) && *name != '_' && *name != '-')
 	return false;
 
     return true;
@@ -363,7 +363,7 @@ gdbpy_notify_mi (PyObject *self, PyObject *args, PyObject *kwargs)
     }
   for (int i = 0; i < name_len; i++)
     {
-      if (!isalnum (name[i]) && name[i] != '-')
+      if (!c_isalnum (name[i]) && name[i] != '-')
 	{
 	  PyErr_Format
 	    (PyExc_ValueError,
diff --git a/gdb/python/py-micmd.c b/gdb/python/py-micmd.c
index 72f427f24b2200cadd861f5f874bef2d58b6120c..07db0cca50d9f1c00529b10e948e12cf33f97eb8 100644
--- a/gdb/python/py-micmd.c
+++ b/gdb/python/py-micmd.c
@@ -350,7 +350,7 @@ micmdpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
       PyErr_SetString (PyExc_ValueError, _("MI command name is empty."));
       return -1;
     }
-  else if ((name_len < 2) || (name[0] != '-') || !isalnum (name[1]))
+  else if ((name_len < 2) || (name[0] != '-') || !c_isalnum (name[1]))
     {
       PyErr_SetString (PyExc_ValueError,
 		       _("MI command name does not start with '-'"
@@ -361,7 +361,7 @@ micmdpy_init (PyObject *self, PyObject *args, PyObject *kwargs)
     {
       for (int i = 2; i < name_len; i++)
 	{
-	  if (!isalnum (name[i]) && name[i] != '-')
+	  if (!c_isalnum (name[i]) && name[i] != '-')
 	    {
 	      PyErr_Format
 		(PyExc_ValueError,
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index 1c6f5697302cdf75e3079110de971d64e7739150..a32b0077f61985a6565e1e7e9eb2e3b200134b6d 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -556,7 +556,7 @@ objfpy_build_id_ok (const char *string)
     return 0;
   for (i = 0; i < n; ++i)
     {
-      if (!isxdigit (string[i]))
+      if (!c_isxdigit (string[i]))
 	return 0;
     }
   return 1;
diff --git a/gdb/python/python.c b/gdb/python/python.c
index cb0d642a67d63dcca86210e3495563ed56a9c10d..ac13bf7be1e65c3e9d969d04cf4f7b620822acb4 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -31,7 +31,6 @@
 #include "python.h"
 #include "extension-priv.h"
 #include "cli/cli-utils.h"
-#include <ctype.h>
 #include "location.h"
 #include "run-on-main-thread.h"
 #include "observable.h"
diff --git a/gdb/record.c b/gdb/record.c
index 248cfaa481ab71f89d82e23f5e545cc4b6789671..de1a7a87a8e430d04adba20220004ab0947f6887 100644
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -28,7 +28,6 @@
 #include "interps.h"
 #include "top.h"
 
-#include <ctype.h>
 
 /* This is the debug switch for process record.  */
 unsigned int record_debug = 0;
@@ -423,7 +422,7 @@ get_insn_number (const char **arg)
   begin = *arg;
   pos = skip_spaces (begin);
 
-  if (!isdigit (*pos))
+  if (!c_isdigit (*pos))
     error (_("Expected positive number, got: %s."), pos);
 
   number = strtoulst (pos, &end, 10);
@@ -443,7 +442,7 @@ get_context_size (const char **arg)
 
   pos = skip_spaces (*arg);
 
-  if (!isdigit (*pos))
+  if (!c_isdigit (*pos))
     error (_("Expected positive number, got: %s."), pos);
 
   long result = strtol (pos, &end, 10);
@@ -483,7 +482,7 @@ get_insn_history_modifiers (const char **arg)
 
       for (; *args; ++args)
 	{
-	  if (isspace (*args))
+	  if (c_isspace (*args))
 	    break;
 
 	  if (*args == '/')
@@ -627,7 +626,7 @@ get_call_history_modifiers (const char **arg)
 
       for (; *args; ++args)
 	{
-	  if (isspace (*args))
+	  if (c_isspace (*args))
 	    break;
 
 	  if (*args == '/')
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index 425e50ddfc062e1387697d97b8a3c6cc928388db..a325ffa58989cc76caec5b58a480c8984c2cf441 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -25,7 +25,6 @@
 #include "inferior.h"
 #include "infrun.h"
 #include "value.h"
-#include <ctype.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <setjmp.h>
diff --git a/gdb/remote.c b/gdb/remote.c
index 6208a90f94a70bf25b0e16cfc4dcce1e01f28828..ea9728ead58f5559edd4a99a2a6d48d21ac02295 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -19,7 +19,6 @@
 
 /* See the GDB User Guide for details of the GDB remote protocol.  */
 
-#include <ctype.h>
 #include <fcntl.h>
 #include "exceptions.h"
 #include "inferior.h"
@@ -2558,7 +2557,7 @@ packet_check_result (const char *buf)
       /* The stub recognized the packet request.  Check that the
 	 operation succeeded.  */
       if (buf[0] == 'E'
-	  && isxdigit (buf[1]) && isxdigit (buf[2])
+	  && c_isxdigit (buf[1]) && c_isxdigit (buf[2])
 	  && buf[3] == '\0')
 	/* "Enn"  - definitely an error.  */
 	return packet_result::make_numeric_error (buf + 1);
@@ -11936,7 +11935,7 @@ remote_target::xfer_partial (enum target_object object,
   while (annex[i] && (i < (get_remote_packet_size () - 8)))
     {
       /* Bad caller may have sent forbidden characters.  */
-      gdb_assert (isprint (annex[i]) && annex[i] != '$' && annex[i] != '#');
+      gdb_assert (c_isprint (annex[i]) && annex[i] != '$' && annex[i] != '#');
       *p2++ = annex[i];
       i++;
     }
@@ -12186,7 +12185,7 @@ struct cli_packet_command_callbacks : public send_remote_packet_callbacks
     for (int i = 0; i < buf.size (); ++i)
       {
 	gdb_byte c = buf[i];
-	if (isprint (c))
+	if (c_isprint (c))
 	  gdb_putc (c, &stb);
 	else
 	  gdb_printf (&stb, "\\x%02x", (unsigned char) c);
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 39574139b414f1efc187cbbe9568ecaf3d3f746a..09a728a2ee43bf5d2e3226185b0c0581b87b88ec 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -18,7 +18,6 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
-#include <ctype.h>
 
 #include "block.h"
 #include "c-lang.h"
@@ -1788,7 +1787,7 @@ rust_language::emitchar (int ch, struct type *chtype,
     gdb_puts ("\\t", stream);
   else if (ch == '\0')
     gdb_puts ("\\0", stream);
-  else if (ch >= 32 && ch <= 127 && isprint (ch))
+  else if (ch >= 32 && ch <= 127 && c_isprint (ch))
     gdb_putc (ch, stream);
   else if (ch <= 255)
     gdb_printf (stream, "\\x%02x", ch);
diff --git a/gdb/s12z-tdep.c b/gdb/s12z-tdep.c
index 28d56356661e62b22f14ceaf6f5ab8b17c172ed0..0d49f9888c9be28b74526822e44f07ca33ab6642 100644
--- a/gdb/s12z-tdep.c
+++ b/gdb/s12z-tdep.c
@@ -516,7 +516,7 @@ s12z_print_ccw_info (struct gdbarch *gdbarch,
 	    gdb_putc (ccw_bits[b], file);
 	}
       else
-	gdb_putc (tolower (ccw_bits[b]), file);
+	gdb_putc (c_tolower (ccw_bits[b]), file);
     }
   gdb_putc ('\n', file);
 }
diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
index 8a2b405b8b4facc0c23c9402c2391a428014ca7e..4cc3f6a19e46a9bc8372baf61eebb39a54e4326a 100644
--- a/gdb/s390-tdep.c
+++ b/gdb/s390-tdep.c
@@ -7057,10 +7057,10 @@ s390_gnu_triplet_regexp (struct gdbarch *gdbarch)
 static int
 s390_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
 {
-  return ((isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement
+  return ((c_isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement
 							  or indirection.  */
 	  || *s == '%' /* Register access.  */
-	  || isdigit (*s)); /* Literal number.  */
+	  || c_isdigit (*s)); /* Literal number.  */
 }
 
 /* gdbarch init.  */
diff --git a/gdb/serial.c b/gdb/serial.c
index d66c6379f3b6b1050eb159fbbdfb01c2b4f494fa..d047fdf5c75becfbd16257200db9a25debd031d2 100644
--- a/gdb/serial.c
+++ b/gdb/serial.c
@@ -17,7 +17,6 @@
    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 <ctype.h>
 #include "serial.h"
 #include "cli/cli-cmds.h"
 #include "cli/cli-utils.h"
@@ -116,7 +115,7 @@ serial_logchar (struct ui_file *stream, int ch_type, int ch, int timeout)
 	    break;
 	  default:
 	    gdb_printf (stream,
-			isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF);
+			c_isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF);
 	    break;
 	  }
     }
diff --git a/gdb/solib-rocm.c b/gdb/solib-rocm.c
index 2d26c3c1c6edabc4ca1f3002d6b2b9b3c8edff0d..e12d552cf99c2960cbf3ccfb457e4524a04f401a 100644
--- a/gdb/solib-rocm.c
+++ b/gdb/solib-rocm.c
@@ -503,7 +503,7 @@ rocm_bfd_iovec_open (bfd *abfd, inferior *inferior)
   protocol_end += protocol_delim.length ();
 
   std::transform (protocol.begin (), protocol.end (), protocol.begin (),
-		  [] (unsigned char c) { return std::tolower (c); });
+		  [] (unsigned char c) { return c_tolower (c); });
 
   std::string_view path;
   size_t path_end = uri.find_first_of ("#?", protocol_end);
@@ -518,8 +518,8 @@ rocm_bfd_iovec_open (bfd *abfd, inferior *inferior)
   for (size_t i = 0; i < path.length (); ++i)
     if (path[i] == '%'
 	&& i < path.length () - 2
-	&& std::isxdigit (path[i + 1])
-	&& std::isxdigit (path[i + 2]))
+	&& c_isxdigit (path[i + 1])
+	&& c_isxdigit (path[i + 2]))
       {
 	std::string_view hex_digits = path.substr (i + 1, 2);
 	decoded_path += std::stoi (std::string (hex_digits), 0, 16);
diff --git a/gdb/stabsread.c b/gdb/stabsread.c
index 6ee61e0a1174a8ca021e3f9e2ce2d723d59a0e35..808cfd8221e6a2b6a5695aceb8d40ced0fc93f5e 100644
--- a/gdb/stabsread.c
+++ b/gdb/stabsread.c
@@ -46,7 +46,6 @@
 #include "c-lang.h"
 #include "cp-abi.h"
 #include "cp-support.h"
-#include <ctype.h>
 #include "block.h"
 #include "filenames.h"
 
@@ -3067,7 +3066,7 @@ process_reference (const char **string)
   p = *string + 1;
 
   /* Read number as reference id.  */
-  while (*p && isdigit (*p))
+  while (*p && c_isdigit (*p))
     {
       refnum = refnum * 10 + *p - '0';
       p++;
@@ -3251,7 +3250,7 @@ define_symbol (CORE_ADDR valu, const char *string, int desc, int type,
      deftypes we know how to handle is a local.  */
   if (!strchr ("cfFGpPrStTvVXCR", *p))
 #else
-  if (isdigit (*p) || *p == '(' || *p == '-')
+  if (c_isdigit (*p) || *p == '(' || *p == '-')
 #endif
     deftype = 'l';
   else
@@ -4340,7 +4339,7 @@ read_type (const char **pp, struct objfile *objfile)
       break;
 
     case '@':
-      if (isdigit (**pp) || **pp == '(' || **pp == '-')
+      if (c_isdigit (**pp) || **pp == '(' || **pp == '-')
 	{			/* Member (class & variable) type */
 	  /* FIXME -- we should be doing smash_to_XXX types here.  */
 
diff --git a/gdb/stack.c b/gdb/stack.c
index e6335669531895d377eaab85aefe61496ab8e199..cf773d105741acfdca75d39f6b9d6c49eae3bf64 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -3066,7 +3066,7 @@ frame_apply_level_cmd_completer (struct cmd_list_element *ignore,
 
   /* Check if we're past a valid LEVEL already.  */
   if (levels.finished ()
-      && cmd > text && !isspace (cmd[-1]))
+      && cmd > text && !c_isspace (cmd[-1]))
     return;
 
   /* We're past LEVELs, advance word point.  */
@@ -3100,7 +3100,7 @@ frame_apply_cmd_completer (struct cmd_list_element *ignore,
     return;
 
   /* Check if we're past a valid COUNT already.  */
-  if (cmd > text && !isspace (cmd[-1]))
+  if (cmd > text && !c_isspace (cmd[-1]))
     return;
 
   /* We're past COUNT, advance word point.  */
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index 3b692e292381f1638091631a6df0f7e3d42bfab3..6c15bce704c89df0631216907a365a9bfb9bb11a 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -39,7 +39,6 @@
 #include "expop.h"
 #include "gdbsupport/unordered_map.h"
 
-#include <ctype.h>
 
 /* The name of the SystemTap section where we will find information about
    the probes.  */
@@ -575,14 +574,14 @@ stap_is_integer_prefix (struct gdbarch *gdbarch, const char *s,
       if (r != NULL)
 	*r = "";
 
-      return isdigit (*s) > 0;
+      return c_isdigit (*s) > 0;
     }
 
   for (p = t; *p != NULL; ++p)
     {
       size_t len = strlen (*p);
 
-      if ((len == 0 && isdigit (*s))
+      if ((len == 0 && c_isdigit (*s))
 	  || (len > 0 && strncasecmp (s, *p, len) == 0))
 	{
 	  /* Integers may or may not have a prefix.  The "len == 0"
@@ -732,7 +731,7 @@ stap_parse_register_operand (struct stap_parse_info *p)
 
   struct type *long_type = builtin_type (gdbarch)->builtin_long;
   operation_up disp_op;
-  if (isdigit (*p->arg))
+  if (c_isdigit (*p->arg))
     {
       /* The value of the displacement.  */
       long displacement;
@@ -767,14 +766,14 @@ stap_parse_register_operand (struct stap_parse_info *p)
   start = p->arg;
 
   /* We assume the register name is composed by letters and numbers.  */
-  while (isalnum (*p->arg))
+  while (c_isalnum (*p->arg))
     ++p->arg;
 
   std::string regname (start, p->arg - start);
 
   /* We only add the GDB's register prefix/suffix if we are dealing with
      a numeric register.  */
-  if (isdigit (*start))
+  if (c_isdigit (*start))
     {
       if (gdb_reg_prefix != NULL)
 	regname = gdb_reg_prefix + regname;
@@ -921,7 +920,7 @@ stap_parse_single_operand (struct stap_parse_info *p)
       if (p->inside_paren_p)
 	tmp = skip_spaces (tmp);
 
-      while (isdigit (*tmp))
+      while (c_isdigit (*tmp))
 	{
 	  /* We skip the digit here because we are only interested in
 	     knowing what kind of unary operation this is.  The digit
@@ -959,7 +958,7 @@ stap_parse_single_operand (struct stap_parse_info *p)
 		      (std::move (result)));
 	}
     }
-  else if (isdigit (*p->arg))
+  else if (c_isdigit (*p->arg))
     {
       /* A temporary variable, needed for lookahead.  */
       const char *tmp = p->arg;
@@ -1042,7 +1041,7 @@ stap_parse_argument_conditionally (struct stap_parse_info *p)
 
   expr::operation_up result;
   if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' || *p->arg == '!'
-      || isdigit (*p->arg)
+      || c_isdigit (*p->arg)
       || gdbarch_stap_is_single_operand (p->gdbarch, p->arg))
     result = stap_parse_single_operand (p);
   else if (*p->arg == '(')
@@ -1111,7 +1110,7 @@ stap_parse_argument_1 (struct stap_parse_info *p,
      This loop shall continue until we run out of characters in the input,
      or until we find a close-parenthesis, which means that we've reached
      the end of a sub-expression.  */
-  while (*p->arg != '\0' && *p->arg != ')' && !isspace (*p->arg))
+  while (*p->arg != '\0' && *p->arg != ')' && !c_isspace (*p->arg))
     {
       const char *tmp_exp_buf;
       enum exp_opcode opcode;
@@ -1270,8 +1269,8 @@ stap_probe::parse_arguments (struct gdbarch *gdbarch)
 	 Where `N' can be [+,-][1,2,4,8].  This is not mandatory, so
 	 we check it here.  If we don't find it, go to the next
 	 state.  */
-      if ((cur[0] == '-' && isdigit (cur[1]) && cur[2] == '@')
-	  || (isdigit (cur[0]) && cur[1] == '@'))
+      if ((cur[0] == '-' && c_isdigit (cur[1]) && cur[2] == '@')
+	  || (c_isdigit (cur[0]) && cur[1] == '@'))
 	{
 	  if (*cur == '-')
 	    {
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 0e47f5099943b9ceecbb5da5a287a5116e1373ed..a7c009bbcd2bd2052227e9ad90110608bd2410fe 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -58,7 +58,6 @@
 #include <sys/types.h>
 #include <fcntl.h>
 #include <sys/stat.h>
-#include <ctype.h>
 #include <chrono>
 #include <algorithm>
 
@@ -2748,7 +2747,7 @@ set_ext_lang_command (const char *args,
     error (_("'%s': Filename extension must begin with '.'"), ext_args.c_str ());
 
   /* Find end of first arg.  */
-  while (*end != '\0' && !isspace (*end))
+  while (*end != '\0' && !c_isspace (*end))
     end++;
 
   if (*end == '\0')
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 302f4ebf2746221f5b1b8b9c50e88bac796c7ec3..e0706b4ed42dd4635040bdb576eb9732e6e9afc7 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -56,7 +56,6 @@
 #include <sys/types.h>
 #include <fcntl.h>
 #include <sys/stat.h>
-#include <ctype.h>
 #include "cp-abi.h"
 #include "cp-support.h"
 #include "observable.h"
@@ -4333,7 +4332,7 @@ operator_chars (const char *p, const char **end)
 
   /* Don't get faked out by `operator' being part of a longer
      identifier.  */
-  if (isalpha (*p) || *p == '_' || *p == '$' || *p == '\0')
+  if (c_isalpha (*p) || *p == '_' || *p == '$' || *p == '\0')
     return *end;
 
   /* Allow some whitespace between `operator' and the operator symbol.  */
@@ -4342,11 +4341,11 @@ operator_chars (const char *p, const char **end)
 
   /* Recognize 'operator TYPENAME'.  */
 
-  if (isalpha (*p) || *p == '_' || *p == '$')
+  if (c_isalpha (*p) || *p == '_' || *p == '$')
     {
       const char *q = p + 1;
 
-      while (isalnum (*q) || *q == '_' || *q == '$')
+      while (c_isalnum (*q) || *q == '_' || *q == '$')
 	q++;
       *end = q;
       return p;
@@ -5120,7 +5119,7 @@ global_symbol_searcher::search () const
 	  int fix = -1;		/* -1 means ok; otherwise number of
 				    spaces needed.  */
 
-	  if (isalpha (*opname) || *opname == '_' || *opname == '$')
+	  if (c_isalpha (*opname) || *opname == '_' || *opname == '$')
 	    {
 	      /* There should 1 space between 'operator' and 'TYPENAME'.  */
 	      if (opname[-1] != ' ' || opname[-2] == ' ')
@@ -5602,7 +5601,7 @@ rbreak_command (const char *regexp, int from_tty)
       if (colon && *(colon + 1) != ':')
 	{
 	  int colon_index = colon - regexp;
-	  while (colon_index > 0 && isspace (regexp[colon_index - 1]))
+	  while (colon_index > 0 && c_isspace (regexp[colon_index - 1]))
 	    --colon_index;
 
 	  file_name = make_unique_xstrndup (regexp, colon_index);
@@ -5854,7 +5853,7 @@ language_search_unquoted_string (const char *text, const char *p)
 {
   for (; p > text; --p)
     {
-      if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0')
+      if (c_isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0')
 	continue;
       else
 	{
@@ -5874,7 +5873,7 @@ language_search_unquoted_string (const char *text, const char *p)
 		     Unfortunately we have to find it now to decide.  */
 
 		  while (t > text)
-		    if (isalnum (t[-1]) || t[-1] == '_' ||
+		    if (c_isalnum (t[-1]) || t[-1] == '_' ||
 			t[-1] == ' '    || t[-1] == ':' ||
 			t[-1] == '('    || t[-1] == ')')
 		      --t;
@@ -6082,7 +6081,7 @@ default_collect_symbol_completion_matches_break_on
 	     which are in symbols.  */
 	  while (p > text)
 	    {
-	      if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0'
+	      if (c_isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0'
 		  || p[-1] == ':' || strchr (break_on, p[-1]) != NULL)
 		--p;
 	      else
diff --git a/gdb/thread.c b/gdb/thread.c
index 920d8dc07a8551a299b475526fa0ac60588b0c32..b6c19f9bfc1122863e571dc93bd1c9bbaffe001b 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -33,7 +33,6 @@
 #include "regcache.h"
 #include "btrace.h"
 
-#include <ctype.h>
 #include <sys/types.h>
 #include <signal.h>
 #include "ui-out.h"
@@ -1808,7 +1807,7 @@ thread_apply_command_completer (cmd_list_element *ignore,
 
   /* Check if we're past a valid thread ID list already.  */
   if (parser.finished ()
-      && cmd > text && !isspace (cmd[-1]))
+      && cmd > text && !c_isspace (cmd[-1]))
     return;
 
   /* We're past the thread ID list, advance word point.  */
@@ -1871,7 +1870,7 @@ thread_apply_command (const char *tidlist, int from_tty)
   if (*cmd == '\0')
     error (_("Please specify a command following the thread ID list"));
 
-  if (tidlist == cmd || isdigit (cmd[0]))
+  if (tidlist == cmd || c_isdigit (cmd[0]))
     invalid_thread_id_error (cmd);
 
   scoped_restore_current_thread restore_thread;
diff --git a/gdb/tid-parse.c b/gdb/tid-parse.c
index 4e45798b27b8bd2284c00ffa6eead42158c54168..9f79fba6077ab9594b1285c1a7996c1415d54dbb 100644
--- a/gdb/tid-parse.c
+++ b/gdb/tid-parse.c
@@ -20,7 +20,6 @@
 #include "tid-parse.h"
 #include "inferior.h"
 #include "gdbthread.h"
-#include <ctype.h>
 
 /* See tid-parse.h.  */
 
@@ -184,7 +183,7 @@ tid_range_parser::finished () const
 	 or we are not in a range and not in front of an integer, negative
 	 integer, convenience var or negative convenience var.  */
       return (*m_cur_tok == '\0'
-	      || !(isdigit (*m_cur_tok)
+	      || !(c_isdigit (*m_cur_tok)
 		   || *m_cur_tok == '$'
 		   || *m_cur_tok == '*'));
     case STATE_THREAD_RANGE:
@@ -261,7 +260,7 @@ tid_range_parser::get_tid_or_range (int *inf_num,
 	  m_qualified = true;
 	  p = dot + 1;
 
-	  if (isspace (*p))
+	  if (c_isspace (*p))
 	    return false;
 	}
       else
@@ -272,7 +271,7 @@ tid_range_parser::get_tid_or_range (int *inf_num,
 	}
 
       m_range_parser.init (p);
-      if (p[0] == '*' && (p[1] == '\0' || isspace (p[1])))
+      if (p[0] == '*' && (p[1] == '\0' || c_isspace (p[1])))
 	{
 	  /* Setup the number range parser to return numbers in the
 	     whole [1,INT_MAX] range.  */
diff --git a/gdb/top.c b/gdb/top.c
index b097683e6138102fe543dfe5d68dda73895f1124..b13e787067897837218c6988dff045d75cbbd2a4 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -69,7 +69,6 @@
 
 #include "event-top.h"
 #include <sys/stat.h>
-#include <ctype.h>
 #include "ui-out.h"
 #include "cli-out.h"
 #include "tracepoint.h"
diff --git a/gdb/tracectf.c b/gdb/tracectf.c
index 0f80d08e6d6c636a832df59d1bb872bc785a9166..c2231ff32d23fff66507a0b7946149d6f5818d0f 100644
--- a/gdb/tracectf.c
+++ b/gdb/tracectf.c
@@ -28,7 +28,6 @@
 #include "inferior.h"
 #include "gdbthread.h"
 #include "tracefile.h"
-#include <ctype.h>
 #include <algorithm>
 #include "gdbsupport/filestuff.h"
 #include "gdbarch.h"
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index c0f1eae334340e70c2fb9073a5259f8b8fa69613..4667b25b82f0071697610f81e54870596cbd5a72 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -308,12 +308,12 @@ validate_trace_state_variable_name (const char *name)
 
   /* All digits in the name is reserved for value history
      references.  */
-  for (p = name; isdigit (*p); p++)
+  for (p = name; c_isdigit (*p); p++)
     ;
   if (*p == '\0')
     error (_("$%s is not a valid trace state variable name"), name);
 
-  for (p = name; isalnum (*p) || *p == '_'; p++)
+  for (p = name; c_isalnum (*p) || *p == '_'; p++)
     ;
   if (*p != '\0')
     error (_("$%s is not a valid trace state variable name"), name);
@@ -339,7 +339,7 @@ trace_variable_command (const char *args, int from_tty)
     error (_("Name of trace variable should start with '$'"));
 
   name_start = p;
-  while (isalnum (*p) || *p == '_')
+  while (c_isalnum (*p) || *p == '_')
     p++;
   std::string name (name_start, p - name_start);
 
diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index d4fbbf157f119632d1021fdf48e682239d6eeb9c..b411d074ffe196d1424ab9010723c14580a7538c 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -45,7 +45,6 @@
 #include "tui/tui-win.h"
 
 #include "gdb_curses.h"
-#include <ctype.h>
 #include "readline/readline.h"
 #include <signal.h>
 #include <string_view>
@@ -1041,7 +1040,7 @@ parse_scrolling_args (const char *arg,
       /* Process the number of lines to scroll.  */
       std::string copy = arg;
       buf_ptr = &copy[0];
-      if (isdigit (*buf_ptr))
+      if (c_isdigit (*buf_ptr))
 	{
 	  char *num_str;
 
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index ef0c5aadb9ecba8c06fad97464ac3093a7eca85e..4d7465c7381e2ebafd4739053573e00260d64b14 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -31,7 +31,6 @@
 #include "cp-abi.h"
 #include "typeprint.h"
 #include "valprint.h"
-#include <ctype.h>
 #include "cli/cli-utils.h"
 #include "extension.h"
 #include "completer.h"
@@ -367,7 +366,7 @@ whatis_exp (const char *exp, int show)
 	{
 	  int seen_one = 0;
 
-	  for (++exp; *exp && !isspace (*exp); ++exp)
+	  for (++exp; *exp && !c_isspace (*exp); ++exp)
 	    {
 	      switch (*exp)
 		{
@@ -413,7 +412,7 @@ whatis_exp (const char *exp, int show)
 
 	  if (!*exp && !seen_one)
 	    error (_("flag expected"));
-	  if (!isspace (*exp))
+	  if (!c_isspace (*exp))
 	    error (_("expected space after format"));
 	  exp = skip_spaces (exp);
 	}
diff --git a/gdb/unittests/command-def-selftests.c b/gdb/unittests/command-def-selftests.c
index 0a54d31fbc6358291f9972536d6c40e5137cfd7d..095b57f6e95cd900c522b2b8010e27c01c83e2e0 100644
--- a/gdb/unittests/command-def-selftests.c
+++ b/gdb/unittests/command-def-selftests.c
@@ -72,7 +72,7 @@ check_doc (struct cmd_list_element *commandlist, const char *prefix)
 	   "first line is not terminated with a '.' character");
 
       /* Checks the doc is not terminated with a new line.  */
-      if (isspace (c->doc[strlen (c->doc) - 1]))
+      if (c_isspace (c->doc[strlen (c->doc) - 1]))
 	broken_doc_invariant
 	  (prefix, c->name,
 	   "has superfluous trailing whitespace");
@@ -87,7 +87,7 @@ check_doc (struct cmd_list_element *commandlist, const char *prefix)
 	  else
 	    {
 	      /* \n\n is ok, so we check that explicitly here.  */
-	      if (isspace (nl[-1]) && nl[-1] != '\n')
+	      if (c_isspace (nl[-1]) && nl[-1] != '\n')
 		broken_doc_invariant (prefix, c->name,
 				      "has whitespace before a newline");
 	    }
diff --git a/gdb/utils.c b/gdb/utils.c
index c1a36025b6cfe70f997e750b8175d86bd9a8deb6..9edcf25804dc21bdbeb5c0a02be69856e8684997 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -17,7 +17,6 @@
    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 <ctype.h>
 #include "gdbsupport/gdb_wait.h"
 #include "gdbsupport/scoped_signal_handler.h"
 #include "event-top.h"
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 305faf73a56cf8bea41debf2bb4fcbbf86150545..b8c1c06ec87b82316f0f5014898fc42a1678c556 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -34,7 +34,6 @@
 #include "gdbsupport/gdb_obstack.h"
 #include "charset.h"
 #include "typeprint.h"
-#include <ctype.h>
 #include <algorithm>
 #include "gdbsupport/byte-vector.h"
 #include "cli/cli-option.h"
diff --git a/gdb/value.c b/gdb/value.c
index 82d9a86e372aea4a50d0b612996cf8ebecc39058..c78bb98cb7eb1f3e96e1e31bb594b12207c91efc 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -35,7 +35,6 @@
 #include "valprint.h"
 #include "cli/cli-decode.h"
 #include "extension.h"
-#include <ctype.h>
 #include "tracepoint.h"
 #include "cp-abi.h"
 #include "user-regs.h"
@@ -3723,11 +3722,11 @@ value_from_history_ref (const char *h, const char **endp)
     len = 2;
 
   /* Find length of numeral string.  */
-  for (; isdigit (h[len]); len++)
+  for (; c_isdigit (h[len]); len++)
     ;
 
   /* Make sure numeral string is not part of an identifier.  */
-  if (h[len] == '_' || isalpha (h[len]))
+  if (h[len] == '_' || c_isalpha (h[len]))
     return NULL;
 
   /* Now collect the index value.  */
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index c001d38fc5151a5a6123566013e96fcbc3c14b5c..f74ea0cc11b3c68214204002f0a2190a33ccb26f 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -2426,7 +2426,7 @@ redir_set_redirection (const char *s, int *inp, int *out, int *err)
   /* cmd.exe recognizes "&N" only immediately after the redirection symbol.  */
   if (*s != '&')
     {
-      while (isspace (*s))  /* skip whitespace before file name */
+      while (c_isspace (*s))  /* skip whitespace before file name */
 	s++;
       *d++ = ' ';	    /* separate file name with a single space */
     }
@@ -2453,7 +2453,7 @@ redir_set_redirection (const char *s, int *inp, int *out, int *err)
 	    s++;
 	  *d++ = *s++;
 	}
-      else if (isspace (*s) && !quote)
+      else if (c_isspace (*s) && !quote)
 	break;
       else
 	*d++ = *s++;
@@ -2489,7 +2489,7 @@ redirect_inferior_handles (const char *cmd_orig, char *cmd,
   int quote = 0;
   bool retval = false;
 
-  while (isspace (*s))
+  while (c_isspace (*s))
     *d++ = *s++;
 
   while (*s)
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 70585b36d20ce430d336dfe6b62d17446a85415d..dbe535e02de5ec1582653e1b6928f166a05a1b17 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -23,7 +23,6 @@
 
 #include <sys/types.h>
 #include <fcntl.h>
-#include <ctype.h>
 #ifdef HAVE_SYS_FILE_H
 #include <sys/file.h>
 #endif
diff --git a/gdbserver/gdbreplay.cc b/gdbserver/gdbreplay.cc
index 44aa2fb52cef2164656d92ceb24de8d6f7fa0b89..a905fff0cf6106502eebae0c8426feab24045698 100644
--- a/gdbserver/gdbreplay.cc
+++ b/gdbserver/gdbreplay.cc
@@ -32,7 +32,6 @@
 #if HAVE_SIGNAL_H
 #include <signal.h>
 #endif
-#include <ctype.h>
 #if HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
diff --git a/gdbserver/remote-utils.cc b/gdbserver/remote-utils.cc
index 15f073dd6bece9225e03c4a0ab47b17f64ca3b72..760655994c51d7f989f40c555284deddb0e2dc81 100644
--- a/gdbserver/remote-utils.cc
+++ b/gdbserver/remote-utils.cc
@@ -30,7 +30,6 @@
 #include "gdbsupport/netstuff.h"
 #include "gdbsupport/filestuff.h"
 #include "gdbsupport/gdb-sigmask.h"
-#include <ctype.h>
 #if HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
@@ -759,7 +758,7 @@ input_interrupt (int unused)
       else if (cc != 1 || c != '\003')
 	{
 	  fprintf (stderr, "input_interrupt, count = %d c = %d ", cc, c);
-	  if (isprint (c))
+	  if (c_isprint (c))
 	    fprintf (stderr, "('%c')\n", c);
 	  else
 	    fprintf (stderr, "('\\x%02x')\n", c & 0xff);
@@ -1165,8 +1164,8 @@ prepare_resume_reply (char *buf, ptid_t ptid, const target_waitstatus &status)
 	       here is convert the buffer from a T packet to an S packet
 	       and the avoid adding any extra content by breaking out.  */
 	    gdb_assert (buf_start[0] == 'T');
-	    gdb_assert (isxdigit (buf_start[1]));
-	    gdb_assert (isxdigit (buf_start[2]));
+	    gdb_assert (c_isxdigit (buf_start[1]));
+	    gdb_assert (c_isxdigit (buf_start[2]));
 	    buf_start[0] = 'S';
 	    buf_start[3] = '\0';
 	    break;
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 673b784e42b3d047bf9149f512137b54a0804a36..60afc852235d36a9fafbe6af7c3a88f4585caac1 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -22,7 +22,6 @@
 #include "tdesc.h"
 #include "gdbsupport/rsp-low.h"
 #include "gdbsupport/signals-state-save-restore.h"
-#include <ctype.h>
 #include <unistd.h>
 #if HAVE_SIGNAL_H
 #include <signal.h>
@@ -1427,7 +1426,7 @@ parse_debug_format_options (const char *arg, int is_monitor)
   debug_timestamp = 0;
 
   /* First remove leading spaces, for "monitor set debug-format".  */
-  while (isspace (*arg))
+  while (c_isspace (*arg))
     ++arg;
 
   std::vector<gdb::unique_xmalloc_ptr<char>> options
@@ -1473,8 +1472,8 @@ parse_debug_format_options (const char *arg, int is_monitor)
 struct debug_opt
 {
   /* NAME is the name of this debug option, this should be a simple string
-     containing no whitespace, starting with a letter from isalpha(), and
-     contain only isalnum() characters and '_' underscore and '-' hyphen.
+     containing no whitespace, starting with a letter from c_isalpha(), and
+     contain only c_isalnum() characters and '_' underscore and '-' hyphen.
 
      SETTER is a callback function used to set the debug variable.  This
      callback will be passed true to enable the debug setting, or false to
@@ -1483,7 +1482,7 @@ struct debug_opt
     : m_name (name),
       m_setter (setter)
   {
-    gdb_assert (isalpha (*name));
+    gdb_assert (c_isalpha (*name));
   }
 
   /* Called to enable or disable the debug setting.  */
diff --git a/gdbserver/thread-db.cc b/gdbserver/thread-db.cc
index 20e1dccab18c4773746a5d74776df5b7350452bd..b964389e959dbec8b096a43eaf9474e41313fa14 100644
--- a/gdbserver/thread-db.cc
+++ b/gdbserver/thread-db.cc
@@ -32,7 +32,6 @@
 #include <dlfcn.h>
 #endif
 #include <limits.h>
-#include <ctype.h>
 
 struct thread_db
 {
@@ -849,7 +848,7 @@ thread_db_handle_monitor_command (char *mon)
 	free (libthread_db_search_path);
 
       /* Skip leading space (if any).  */
-      while (isspace (*cp))
+      while (c_isspace (*cp))
 	++cp;
 
       if (*cp == '\0')
diff --git a/gdbserver/tracepoint.cc b/gdbserver/tracepoint.cc
index b308c821e8fbf08fe7cfd40f8f77a4439a22e717..e1044dca5585865b82eded5bfdcb9872c4177f16 100644
--- a/gdbserver/tracepoint.cc
+++ b/gdbserver/tracepoint.cc
@@ -20,7 +20,6 @@
 #include "gdbthread.h"
 #include "gdbsupport/rsp-low.h"
 
-#include <ctype.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <chrono>
@@ -1867,7 +1866,7 @@ add_tracepoint_action (struct tracepoint *tpoint, const char *packet)
 	    trace_debug ("Want to collect registers");
 	    ++act;
 	    /* skip past hex digits of mask for now */
-	    while (isxdigit(*act))
+	    while (c_isxdigit(*act))
 	      ++act;
 	    break;
 	  }
diff --git a/gdbsupport/pathstuff.cc b/gdbsupport/pathstuff.cc
index ce01c95304881caf3cd1c634c87b144264291d49..1866949d62daf34ad3745b617ff40b69667cc9c2 100644
--- a/gdbsupport/pathstuff.cc
+++ b/gdbsupport/pathstuff.cc
@@ -106,7 +106,7 @@ gdb_realpath_keepfile (const char *filename)
 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
   /* We need to be careful when filename is of the form 'd:foo', which
      is equivalent of d:./foo, which is totally different from d:/foo.  */
-  if (strlen (dir_name) == 2 && isalpha (dir_name[0]) && dir_name[1] == ':')
+  if (strlen (dir_name) == 2 && c_isalpha (dir_name[0]) && dir_name[1] == ':')
     {
       dir_name[2] = '.';
       dir_name[3] = '\000';

-- 
2.50.1


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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-08-06 13:13 [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h> Tom Tromey
                   ` (2 preceding siblings ...)
  2025-08-06 13:13 ` [PATCH 3/3] Use gnulib c-ctype module " Tom Tromey
@ 2025-08-06 19:46 ` Simon Marchi
  2025-08-07 20:39   ` Tom Tromey
  2025-10-14 13:00 ` Guinevere Larsen
  4 siblings, 1 reply; 16+ messages in thread
From: Simon Marchi @ 2025-08-06 19:46 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

On 8/6/25 9:13 AM, Tom Tromey wrote:
> This series changes gdb to use the gnulib c-ctype module rather than
> <ctype.h> or "safe-ctype.h".
> 
> The rationale is mostly in patch #3.  I do wonder if it would be
> better to just add the casts everywhere.
> 
> Regression tested on x86-64 Fedora 41.  This doesn't cover
> solib-rocm.c though.
> 
> Signed-off-by: Tom Tromey <tromey@adacore.com>

My understanding is that poisoning using macros doesn't work, because it
interferes with identifiers of the same name in other headers.  But
would it be possible to do it using "#pragma GCC poison"?  Like:

  #pragma GCC poison isspace

If I try to use it, I get:

      CXX    cp-support.o
    /home/smarchi/src/binutils-gdb/gdb/cp-support.c:1137:22: error: attempt to use poisoned ‘isspace’
     1137 |               while (isspace(name[index]))
          |                      ^
    In file included from /home/smarchi/src/binutils-gdb/gdb/defs.h:26,
                     from <command-line>:
    /home/smarchi/src/binutils-gdb/gdb/../gdbsupport/common-defs.h:231:20: note: poisoned here
      231 | #pragma GCC poison isspace
          |                    ^~~~~~~

This pragma can obviously be gated by an appropriate ifdef, if not all
compilers support it.

I was wondering if clang-tidy would have a check for this.  The answer
is no, but there is a bug open about it:

  https://github.com/llvm/llvm-project/issues/63280

Simon

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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-08-06 19:46 ` [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h> Simon Marchi
@ 2025-08-07 20:39   ` Tom Tromey
  2025-08-20 17:14     ` Simon Marchi
  0 siblings, 1 reply; 16+ messages in thread
From: Tom Tromey @ 2025-08-07 20:39 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tom Tromey, gdb-patches

>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:

Simon> My understanding is that poisoning using macros doesn't work, because it
Simon> interferes with identifiers of the same name in other headers.  But
Simon> would it be possible to do it using "#pragma GCC poison"?  Like:

I didn't try it but that's because I believe it won't work.

The pragma is better than the preprocessor approach, the manual says:

     If a poisoned identifier appears as part of the expansion of a
     macro which was defined before the identifier was poisoned, it will
     _not_ cause an error.  This lets you poison an identifier without
     worrying about system headers defining macros that use it.

However in our case the poisoning would likely occur before the
inclusion of the offending header.  The workaround would be to include
the locale (and maybe iostream?) headers everywhere, but I think we
definitely should not do that.

FTR the failure I saw (with cpp-style poisoning, a la safe-ctype.h) came
from source-cache.c which includes some locale stuff via <sstream>.

The main issue here is that the pragma works on an identifier basis but
really we'd like to be more selective and only exclude some particular
functions.

Tom

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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-08-07 20:39   ` Tom Tromey
@ 2025-08-20 17:14     ` Simon Marchi
  2025-09-09 17:53       ` Tom Tromey
  0 siblings, 1 reply; 16+ messages in thread
From: Simon Marchi @ 2025-08-20 17:14 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 8/7/25 4:39 PM, Tom Tromey wrote:
>>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:
> 
> Simon> My understanding is that poisoning using macros doesn't work, because it
> Simon> interferes with identifiers of the same name in other headers.  But
> Simon> would it be possible to do it using "#pragma GCC poison"?  Like:
> 
> I didn't try it but that's because I believe it won't work.
> 
> The pragma is better than the preprocessor approach, the manual says:
> 
>      If a poisoned identifier appears as part of the expansion of a
>      macro which was defined before the identifier was poisoned, it will
>      _not_ cause an error.  This lets you poison an identifier without
>      worrying about system headers defining macros that use it.
> 
> However in our case the poisoning would likely occur before the
> inclusion of the offending header.  The workaround would be to include
> the locale (and maybe iostream?) headers everywhere, but I think we
> definitely should not do that.
> 
> FTR the failure I saw (with cpp-style poisoning, a la safe-ctype.h) came
> from source-cache.c which includes some locale stuff via <sstream>.

Indeed, it doesn't work:

  CXX      agent.o
In file included from ../gnulib/import/ctype.h:35,
                 from /usr/include/c++/15.2.1/cctype:47,
                 from /usr/include/c++/15.2.1/bits/localefwd.h:44,
                 from /usr/include/c++/15.2.1/string:47,
                 from /home/smarchi/src/binutils-gdb/gdbsupport/ptid.h:36,
                 from /home/smarchi/src/binutils-gdb/gdbsupport/common-defs.h:214,
                 from <command-line>:
/usr/include/ctype.h:108:12: error: attempt to use poisoned ‘isalnum’
  108 | __exctype (isalnum);
      |            ^
/home/smarchi/src/binutils-gdb/gdbsupport/common-defs.h:208:20: note: poisoned here
  208 | #pragma GCC poison isalnum
      |                    ^~~~~~~

> The main issue here is that the pragma works on an identifier basis but
> really we'd like to be more selective and only exclude some particular
> functions.

As far as I'm concerned, this patch series LGTM, I'm not aware of better
alternatives.

Approved-By: Simon Marchi <simon.marchi@efficios.com>

Simon

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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-08-20 17:14     ` Simon Marchi
@ 2025-09-09 17:53       ` Tom Tromey
  2025-09-09 18:01         ` Simon Marchi
  0 siblings, 1 reply; 16+ messages in thread
From: Tom Tromey @ 2025-09-09 17:53 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tom Tromey, gdb-patches

>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:

Simon> As far as I'm concerned, this patch series LGTM, I'm not aware of better
Simon> alternatives.

Simon> Approved-By: Simon Marchi <simon.marchi@efficios.com>

I'm going to check this in now.

Just as a reminder to everyone, gdb should generally use these new
"c-ctype" wrapper functions and not <ctype.h>.

One idea I had for enforcement was to write a new pre-commit script that
looked for includes of ctype.h or safe-ctype.h.  WDYT?

Tom

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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-09-09 17:53       ` Tom Tromey
@ 2025-09-09 18:01         ` Simon Marchi
  2025-09-09 18:55           ` Tom Tromey
  0 siblings, 1 reply; 16+ messages in thread
From: Simon Marchi @ 2025-09-09 18:01 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 9/9/25 1:53 PM, Tom Tromey wrote:
>>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:
> 
> Simon> As far as I'm concerned, this patch series LGTM, I'm not aware of better
> Simon> alternatives.
> 
> Simon> Approved-By: Simon Marchi <simon.marchi@efficios.com>
> 
> I'm going to check this in now.
> 
> Just as a reminder to everyone, gdb should generally use these new
> "c-ctype" wrapper functions and not <ctype.h>.
> 
> One idea I had for enforcement was to write a new pre-commit script that
> looked for includes of ctype.h or safe-ctype.h.  WDYT?
> 
> Tom

1. Should all includes of ctype.h and safe-ctype.h be removed from GDB
right now, in any case?

2. Is ctype.h available transitively anyway?  If so, we could add a
call to a ctype.h function without adding an include, so the script
wouldn't catch it.  The script wouldn't hurt, but I don't think it would
be terribly useful.

Simon

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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-09-09 18:01         ` Simon Marchi
@ 2025-09-09 18:55           ` Tom Tromey
  0 siblings, 0 replies; 16+ messages in thread
From: Tom Tromey @ 2025-09-09 18:55 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tom Tromey, gdb-patches

>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:

>> Just as a reminder to everyone, gdb should generally use these new
>> "c-ctype" wrapper functions and not <ctype.h>.
>> 
>> One idea I had for enforcement was to write a new pre-commit script that
>> looked for includes of ctype.h or safe-ctype.h.  WDYT?

Simon> 1. Should all includes of ctype.h and safe-ctype.h be removed from GDB
Simon> right now, in any case?

Yeah, this series did that.

Simon> 2. Is ctype.h available transitively anyway?  If so, we could add a
Simon> call to a ctype.h function without adding an include, so the script
Simon> wouldn't catch it.

That's true, it's available sometimes depending on which libstdc++
headers are included.

Tom

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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-08-06 13:13 [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h> Tom Tromey
                   ` (3 preceding siblings ...)
  2025-08-06 19:46 ` [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h> Simon Marchi
@ 2025-10-14 13:00 ` Guinevere Larsen
  2025-10-14 19:19   ` Tom Tromey
  4 siblings, 1 reply; 16+ messages in thread
From: Guinevere Larsen @ 2025-10-14 13:00 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

On 8/6/25 10:13 AM, Tom Tromey wrote:
> This series changes gdb to use the gnulib c-ctype module rather than
> <ctype.h> or "safe-ctype.h".
>
> The rationale is mostly in patch #3.  I do wonder if it would be
> better to just add the casts everywhere.
>
> Regression tested on x86-64 Fedora 41.  This doesn't cover
> solib-rocm.c though.
>
> Signed-off-by: Tom Tromey <tromey@adacore.com>

This patch series causes compilation to fail when using clang to compile 
GDB in fedora rawhide.

The errors look like this:

/usr/bin/ld: gdbsupport/common-utils-ipa.o: in function `strtoulst(char 
const*, char const**, int)':
/home/buildbot/buildbot/binutils-gdb-clang-fedrawhide-x86_64/build/gdbserver/../gdbsupport/common-utils.cc:256:(.text+0xa3d): 
undefined reference to `c_isalnum'
/usr/bin/ld: 
/home/buildbot/buildbot/binutils-gdb-clang-fedrawhide-x86_64/build/gdbserver/../gdbsupport/common-utils.cc:256:(.text+0xb0a): 
undefined reference to `c_isalnum'
clang++: error: linker command failed with exit code 1 (use -v to see 
invocation)

I have no idea why the newest clang has this problem and no other 
compiler does, might be a bug, but regardless, it is causing the clang 
buildbot to stop working

> ---
> Tom Tromey (3):
>        Import the c-ctype module from gnulib
>        Use c-ctype.h (not safe-ctype.h) in gdb
>        Use gnulib c-ctype module in gdb
>
>   gdb/aarch64-linux-tdep.c              |   9 +-
>   gdb/ada-exp.y                         |   5 +-
>   gdb/ada-lang.c                        |  87 ++++----
>   gdb/ada-lex.l                         |  23 +--
>   gdb/ada-typeprint.c                   |   3 +-
>   gdb/ada-valprint.c                    |   5 +-
>   gdb/arm-linux-tdep.c                  |   9 +-
>   gdb/arm-tdep.c                        |   1 -
>   gdb/auto-load.c                       |   3 +-
>   gdb/break-catch-exec.c                |   4 +-
>   gdb/break-catch-fork.c                |   2 +-
>   gdb/break-catch-syscall.c             |   3 +-
>   gdb/break-catch-throw.c               |   3 +-
>   gdb/break-cond-parse.c                |   4 +-
>   gdb/breakpoint.c                      |   7 +-
>   gdb/btrace.c                          |   5 +-
>   gdb/c-exp.y                           |  19 +-
>   gdb/c-lang.c                          |  11 +-
>   gdb/c-support.h                       |  10 +-
>   gdb/charset.c                         |   1 -
>   gdb/cli/cli-cmds.c                    |  16 +-
>   gdb/cli/cli-decode.c                  |   9 +-
>   gdb/cli/cli-dump.c                    |   1 -
>   gdb/cli/cli-option.c                  |   4 +-
>   gdb/cli/cli-script.c                  |   7 +-
>   gdb/cli/cli-setshow.c                 |   3 +-
>   gdb/cli/cli-utils.c                   |  27 ++-
>   gdb/coff-pe-read.c                    |   3 +-
>   gdb/coffread.c                        |   7 +-
>   gdb/completer.c                       |   2 +-
>   gdb/cp-name-parser.y                  |  11 +-
>   gdb/cp-support.c                      |   9 +-
>   gdb/d-exp.y                           |  22 +-
>   gdb/darwin-nat.c                      |   1 -
>   gdb/dictionary.c                      |   4 +-
>   gdb/disasm.c                          |   1 -
>   gdb/dwarf2/cooked-index-entry.c       |   3 +-
>   gdb/dwarf2/index-common.c             |  10 +-
>   gdb/dwarf2/read.c                     |   4 +-
>   gdb/eval.c                            |   1 -
>   gdb/exec.c                            |   3 +-
>   gdb/expprint.c                        |   1 -
>   gdb/f-exp.y                           |   5 +-
>   gdb/fbsd-nat.c                        |   2 +-
>   gdb/findcmd.c                         |   7 +-
>   gdb/gdb_wchar.h                       |   4 +-
>   gdb/gnu-nat.c                         |   3 +-
>   gdb/gnu-v2-abi.c                      |   3 +-
>   gdb/go-exp.y                          |   9 +-
>   gdb/go-lang.c                         |   3 +-
>   gdb/go32-nat.c                        |   1 -
>   gdb/guile/scm-cmd.c                   |   1 -
>   gdb/i386-tdep.c                       |  25 ++-
>   gdb/ia64-linux-tdep.c                 |   5 +-
>   gdb/infcmd.c                          |   7 +-
>   gdb/infrun.c                          |   3 +-
>   gdb/language.c                        |   1 -
>   gdb/linespec.c                        |  19 +-
>   gdb/linux-fork.c                      |   3 +-
>   gdb/linux-nat.c                       |   1 -
>   gdb/linux-tdep.c                      |  17 +-
>   gdb/linux-thread-db.c                 |   1 -
>   gdb/location.c                        |  17 +-
>   gdb/main.c                            |   3 +-
>   gdb/maint.c                           |   5 +-
>   gdb/mi/mi-cmd-break.c                 |   3 +-
>   gdb/mi/mi-cmd-stack.c                 |   2 -
>   gdb/mi/mi-cmd-var.c                   |   3 +-
>   gdb/mi/mi-main.c                      |   1 -
>   gdb/mi/mi-parse.c                     |  11 +-
>   gdb/minsyms.c                         |   2 -
>   gdb/minsyms.h                         |   2 +-
>   gdb/nat/linux-osdata.c                |  15 +-
>   gdb/netbsd-nat.c                      |   2 +-
>   gdb/objc-lang.c                       |  13 +-
>   gdb/or1k-tdep.c                       |   1 -
>   gdb/p-exp.y                           |  17 +-
>   gdb/p-lang.c                          |   1 -
>   gdb/p-typeprint.c                     |   5 +-
>   gdb/parse.c                           |   1 -
>   gdb/ppc-linux-tdep.c                  |  13 +-
>   gdb/printcmd.c                        |   1 -
>   gdb/probe.c                           |   3 +-
>   gdb/procfs.c                          |   5 +-
>   gdb/producer.c                        |   4 +-
>   gdb/python/py-mi.c                    |   6 +-
>   gdb/python/py-micmd.c                 |   4 +-
>   gdb/python/py-objfile.c               |   2 +-
>   gdb/python/python.c                   |   1 -
>   gdb/record.c                          |   9 +-
>   gdb/remote-sim.c                      |   1 -
>   gdb/remote.c                          |   7 +-
>   gdb/riscv-tdep.c                      |   5 +-
>   gdb/rust-lang.c                       |   3 +-
>   gdb/s12z-tdep.c                       |   2 +-
>   gdb/s390-tdep.c                       |   4 +-
>   gdb/serial.c                          |   3 +-
>   gdb/solib-rocm.c                      |   6 +-
>   gdb/stabsread.c                       |   7 +-
>   gdb/stack.c                           |   4 +-
>   gdb/stap-probe.c                      |  23 +--
>   gdb/symfile.c                         |   3 +-
>   gdb/symtab.c                          |  17 +-
>   gdb/thread.c                          |   5 +-
>   gdb/tid-parse.c                       |   7 +-
>   gdb/top.c                             |   1 -
>   gdb/tracectf.c                        |   1 -
>   gdb/tracepoint.c                      |   6 +-
>   gdb/tui/tui-layout.c                  |   7 +-
>   gdb/tui/tui-win.c                     |   3 +-
>   gdb/tui/tui-winsource.c               |   3 +-
>   gdb/typeprint.c                       |   5 +-
>   gdb/unittests/command-def-selftests.c |   4 +-
>   gdb/utils.c                           |  47 ++---
>   gdb/valprint.c                        |   1 -
>   gdb/value.c                           |   5 +-
>   gdb/windows-nat.c                     |   6 +-
>   gdb/xcoffread.c                       |   1 -
>   gdb/xml-support.c                     |   5 +-
>   gdbserver/gdbreplay.cc                |   1 -
>   gdbserver/linux-low.cc                |   3 +-
>   gdbserver/remote-utils.cc             |   7 +-
>   gdbserver/server.cc                   |   9 +-
>   gdbserver/thread-db.cc                |   3 +-
>   gdbserver/tracepoint.cc               |   3 +-
>   gdbsupport/common-defs.h              |   6 +
>   gdbsupport/common-utils.cc            |  21 +-
>   gdbsupport/gdb-safe-ctype.h           |  49 -----
>   gdbsupport/pathstuff.cc               |   2 +-
>   gnulib/configure                      |  25 +--
>   gnulib/import/Makefile.am             |   7 +
>   gnulib/import/Makefile.in             |  33 ++-
>   gnulib/import/c-ctype.c               |  21 ++
>   gnulib/import/c-ctype.h               | 366 ++++++++++++++++++++++++++++++++++
>   gnulib/import/m4/gnulib-cache.m4      |   2 +
>   gnulib/import/m4/gnulib-comp.m4       |   3 +
>   gnulib/update-gnulib.sh               |   1 +
>   137 files changed, 828 insertions(+), 561 deletions(-)
> ---
> base-commit: c2729c37f10af09126b2916215cae425ae724f55
> change-id: 20250805-gnulib-c-ctype-1b8fb88a6c5e
>
> Best regards,


-- 
Cheers,
Guinevere Larsen
It/she


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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-10-14 13:00 ` Guinevere Larsen
@ 2025-10-14 19:19   ` Tom Tromey
  2025-10-16 15:30     ` Tom Tromey
  0 siblings, 1 reply; 16+ messages in thread
From: Tom Tromey @ 2025-10-14 19:19 UTC (permalink / raw)
  To: Guinevere Larsen; +Cc: Tom Tromey, gdb-patches

Guinevere> This patch series causes compilation to fail when using clang to
Guinevere> compile GDB in fedora rawhide.

Guinevere> The errors look like this:

Guinevere> /usr/bin/ld: gdbsupport/common-utils-ipa.o: in function
Guinevere> `strtoulst(char const*, char const**, int)':
Guinevere> /home/buildbot/buildbot/binutils-gdb-clang-fedrawhide-x86_64/build/gdbserver/../gdbsupport/common-utils.cc:256:(.text+0xa3d):
Guinevere> undefined reference to `c_isalnum'
Guinevere> /usr/bin/ld:
Guinevere> /home/buildbot/buildbot/binutils-gdb-clang-fedrawhide-x86_64/build/gdbserver/../gdbsupport/common-utils.cc:256:(.text+0xb0a):
Guinevere> undefined reference to `c_isalnum'
Guinevere> clang++: error: linker command failed with exit code 1 (use -v to see
Guinevere> invocation)

Guinevere> I have no idea why the newest clang has this problem and no other
Guinevere> compiler does, might be a bug, but regardless, it is causing the clang
Guinevere> buildbot to stop working

gnulib + libinproctrace.so + clang ... lol

I was able to reproduce this.  I am not completely sure what to do here.
Maybe for the IPA case we can use <ctype.h> conditionally.  I'll
probably take this route.

Another option would be to write our own thing akin to "c-ctype" but
that uses the libiberty code instead.  That would work since
libinproctrace.so seems to link against libiberty.

I am more and more tempted to remove gnulib entirely.

I also wonder - is anyone using libinproctrace.so?

Tom

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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-10-14 19:19   ` Tom Tromey
@ 2025-10-16 15:30     ` Tom Tromey
  2025-10-16 21:50       ` Luis
  0 siblings, 1 reply; 16+ messages in thread
From: Tom Tromey @ 2025-10-16 15:30 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Guinevere Larsen, gdb-patches

Tom> Another option would be to write our own thing akin to "c-ctype" but
Tom> that uses the libiberty code instead.  That would work since
Tom> libinproctrace.so seems to link against libiberty.

I tried this but forgot that libinproctrace.so does not use gdbsupport
either.

I strongly dislike how libinproctrace.so was implemented.  A bunch of
cpp conditions in random files seems a lot worse than just having
separate sources, since the rules for the IPA and non-IPA cases are
different.

Tom

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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-10-16 15:30     ` Tom Tromey
@ 2025-10-16 21:50       ` Luis
  2025-10-21 12:59         ` Tom Tromey
  2025-10-21 17:37         ` Simon Marchi
  0 siblings, 2 replies; 16+ messages in thread
From: Luis @ 2025-10-16 21:50 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Guinevere Larsen, gdb-patches

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

On Thu, Oct 16, 2025, 16:30 Tom Tromey <tromey@adacore.com> wrote:

> Tom> Another option would be to write our own thing akin to "c-ctype" but
> Tom> that uses the libiberty code instead.  That would work since
> Tom> libinproctrace.so seems to link against libiberty.
>
> I tried this but forgot that libinproctrace.so does not use gdbsupport
> either.
>
> I strongly dislike how libinproctrace.so was implemented.  A bunch of
> cpp conditions in random files seems a lot worse than just having
> separate sources, since the rules for the IPA and non-IPA cases are
> different.
>
> Tom
>

Does anybody else think it might be time for the IPA to go? It feels like
it is one of those bits that almost nobody uses nowadays and maintenance
hasn't kept up, and it gets in the way of newer changes.

If tracepoints are seldom used in gdbserver, the IPA seems even more niche.

>

[-- Attachment #2: Type: text/html, Size: 1510 bytes --]

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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-10-16 21:50       ` Luis
@ 2025-10-21 12:59         ` Tom Tromey
  2025-10-21 17:37         ` Simon Marchi
  1 sibling, 0 replies; 16+ messages in thread
From: Tom Tromey @ 2025-10-21 12:59 UTC (permalink / raw)
  To: Luis; +Cc: Tom Tromey, Guinevere Larsen, gdb-patches

Luis> Does anybody else think it might be time for the IPA to go?

I think so as well but I've never been all that involved with it in the
first place.

Meanwhile I sent a patch to fix the build bug.

Tom

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

* Re: [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h>
  2025-10-16 21:50       ` Luis
  2025-10-21 12:59         ` Tom Tromey
@ 2025-10-21 17:37         ` Simon Marchi
  1 sibling, 0 replies; 16+ messages in thread
From: Simon Marchi @ 2025-10-21 17:37 UTC (permalink / raw)
  To: Luis, Tom Tromey; +Cc: Guinevere Larsen, gdb-patches

On 10/16/25 5:50 PM, Luis wrote:
> On Thu, Oct 16, 2025, 16:30 Tom Tromey <tromey@adacore.com <mailto:tromey@adacore.com>> wrote:
> 
>     Tom> Another option would be to write our own thing akin to "c-ctype" but
>     Tom> that uses the libiberty code instead.  That would work since
>     Tom> libinproctrace.so seems to link against libiberty.
> 
>     I tried this but forgot that libinproctrace.so does not use gdbsupport
>     either.
> 
>     I strongly dislike how libinproctrace.so was implemented.  A bunch of
>     cpp conditions in random files seems a lot worse than just having
>     separate sources, since the rules for the IPA and non-IPA cases are
>     different.
> 
>     Tom
> 
> 
> Does anybody else think it might be time for the IPA to go? It feels like it is one of those bits that almost nobody uses nowadays and maintenance hasn't kept up, and it gets in the way of newer changes.
> 
> If tracepoints are seldom used in gdbserver, the IPA seems even more niche.

Given the bit-rot and lack of maintenance, I think it would be
reasonable to start the removal process.  That's the only real way to
know if it's actually used... if someone actually needs it, they'll
speak up.

Simon

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

end of thread, other threads:[~2025-10-21 17:38 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-06 13:13 [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h> Tom Tromey
2025-08-06 13:13 ` [PATCH 1/3] Import the c-ctype module from gnulib Tom Tromey
2025-08-06 13:13 ` [PATCH 2/3] Use c-ctype.h (not safe-ctype.h) in gdb Tom Tromey
2025-08-06 13:13 ` [PATCH 3/3] Use gnulib c-ctype module " Tom Tromey
2025-08-06 19:46 ` [PATCH 0/3] Use gnulib c-ctype module, not <ctype.h> Simon Marchi
2025-08-07 20:39   ` Tom Tromey
2025-08-20 17:14     ` Simon Marchi
2025-09-09 17:53       ` Tom Tromey
2025-09-09 18:01         ` Simon Marchi
2025-09-09 18:55           ` Tom Tromey
2025-10-14 13:00 ` Guinevere Larsen
2025-10-14 19:19   ` Tom Tromey
2025-10-16 15:30     ` Tom Tromey
2025-10-16 21:50       ` Luis
2025-10-21 12:59         ` Tom Tromey
2025-10-21 17:37         ` Simon Marchi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox