summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <pedro@palves.net>2021-07-15 10:47:56 +0100
committerPedro Alves <pedro@palves.net>2021-07-15 15:10:59 +0100
commit50991aaf22b03a9925ae37155f16bc8257f95242 (patch)
treedb0d641ebab1211d0f79c5dc00062c0708ad5b60
parent67ea24cb99efcd50d8acb6ce3e3ffbd8c97f0829 (diff)
downloadbinutils-gdb-users/palves/value_string.tar.gz
Change-Id: I79ef914087dbf85e1cbc19263843a6034383afe7
-rw-r--r--gdb/ada-lang.c10
-rw-r--r--gdb/c-lang.c12
-rw-r--r--gdb/cli/cli-cmds.c22
-rw-r--r--gdb/f-lang.c8
-rw-r--r--gdb/f-lang.h3
-rw-r--r--gdb/guile/scm-math.c8
-rw-r--r--gdb/language.c9
-rw-r--r--gdb/language.h7
-rw-r--r--gdb/python/py-value.c8
-rw-r--r--gdb/testsuite/gdb.base/internal-string-values.exp80
-rw-r--r--gdb/valops.c7
-rw-r--r--gdb/value.c5
-rw-r--r--gdb/value.h8
13 files changed, 152 insertions, 35 deletions
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index b098991612d..82319e49326 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -12900,6 +12900,16 @@ public:
return language_defn::read_var_value (var, var_block, frame);
}
+ struct value *value_string (struct gdbarch *gdbarch,
+ const char *ptr, ssize_t len) const override
+ {
+ struct type *type = language_string_char_type (this, gdbarch);
+ value *val = ::value_string (ptr, len, type);
+ /* See ada_string_operation::evaluate. */
+ value_type (val)->set_code (TYPE_CODE_ARRAY);
+ return val;
+ }
+
/* See language.h. */
void language_arch_info (struct gdbarch *gdbarch,
struct language_arch_info *lai) const override
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 98f4984b020..d30cebe9f0c 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -653,16 +653,11 @@ c_string_operation::evaluate (struct type *expect_type,
}
else
{
- int i;
-
- /* Write the terminating character. */
- for (i = 0; i < TYPE_LENGTH (type); ++i)
- obstack_1grow (&output, 0);
+ int element_size = TYPE_LENGTH (type);
if (satisfy_expected)
{
LONGEST low_bound, high_bound;
- int element_size = TYPE_LENGTH (type);
if (!get_discrete_bounds (expect_type->index_type (),
&low_bound, &high_bound))
@@ -677,10 +672,13 @@ c_string_operation::evaluate (struct type *expect_type,
result = allocate_value (expect_type);
memcpy (value_contents_raw (result), obstack_base (&output),
obstack_object_size (&output));
+ /* Write the terminating character. */
+ memset (value_contents_raw (result) + obstack_object_size (&output),
+ 0, element_size);
}
else
result = value_cstring ((const char *) obstack_base (&output),
- obstack_object_size (&output),
+ obstack_object_size (&output) / element_size,
type);
}
return result;
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index f6fc5ab854f..b445b75fae2 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -2146,12 +2146,10 @@ value_from_setting (const cmd_list_element *cmd, struct gdbarch *gdbarch)
case var_filename:
case var_enum:
if (*(char **) cmd->var)
- return value_cstring (*(char **) cmd->var,
- strlen (*(char **) cmd->var) + 1,
- builtin_type (gdbarch)->builtin_char);
+ return current_language->value_string (gdbarch, *(char **) cmd->var,
+ strlen (*(char **) cmd->var));
else
- return value_cstring ("", 1,
- builtin_type (gdbarch)->builtin_char);
+ return current_language->value_string (gdbarch, "", 0);
default:
gdb_assert_not_reached ("bad var_type");
}
@@ -2199,8 +2197,9 @@ str_value_from_setting (const cmd_list_element *cmd, struct gdbarch *gdbarch)
{
std::string cmd_val = get_setshow_command_value_string (cmd);
- return value_cstring (cmd_val.c_str (), cmd_val.size () + 1,
- builtin_type (gdbarch)->builtin_char);
+ return current_language->value_string (gdbarch,
+ cmd_val.data (),
+ cmd_val.size ());
}
case var_string:
@@ -2213,12 +2212,11 @@ str_value_from_setting (const cmd_list_element *cmd, struct gdbarch *gdbarch)
escaping quotes. So, we directly use the cmd->var string value,
similarly to the value_from_setting code for these cases. */
if (*(char **) cmd->var)
- return value_cstring (*(char **) cmd->var,
- strlen (*(char **) cmd->var) + 1,
- builtin_type (gdbarch)->builtin_char);
+ return current_language->value_string (gdbarch,
+ *(char **) cmd->var,
+ strlen (*(char **) cmd->var));
else
- return value_cstring ("", 1,
- builtin_type (gdbarch)->builtin_char);
+ return current_language->value_string (gdbarch, "", 0);
default:
gdb_assert_not_reached ("bad var_type");
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 16ec9e04044..869a95d4304 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -103,6 +103,14 @@ f_language::get_encoding (struct type *type)
+struct value *
+f_language::value_string (struct gdbarch *gdbarch,
+ const char *ptr, ssize_t len) const
+{
+ struct type *type = language_string_char_type (this, gdbarch);
+ return ::value_string (ptr, len, type);
+}
+
/* A helper function for the "bound" intrinsics that checks that TYPE
is an array. LBOUND_P is true for lower bound; this is used for
the error message, if any. */
diff --git a/gdb/f-lang.h b/gdb/f-lang.h
index 1ccdd3978ea..1306b135779 100644
--- a/gdb/f-lang.h
+++ b/gdb/f-lang.h
@@ -193,6 +193,9 @@ public:
&& TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_CHAR));
}
+ struct value *value_string (struct gdbarch *gdbarch,
+ const char *ptr, ssize_t len) const override;
+
/* See language.h. */
const char *struct_too_deep_ellipsis () const override
diff --git a/gdb/guile/scm-math.c b/gdb/guile/scm-math.c
index 8b7fe9b69ec..a88c805fc23 100644
--- a/gdb/guile/scm-math.c
+++ b/gdb/guile/scm-math.c
@@ -776,6 +776,8 @@ vlscm_convert_typed_value_from_scheme (const char *func_name,
}
else if (scm_is_string (obj))
{
+ size_t len;
+
if (type != NULL)
{
except_scm = gdbscm_make_misc_error (func_name, type_arg_pos,
@@ -787,14 +789,12 @@ vlscm_convert_typed_value_from_scheme (const char *func_name,
{
/* TODO: Provide option to specify conversion strategy. */
gdb::unique_xmalloc_ptr<char> s
- = gdbscm_scm_to_string (obj, nullptr,
+ = gdbscm_scm_to_string (obj, &len,
target_charset (gdbarch),
0 /*non-strict*/,
&except_scm);
if (s != NULL)
- value = value_cstring (s.get (), strlen (s.get ()) + 1,
- language_string_char_type (language,
- gdbarch));
+ value = language->value_string (gdbarch, s.get (), len);
else
value = NULL;
}
diff --git a/gdb/language.c b/gdb/language.c
index 0d1e3848de8..2ee32a1edff 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -47,6 +47,7 @@
#include <algorithm>
#include "gdbarch.h"
#include "compile/compile-internal.h"
+#include "arch-utils.h"
static void set_range_case (void);
@@ -976,6 +977,14 @@ language_string_char_type (const struct language_defn *la,
return ld->arch_info[la->la_language].string_char_type ();
}
+struct value *
+language_defn::value_string (struct gdbarch *gdbarch,
+ const char *ptr, ssize_t len) const
+{
+ struct type *type = language_string_char_type (this, gdbarch);
+ return value_cstring (ptr, len, type);
+}
+
/* See language.h. */
struct type *
diff --git a/gdb/language.h b/gdb/language.h
index 21ed47b3580..87064962b9b 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -579,6 +579,13 @@ struct language_defn
virtual char string_lower_bound () const
{ return c_style_arrays_p () ? 0 : 1; }
+ /* Return the LEN characters long string at STR as a value as
+ represented in this language. GDBARCH is used to infer the
+ character type. The default implementation returns a
+ null-terminated C string. */
+ virtual struct value *value_string (struct gdbarch *gdbarch,
+ const char *ptr, ssize_t len) const;
+
/* Returns true if the symbols names should be stored in GDB's data
structures for minimal/partial/full symbols using their linkage (aka
mangled) form; false if the symbol names should be demangled first.
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index bc0f88b7a16..f5b72446912 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -50,9 +50,6 @@
#define builtin_type_pybool \
language_bool_type (python_language, python_gdbarch)
-#define builtin_type_pychar \
- language_string_char_type (python_language, python_gdbarch)
-
struct value_object {
PyObject_HEAD
struct value_object *next;
@@ -1907,8 +1904,9 @@ convert_value_from_python (PyObject *obj)
gdb::unique_xmalloc_ptr<char> s
= python_string_to_target_string (obj);
if (s != NULL)
- value = value_cstring (s.get (), strlen (s.get ()) + 1,
- builtin_type_pychar);
+ value = python_language->value_string (python_gdbarch,
+ s.get (),
+ strlen (s.get ()));
}
else if (PyObject_TypeCheck (obj, &value_object_type))
value = value_copy (((value_object *) obj)->value);
diff --git a/gdb/testsuite/gdb.base/internal-string-values.exp b/gdb/testsuite/gdb.base/internal-string-values.exp
index 0748ab0984c..3380d9d8077 100644
--- a/gdb/testsuite/gdb.base/internal-string-values.exp
+++ b/gdb/testsuite/gdb.base/internal-string-values.exp
@@ -118,6 +118,86 @@ proc_with_prefix test_setting { } {
gdb_test_no_output {set $v = $_gdb_setting_str("remotetimeout")}
check_v_string "2"
}
+
+ # Test string values made by $_gdb_setting & co. in all languages.
+ with_test_prefix "all langs" {
+ # Get list of supported languages.
+ set langs {}
+ gdb_test_multiple "complete set language " "" {
+ -re "set language (\[^\r\n\]+)" {
+ lappend langs $expect_out(1,string)
+ exp_continue
+ }
+ -re "$::gdb_prompt $" {
+ pass $gdb_test_name
+ }
+ }
+
+ proc quote {str} {
+ upvar lang lang
+
+ if {$lang == "fortran"} {
+ return "'$str'"
+ } else {
+ return "\"$str\""
+ }
+ }
+
+ gdb_test "maintenance set test-settings string foo"
+ foreach_with_prefix lang $langs {
+ gdb_test_no_output "set language $lang"
+
+ if {$lang == "modula-2"} {
+ gdb_test "print \"foo\"" "strings are not implemented"
+ continue
+ }
+
+ if {$lang == "rust"} {
+ gdb_test "print \"foo\"" \
+ "evaluation of this expression requires the target program to be active"
+
+ # We could get the above working by starting the
+ # program, but how to make the below work?
+ gdb_test "print \$_gdb_maint_setting(\"test-settings string\")" \
+ "',' or '\\)' expected"
+ continue
+ }
+
+ if {$lang == "unknown"} {
+ # Skipped because of PR gdb/28093 -- GDB would crash.
+ continue
+ }
+
+ set print_output ""
+ set ptype_output ""
+
+ set foo_str [quote foo]
+ gdb_test_multiple "print $foo_str" "" {
+ -wrap -re " = (.*)" {
+ set print_output $expect_out(1,string)
+ pass $gdb_test_name
+ }
+ }
+
+ gdb_test_multiple "ptype $foo_str" "" {
+ -wrap -re " = (.*)" {
+ set ptype_output $expect_out(1,string)
+ pass $gdb_test_name
+ }
+ }
+
+ set cmd_str [quote "test-settings string"]
+ set ptype_output_re [string_to_regexp $ptype_output]
+ set print_output_re [string_to_regexp $print_output]
+
+ foreach_with_prefix conv_func {$_gdb_maint_setting $_gdb_maint_setting_str} {
+ gdb_test "print ${conv_func}($cmd_str)" \
+ " = $print_output_re"
+ gdb_test "ptype \$" \
+ " = $ptype_output_re"
+ }
+ }
+ }
}
# Test with a string value created by gdb.Value in Python.
diff --git a/gdb/valops.c b/gdb/valops.c
index f67612e87b0..161b8696cb2 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1754,12 +1754,15 @@ value_cstring (const char *ptr, ssize_t len, struct type *char_type)
{
struct value *val;
int lowbound = current_language->string_lower_bound ();
- ssize_t highbound = len / TYPE_LENGTH (char_type);
+ ssize_t highbound = len + 1;
struct type *stringtype
= lookup_array_range_type (char_type, lowbound, highbound + lowbound - 1);
val = allocate_value (stringtype);
- memcpy (value_contents_raw (val), ptr, len);
+ memcpy (value_contents_raw (val), ptr, len * TYPE_LENGTH (char_type));
+ /* Write the terminating character. */
+ memset (value_contents_raw (val) + len * TYPE_LENGTH (char_type),
+ 0, TYPE_LENGTH (char_type));
return val;
}
diff --git a/gdb/value.c b/gdb/value.c
index db34d2e5762..092325c8731 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2188,8 +2188,9 @@ value_of_internalvar (struct gdbarch *gdbarch, struct internalvar *var)
break;
case INTERNALVAR_STRING:
- val = value_cstring (var->u.string, strlen (var->u.string) + 1,
- builtin_type (gdbarch)->builtin_char);
+ val = current_language->value_string (gdbarch,
+ var->u.string,
+ strlen (var->u.string));
break;
case INTERNALVAR_VALUE:
diff --git a/gdb/value.h b/gdb/value.h
index 24392437ed0..3313b9fd346 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -782,10 +782,12 @@ class scoped_value_mark
const struct value *m_value;
};
-/* Create a not_lval value with type TYPE_CODE_ARRAY.
+/* Create not_lval value representing a NULL-terminated C string. The
+ resulting value has type TYPE_CODE_ARRAY.
- PTR points to the string data; LEN is the length of the string including the
- NULL terminator. */
+ PTR points to the string data; LEN is number of characters (does
+ not include the NULL terminator). CHAR_TYPE is the character
+ type. */
extern struct value *value_cstring (const char *ptr, ssize_t len,
struct type *char_type);