diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index fddb0d7278c..6184067c805 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -14381,6 +14381,7 @@ extern const struct language_defn ada_language_defn = {
   &ada_varobj_ops,
   NULL,
   NULL,
+  ada_is_string_type,
   "(...)"			/* la_struct_too_deep_ellipsis */
 };
 
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 3be5ef57252..4d5284e2e80 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -715,6 +715,37 @@ c_watch_location_expression (struct type *type, CORE_ADDR addr)
     (xstrprintf ("* (%s *) %s", name.c_str (), core_addr_to_string (addr)));
 }
 
+/* See c-lang.h.  */
+
+bool
+c_is_string_type_p (struct type *type)
+{
+  type = check_typedef (type);
+  while (TYPE_CODE (type) == TYPE_CODE_REF)
+    {
+      type = TYPE_TARGET_TYPE (type);
+      type = check_typedef (type);
+    }
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_ARRAY:
+      {
+	/* See if target type looks like a string.  */
+	struct type *array_target_type = TYPE_TARGET_TYPE (type);
+	return (TYPE_LENGTH (type) > 0
+		&& TYPE_LENGTH (array_target_type) > 0
+		&& c_textual_element_type (array_target_type, 0));
+      }
+    case TYPE_CODE_STRING:
+      return true;
+    default:
+      break;
+    }
+
+  return false;
+}
+
 
 /* Table mapping opcodes into strings for printing operators
    and precedences of the operators.  */
@@ -874,6 +905,7 @@ extern const struct language_defn c_language_defn =
   &c_varobj_ops,
   c_get_compile_context,
   c_compute_program,
+  c_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
 
@@ -1019,6 +1051,7 @@ extern const struct language_defn cplus_language_defn =
   &cplus_varobj_ops,
   cplus_get_compile_context,
   cplus_compute_program,
+  c_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
 
@@ -1073,6 +1106,7 @@ extern const struct language_defn asm_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  c_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
 
@@ -1127,5 +1161,6 @@ extern const struct language_defn minimal_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  c_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
diff --git a/gdb/c-lang.h b/gdb/c-lang.h
index e7b6d5ef737..70a95eadbf8 100644
--- a/gdb/c-lang.h
+++ b/gdb/c-lang.h
@@ -148,6 +148,11 @@ extern int cp_is_vtbl_ptr_type (struct type *);
 
 extern int cp_is_vtbl_member (struct type *);
 
+/* Return true if TYPE is a string type.  Unlike DEFAULT_IS_STRING_TYPE_P
+   this will detect arrays of characters not just TYPE_CODE_STRING.  */
+
+extern bool c_is_string_type_p (struct type *type);
+
 /* These are in c-valprint.c.  */
 
 extern int c_textual_element_type (struct type *, char);
diff --git a/gdb/d-lang.c b/gdb/d-lang.c
index 751c521a75d..0f8f916c9b1 100644
--- a/gdb/d-lang.c
+++ b/gdb/d-lang.c
@@ -251,6 +251,7 @@ extern const struct language_defn d_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  c_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
 
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 77eb50a0761..b03f1f58b41 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -308,6 +308,16 @@ evaluate_subexp_f (struct type *expect_type, struct expression *exp,
   return nullptr;
 }
 
+/* Return true if TYPE is a string.  */
+static bool
+f_is_string_type_p (struct type *type)
+{
+  type = check_typedef (type);
+  return (TYPE_CODE (type) == TYPE_CODE_STRING
+	  || (TYPE_CODE (type) == TYPE_CODE_ARRAY
+	      && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CHAR));
+}
+
 static const char *f_extensions[] =
 {
   ".f", ".F", ".for", ".FOR", ".ftn", ".FTN", ".fpp", ".FPP",
@@ -378,6 +388,7 @@ extern const struct language_defn f_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  f_is_string_type_p,
   "(...)"			/* la_struct_too_deep_ellipsis */
 };
 
diff --git a/gdb/go-lang.c b/gdb/go-lang.c
index b8617cb162d..6473468d4d9 100644
--- a/gdb/go-lang.c
+++ b/gdb/go-lang.c
@@ -130,6 +130,16 @@ go_classify_struct_type (struct type *type)
   return GO_TYPE_NONE;
 }
 
+/* Return true if TYPE is a string.  */
+
+static bool
+go_is_string_type_p (struct type *type)
+{
+  type = check_typedef (type);
+  return (TYPE_CODE (type) == TYPE_CODE_STRUCT
+	  && go_classify_struct_type (type) == GO_TYPE_STRING);
+}
+
 /* Subroutine of unpack_mangled_go_symbol to simplify it.
    Given "[foo.]bar.baz", store "bar" in *PACKAGEP and "baz" in *OBJECTP.
    We stomp on the last '.' to nul-terminate "bar".
@@ -612,6 +622,7 @@ extern const struct language_defn go_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  go_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
 
diff --git a/gdb/language.c b/gdb/language.c
index da8dd1bf7ae..9d0eb03b420 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -723,6 +723,20 @@ default_symbol_name_matcher (const char *symbol_search_name,
 
 /* See language.h.  */
 
+bool
+default_is_string_type_p (struct type *type)
+{
+  type = check_typedef (type);
+  while (TYPE_CODE (type) == TYPE_CODE_REF)
+    {
+      type = TYPE_TARGET_TYPE (type);
+      type = check_typedef (type);
+    }
+  return (TYPE_CODE (type)  == TYPE_CODE_STRING);
+}
+
+/* See language.h.  */
+
 symbol_name_matcher_ftype *
 get_symbol_name_matcher (const language_defn *lang,
 			 const lookup_name_info &lookup_name)
@@ -877,6 +891,7 @@ const struct language_defn unknown_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  default_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
 
@@ -928,6 +943,7 @@ const struct language_defn auto_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  default_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
 
diff --git a/gdb/language.h b/gdb/language.h
index 261f5a33cc7..e7446efa07f 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -450,6 +450,9 @@ struct language_defn
 				       const struct block *expr_block,
 				       CORE_ADDR expr_pc);
 
+    /* Return true if TYPE is a string type.  */
+    bool (*la_is_string_type_p) (struct type *type);
+
     /* This string is used by the 'set print max-depth' setting.  When GDB
        replaces a struct or union (during value printing) that is "too
        deep" this string is displayed instead.  */
@@ -575,6 +578,10 @@ extern enum language set_language (enum language);
 
 extern int pointer_type (struct type *);
 
+/* Return true if TYPE is a string type, otherwise return false.  This
+   default implementation only detects TYPE_CODE_STRING.  */
+extern bool default_is_string_type_p (struct type *type);
+
 /* Error messages */
 
 extern void range_error (const char *, ...) ATTRIBUTE_PRINTF (1, 2);
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index 9f2a97d54fd..1f7113bd71b 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -174,6 +174,27 @@ m2_printstr (struct ui_file *stream, struct type *type, const gdb_byte *string,
     fputs_filtered ("...", stream);
 }
 
+/* Return true if TYPE is a string.  */
+
+static bool
+m2_is_string_type_p (struct type *type)
+{
+  type = check_typedef (type);
+  if (TYPE_CODE (type) == TYPE_CODE_ARRAY
+      && TYPE_LENGTH (type) > 0
+      && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+    {
+      struct type *elttype = check_typedef (TYPE_TARGET_TYPE (type));
+
+      if (TYPE_LENGTH (elttype) == 1 &&
+	  (TYPE_CODE (elttype) == TYPE_CODE_INT
+	   || TYPE_CODE (elttype) == TYPE_CODE_CHAR))
+	return true;
+    }
+
+  return false;
+}
+
 static struct value *
 evaluate_subexp_modula2 (struct type *expect_type, struct expression *exp,
 			 int *pos, enum noside noside)
@@ -399,6 +420,7 @@ extern const struct language_defn m2_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  m2_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
 
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index af92e55a437..b25a98106c1 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -409,6 +409,7 @@ extern const struct language_defn objc_language_defn = {
   &default_varobj_ops,
   NULL,
   NULL,
+  c_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
 
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index c95bf05a98b..93d8e2f5dd3 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -1087,6 +1087,7 @@ extern const struct language_defn opencl_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  c_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
 
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index 0b85f70dfd2..9b9f19b69cf 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -150,6 +150,16 @@ is_pascal_string_type (struct type *type,int *length_pos,
   return 0;
 }
 
+/* This is a wrapper around IS_PASCAL_STRING_TYPE that returns true if TYPE
+   is a string.  */
+
+static bool
+pascal_is_string_type_p (struct type *type)
+{
+  return is_pascal_string_type (type, nullptr, nullptr, nullptr,
+				nullptr, nullptr) > 0;
+}
+
 static void pascal_one_char (int, struct ui_file *, int *);
 
 /* Print the character C on STREAM as part of the contents of a literal
@@ -460,5 +470,6 @@ extern const struct language_defn pascal_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  pascal_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 8faafd49cdd..d878aec6adc 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -226,6 +226,26 @@ rust_chartype_p (struct type *type)
 	  && TYPE_UNSIGNED (type));
 }
 
+/* Return true if TYPE is a string type.  */
+static bool
+rust_is_string_type_p (struct type *type)
+{
+  LONGEST low_bound, high_bound;
+
+  type = check_typedef (type);
+  return ((TYPE_CODE (type) == TYPE_CODE_STRING)
+	  || (TYPE_CODE (type) == TYPE_CODE_PTR
+	      && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_ARRAY
+		  && rust_u8_type_p (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type)))
+		  && get_array_bounds (TYPE_TARGET_TYPE (type), &low_bound,
+				       &high_bound)))
+	  || ((TYPE_CODE (type) == TYPE_CODE_UNION
+	       || (TYPE_CODE (type) == TYPE_CODE_STRUCT
+		   && !rust_enum_p (type)))
+	      && rust_slice_type_p (type)
+	      && strcmp (TYPE_NAME (type), "&str") == 0));
+}
+
 /* If VALUE represents a trait object pointer, return the underlying
    pointer with the correct (i.e., runtime) type.  Otherwise, return
    NULL.  */
@@ -2142,5 +2162,6 @@ extern const struct language_defn rust_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  rust_is_string_type_p,
   "{...}"			/* la_struct_too_deep_ellipsis */
 };
