* [RFC] Extend gdb.parse_and_eval to accept a format string.
@ 2013-12-29 11:34 Siva Chandra
0 siblings, 0 replies; only message in thread
From: Siva Chandra @ 2013-12-29 11:34 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1555 bytes --]
Hi,
Attached is a patch which extends gdb.parse_and_eval to accept a
format string. The idea was roughly put down by Doug here:
https://sourceware.org/ml/gdb-patches/2013-12/msg00709.html
My patch does not do exactly the same as what Doug did in his example;
Instead of using %V, I used ${N} syntax. If the string argument to
gdb.parse_and_eval is a format string, then a variable number of args
of type gdb.Value can follow. The number of gdb.Value args to be
passed is determined by the format string. The Nth gdb.Value arg is
referenced by "${N}" in the format string. The value of N starts at 0.
I have not made any docs or NEWS changes as I am not sure if the idea
in the patch is acceptable at all. I have however added tests.
* parse.c (write_dollar_variable): Pass 0 for the "true_alias"
arg of create_internalvar.
* value.c (struct internalvar): New field "true_alias".
(create_internalvar): New arg 'true_alias'.
(create_internalvar_type_lazy): Pass 0 for the "true_alias" arg
of create_internalvar.
(value_of_internalvar): Do not set VALUE_LVAL to lval_internalvar
if "true_alias" field of internalvar is set.
* value.h (create_internalvar): Change prototype.
* python/python.c (get_python_internalvar_name): New function.
(validate_expression): New function.
(parse_args_for_parse_and_eval): New function.
(gdbpy_parse_and_eval): Use parse_args_for_parse_and_eval.
testsuite/
* gdb.python/py-value.exp: Add new tests.
[-- Attachment #2: parse_and_eval_patch_v1.txt --]
[-- Type: text/plain, Size: 9410 bytes --]
diff --git a/gdb/parse.c b/gdb/parse.c
index 4b9ca5d..14328a0 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -715,7 +715,7 @@ write_dollar_variable (struct stoken str)
/* Any other names are assumed to be debugger internal variables. */
write_exp_elt_opcode (OP_INTERNALVAR);
- write_exp_elt_intern (create_internalvar (copy_name (str) + 1));
+ write_exp_elt_intern (create_internalvar (copy_name (str) + 1, 0));
write_exp_elt_opcode (OP_INTERNALVAR);
return;
handle_last:
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 55bb6cf..9eb2f41 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -33,6 +33,7 @@
#include "readline/tilde.h"
#include "python.h"
#include "cli/cli-utils.h"
+#include "common/buffer.h"
#include <ctype.h>
@@ -41,6 +42,11 @@ static const char python_excp_none[] = "none";
static const char python_excp_full[] = "full";
static const char python_excp_message[] = "message";
+/* Prefix string to be used in names of internalvar objects when created for
+ expression evaluation via gdb.parse_and_eval(...). */
+
+static const char python_internalvar_prefix[] = "__python__internalvar__";
+
/* "set python print-stack" choices. */
static const char *const python_excp_enums[] =
{
@@ -717,21 +723,156 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
return return_result;
}
+static char *
+get_python_internalvar_name (int i)
+{
+ struct buffer name_buf;
+
+ buffer_init (&name_buf);
+ buffer_xml_printf (&name_buf, "%s%d", python_internalvar_prefix, i);
+ buffer_grow_str0 (&name_buf, "");
+
+ return buffer_finish (&name_buf);
+}
+
+static char *
+validate_expression (const char *pexpr, int argc)
+{
+ struct buffer expr_buf;
+ int i;
+ int pexpr_len = strlen (pexpr);
+
+ buffer_init (&expr_buf);
+ for (i = 0; i < pexpr_len - 3; i++)
+ {
+ if (pexpr[i] == '$' && pexpr[i + 1] == '{')
+ {
+ int j = i + 2;
+ struct buffer int_buf;
+ int val_n;
+ char *internalvar_name, *int_str;
+
+ buffer_init (&int_buf);
+ while (pexpr[j] != '}')
+ {
+ buffer_grow (&int_buf, &pexpr[j], 1);
+ j++;
+ if (j >= pexpr_len)
+ {
+ buffer_free (&expr_buf);
+ buffer_free (&int_buf);
+
+ return NULL;
+ }
+ }
+
+ buffer_grow_str0 (&int_buf, "");
+ int_str = buffer_finish (&int_buf);
+ val_n = atoi (int_str);
+ xfree (int_str);
+ if (val_n >= (argc - 1) || val_n < 0)
+ {
+ buffer_free (&expr_buf);
+
+ return NULL;
+ }
+
+ i = j;
+ internalvar_name = get_python_internalvar_name (val_n);
+ buffer_grow_str (&expr_buf, "$");
+ buffer_grow_str (&expr_buf, internalvar_name);
+ xfree (internalvar_name);
+ }
+ else
+ buffer_grow (&expr_buf, &pexpr[i], 1);
+ }
+ buffer_grow_str0 (&expr_buf, &pexpr[i]);
+
+ return buffer_finish (&expr_buf);
+}
+
+static char *
+parse_args_for_parse_and_eval (PyObject *args)
+{
+ LONGEST argc = PyTuple_GET_SIZE (args), i;
+ PyObject *format_string;
+ char *pexpr, *expr, *tmp;
+
+ if (argc == 0)
+ {
+ PyErr_SetString (PyExc_SyntaxError,
+ _("Insufficient number of arguments."));
+
+ return NULL;
+ }
+
+ format_string = PyTuple_GET_ITEM (args, 0);
+ if (!gdbpy_is_string (format_string))
+ {
+ PyErr_SetString (PyExc_TypeError, _("First argument is not a string."));
+
+ return NULL;
+ }
+ pexpr = python_string_to_host_string (format_string);
+ if (pexpr == NULL)
+ return NULL;
+
+ expr = validate_expression (pexpr, argc);
+ if (expr == NULL)
+ {
+ PyErr_SetString (PyExc_ValueError, _("Incorrect expression format."));
+
+ return NULL;
+ }
+
+ for (i = 1; i < argc; i++)
+ {
+ PyObject *value_obj = PyTuple_GET_ITEM (args, i);
+ struct value *v;
+ struct internalvar *var;
+ char *var_name;
+
+ if (!PyObject_TypeCheck (value_obj, &value_object_type))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("Arguments 1 and beyond are not gdb.Value "
+ "objects."));
+ xfree (expr);
+
+ return NULL;
+ }
+
+ var_name = get_python_internalvar_name (i - 1);
+ var = lookup_only_internalvar (var_name);
+ if (var == NULL)
+ var = create_internalvar (var_name, 1);
+ v = value_object_to_value (value_obj);
+ set_internalvar (var, v);
+
+ xfree (var_name);
+ }
+
+ return expr;
+}
+
/* Parse a string and evaluate it as an expression. */
static PyObject *
gdbpy_parse_and_eval (PyObject *self, PyObject *args)
{
- const char *expr_str;
+ char *expr_str;
struct value *result = NULL;
volatile struct gdb_exception except;
- if (!PyArg_ParseTuple (args, "s", &expr_str))
+ expr_str = parse_args_for_parse_and_eval (args);
+ if (expr_str == NULL)
return NULL;
TRY_CATCH (except, RETURN_MASK_ALL)
{
result = parse_and_eval (expr_str);
}
+
+ xfree (expr_str);
GDB_PY_HANDLE_EXCEPTION (except);
return value_to_value_object (result);
diff --git a/gdb/testsuite/gdb.python/py-value.exp b/gdb/testsuite/gdb.python/py-value.exp
index a052104..3ebe23b 100644
--- a/gdb/testsuite/gdb.python/py-value.exp
+++ b/gdb/testsuite/gdb.python/py-value.exp
@@ -467,6 +467,24 @@ proc test_parse_and_eval {} {
"parse_and_eval type test"
}
+# Few more tests of gdb.parse_and_eval. These tests require execution.
+proc test_parse_and_eval1 {} {
+ gdb_test_no_output "python a = gdb.parse_and_eval('a')" \
+ "test_parse_and_eval1: init a"
+ gdb_test "python print gdb.parse_and_eval('$\{0\}\[1\]', a)" "2" \
+ "test_parse_and_eval1: use subscript on $\{0\}"
+
+ gdb_test_no_output "python s = gdb.parse_and_eval('s')" \
+ "test_parse_and_eval1: init s"
+ gdb_test "python print gdb.parse_and_eval('$\{0\}.b', s)" "5" \
+ "test_parse_and_eval1: use '.' on $\{0\}"
+
+ gdb_test_no_output "python s_ptr = gdb.parse_and_eval('&s')" \
+ "test_parse_and_eval1: init s_ptr"
+ gdb_test "python print gdb.parse_and_eval('$\{0\}->a', s_ptr)" "3" \
+ "test_parse_and_eval1: use '->' on $\{0\}"
+}
+
# Test that values are hashable.
proc test_value_hash {} {
gdb_py_test_multiple "Simple Python value dictionary" \
@@ -509,6 +527,7 @@ if ![runto_main] then {
}
test_value_in_inferior
+test_parse_and_eval1
test_inferior_function_call
test_lazy_strings
test_value_after_death
diff --git a/gdb/value.c b/gdb/value.c
index 25c9f32..22589d6 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1780,6 +1780,15 @@ struct internalvar
struct internalvar *next;
char *name;
+ /* If the internal variable is of INTERNALVAR_VALUE kind (see below),
+ and is going to be used as a true alias for the underlying GDB
+ value, then this field is 1. It is 0 for all other cases. The
+ word 'true' is to imply that this internal variable will be used
+ exactly like the underlying GDB value (and not just a convenience
+ name for a GDB value). */
+
+ int true_alias;
+
/* We support various different kinds of content of an internal variable.
enum internalvar_kind specifies the kind, and union internalvar_data
provides the data associated with this particular kind. */
@@ -1925,15 +1934,19 @@ complete_internalvar (const char *name)
}
/* Create an internal variable with name NAME and with a void value.
- NAME should not normally include a dollar sign. */
+ NAME should not normally include a dollar sign. If the internal
+ variable is going to be set to INTERNALVAR_VALUE kind and is going
+ to be used as true alias for the GDB value it represents, then set
+ TRUE_ALIAS to 1. Set it to 0 otherwise. */
struct internalvar *
-create_internalvar (const char *name)
+create_internalvar (const char *name, int true_alias)
{
struct internalvar *var;
var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
var->name = concat (name, (char *)NULL);
+ var->true_alias = true_alias ? 1 : 0;
var->kind = INTERNALVAR_VOID;
var->next = internalvars;
internalvars = var;
@@ -1952,7 +1965,7 @@ create_internalvar_type_lazy (const char *name,
const struct internalvar_funcs *funcs,
void *data)
{
- struct internalvar *var = create_internalvar (name);
+ struct internalvar *var = create_internalvar (name, 0);
var->kind = INTERNALVAR_MAKE_VALUE;
var->u.make_value.functions = funcs;
@@ -1991,7 +2004,7 @@ lookup_internalvar (const char *name)
if (var)
return var;
- return create_internalvar (name);
+ return create_internalvar (name, 0);
}
/* Return current value of internal variable VAR. For variables that
@@ -2074,7 +2087,7 @@ value_of_internalvar (struct gdbarch *gdbarch, struct internalvar *var)
want. */
if (var->kind != INTERNALVAR_MAKE_VALUE
- && val->lval != lval_computed)
+ && val->lval != lval_computed && !var->true_alias)
{
VALUE_LVAL (val) = lval_internalvar;
VALUE_INTERNALVAR (val) = var;
diff --git a/gdb/value.h b/gdb/value.h
index 6b158df..67e403a 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -799,7 +799,8 @@ extern void set_internalvar_component (struct internalvar *var,
extern struct internalvar *lookup_only_internalvar (const char *name);
-extern struct internalvar *create_internalvar (const char *name);
+extern struct internalvar *create_internalvar (const char *name,
+ int true_alias);
extern VEC (char_ptr) *complete_internalvar (const char *name);
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2013-12-29 11:34 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-29 11:34 [RFC] Extend gdb.parse_and_eval to accept a format string Siva Chandra
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).