gdb: Introduce new language field la_is_string_type_p
authorAndrew Burgess <andrew.burgess@embecosm.com>
Tue, 9 Apr 2019 22:06:41 +0000 (23:06 +0100)
committerAndrew Burgess <andrew.burgess@embecosm.com>
Mon, 29 Apr 2019 21:01:08 +0000 (22:01 +0100)
This commit is preparation work for the next commit, and by itself
makes no user visible change to GDB.  I've split this work into a
separate commit in order to make code review easier.

This commit adds a new field 'la_is_string_type_p' to the language
struct, this predicate will return true if a type is a string type for
the given language.

Some languages already have a "is this a string" predicate that I was
able to reuse, while for other languages I've had to add a new
predicate.  In this case I took inspiration from the value printing
code for that language - what different conditions would result in
printing something as a string.

A default "is this a string" method has also been added that looks for
TYPE_CODE_STRING, this is the fallback I've used for a couple of
languages.

In this commit I add the new field and initialise it for each
language, however at this stage the new field is never used.

gdb/ChangeLog:

* ada-lang.c (ada_language_defn): Initialise new field.
* c-lang.c (c_is_string_type_p): New function.
(c_language_defn): Initialise new field.
(cplus_language_defn): Initialise new field.
(asm_language_defn): Initialise new field.
(minimal_language_defn): Initialise new field.
* c-lang.h (c_is_string_type_p): Declare new function.
* d-lang.c (d_language_defn): Initialise new field.
* f-lang.c (f_is_string_type_p): New function.
(f_language_defn): Initialise new field.
* go-lang.c (go_is_string_type_p): New function.
(go_language_defn): Initialise new field.
* language.c (default_is_string_type_p): New function.
(unknown_language_defn): Initialise new field.
(auto_language_defn): Initialise new field.
* language.h (struct language_defn) <la_is_string_type_p>: New
member variable.
(default_is_string_type_p): Declare new function.
* m2-lang.c (m2_language_defn): Initialise new field.
* objc-lang.c (objc_language_defn): Initialise new field.
* opencl-lang.c (opencl_language_defn): Initialise new field.
* p-lang.c (pascal_is_string_type_p): New function.
(pascal_language_defn): Initialise new field.
* rust-lang.c (rust_is_string_type_p): New function.
(rust_language_defn): Initialise new field.

14 files changed:
gdb/ChangeLog
gdb/ada-lang.c
gdb/c-lang.c
gdb/c-lang.h
gdb/d-lang.c
gdb/f-lang.c
gdb/go-lang.c
gdb/language.c
gdb/language.h
gdb/m2-lang.c
gdb/objc-lang.c
gdb/opencl-lang.c
gdb/p-lang.c
gdb/rust-lang.c

index 0bbe400aae322a0c2cae2521bcae3bb4c0be3fa1..432eb7bda0e18de263a1776174a6716887b6c7b0 100644 (file)
@@ -1,3 +1,31 @@
+2019-04-29  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * ada-lang.c (ada_language_defn): Initialise new field.
+       * c-lang.c (c_is_string_type_p): New function.
+       (c_language_defn): Initialise new field.
+       (cplus_language_defn): Initialise new field.
+       (asm_language_defn): Initialise new field.
+       (minimal_language_defn): Initialise new field.
+       * c-lang.h (c_is_string_type_p): Declare new function.
+       * d-lang.c (d_language_defn): Initialise new field.
+       * f-lang.c (f_is_string_type_p): New function.
+       (f_language_defn): Initialise new field.
+       * go-lang.c (go_is_string_type_p): New function.
+       (go_language_defn): Initialise new field.
+       * language.c (default_is_string_type_p): New function.
+       (unknown_language_defn): Initialise new field.
+       (auto_language_defn): Initialise new field.
+       * language.h (struct language_defn) <la_is_string_type_p>: New
+       member variable.
+       (default_is_string_type_p): Declare new function.
+       * m2-lang.c (m2_language_defn): Initialise new field.
+       * objc-lang.c (objc_language_defn): Initialise new field.
+       * opencl-lang.c (opencl_language_defn): Initialise new field.
+       * p-lang.c (pascal_is_string_type_p): New function.
+       (pascal_language_defn): Initialise new field.
+       * rust-lang.c (rust_is_string_type_p): New function.
+       (rust_language_defn): Initialise new field.
+
 2019-04-29  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * language.h (struct language_defn) <la_struct_too_deep_ellipsis>:
index 4fcbce7c273581e8125f854100dcf872eb09d980..28ab931e3cf0dada9acbb4dafc717ea6ec9f56fd 100644 (file)
@@ -14390,6 +14390,7 @@ extern const struct language_defn ada_language_defn = {
   &ada_varobj_ops,
   NULL,
   NULL,
+  ada_is_string_type,
   "(...)"                      /* la_struct_too_deep_ellipsis */
 };
 
index 3be5ef57252dac0fa1bf64de6ea4e67fbd49242c..aeffefad55e0011258a29e1f510f4950865441cb 100644 (file)
@@ -715,6 +715,42 @@ 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;
+    case TYPE_CODE_PTR:
+      {
+       struct type *element_type = TYPE_TARGET_TYPE (type);
+       return c_textual_element_type (element_type, 0);
+      }
+    default:
+      break;
+    }
+
+  return false;
+}
+
 \f
 /* Table mapping opcodes into strings for printing operators
    and precedences of the operators.  */
@@ -874,6 +910,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 +1056,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 +1111,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 +1166,6 @@ extern const struct language_defn minimal_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  c_is_string_type_p,
   "{...}"                      /* la_struct_too_deep_ellipsis */
 };
index e7b6d5ef7371a82d723e0cc68af60b7c7c5e005f..70a95eadbf8e176b59313ee34e344e790c40d4dd 100644 (file)
@@ -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);
index 751c521a75d27491559be28d29572786c777e4ca..0f8f916c9b1aea2a424595500408ee852fb73671 100644 (file)
@@ -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 */
 };
 
index 77eb50a0761f1463f907861dd90b2928ebe4bcbe..e501d5cc355e4a5427c34a83da8bb0aea16a7630 100644 (file)
@@ -308,6 +308,17 @@ 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 +389,7 @@ extern const struct language_defn f_language_defn =
   &default_varobj_ops,
   NULL,
   NULL,
+  f_is_string_type_p,
   "(...)"                      /* la_struct_too_deep_ellipsis */
 };
 
index b8617cb162daa8b32bd441f61c3528fd0fc0cfb2..6473468d4d96ba9a403d51a0bd2b0d458ea627dc 100644 (file)
@@ -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 */
 };
 
index da8dd1bf7ae4b2fc31c9a078a4a2ac6d39a90812..9d0eb03b4209848b4541efdc4f7c1a45eb4b5312 100644 (file)
@@ -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 */
 };
 
index 261f5a33cc75a53b076a9429a37814584a1abd22..e7446efa07f843b9132a6ccdb207c0704fe798dd 100644 (file)
@@ -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);
index 9f2a97d54fd04e97c05f6e5aa516f90ceef38823..6fe628978cf37b3e37c94186cbd0132f6e30263f 100644 (file)
@@ -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 */
 };
 
index af92e55a43765b3522bcb4b40b0fb5b7ca8bbbaf..b25a98106c1339791c82d046b5bc2370abf0e26d 100644 (file)
@@ -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 */
 };
 
index c95bf05a98b6e9e6c030fe5f517970f846bb1ee7..93d8e2f5dd3381b92fa70da05432c6888f02e960 100644 (file)
@@ -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 */
 };
 
index 0b85f70dfd212146524ad9af1267670552da9b80..9b9f19b69cf2a2586547564bcaceae8c1849cb4a 100644 (file)
@@ -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 */
 };
index 8faafd49cddc283854fe9d6be5175f2f0329b563..2fada465d651527d1c54fc99aa80f15df2063528 100644 (file)
@@ -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_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 */
 };