aboutsummaryrefslogtreecommitdiff
path: root/gdb/python/py-param.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/python/py-param.c')
-rw-r--r--gdb/python/py-param.c296
1 files changed, 185 insertions, 111 deletions
diff --git a/gdb/python/py-param.c b/gdb/python/py-param.c
index 2771bf4..a1bd4e0 100644
--- a/gdb/python/py-param.c
+++ b/gdb/python/py-param.c
@@ -28,24 +28,70 @@
#include "language.h"
#include "arch-utils.h"
+/* Python parameter types as in PARM_CONSTANTS below. */
+
+enum param_types
+{
+ param_boolean,
+ param_auto_boolean,
+ param_uinteger,
+ param_integer,
+ param_string,
+ param_string_noescape,
+ param_optional_filename,
+ param_filename,
+ param_zinteger,
+ param_zuinteger,
+ param_zuinteger_unlimited,
+ param_enum,
+}
+param_types;
+
+/* Translation from Python parameters to GDB variable types. Keep in the
+ same order as PARAM_TYPES due to C++'s lack of designated initializers. */
+
+static const struct
+{
+ /* The type of the parameter. */
+ enum var_types type;
+
+ /* Extra literals, such as `unlimited', accepted in lieu of a number. */
+ const literal_def *extra_literals;
+}
+param_to_var[] =
+{
+ { var_boolean },
+ { var_auto_boolean },
+ { var_uinteger, uinteger_unlimited_literals },
+ { var_integer, integer_unlimited_literals },
+ { var_string },
+ { var_string_noescape },
+ { var_optional_filename },
+ { var_filename },
+ { var_integer },
+ { var_uinteger },
+ { var_pinteger, pinteger_unlimited_literals },
+ { var_enum }
+};
+
/* Parameter constants and their values. */
static struct {
const char *name;
int value;
} parm_constants[] =
{
- { "PARAM_BOOLEAN", var_boolean }, /* ARI: var_boolean */
- { "PARAM_AUTO_BOOLEAN", var_auto_boolean },
- { "PARAM_UINTEGER", var_uinteger },
- { "PARAM_INTEGER", var_integer },
- { "PARAM_STRING", var_string },
- { "PARAM_STRING_NOESCAPE", var_string_noescape },
- { "PARAM_OPTIONAL_FILENAME", var_optional_filename },
- { "PARAM_FILENAME", var_filename },
- { "PARAM_ZINTEGER", var_zinteger },
- { "PARAM_ZUINTEGER", var_zuinteger },
- { "PARAM_ZUINTEGER_UNLIMITED", var_zuinteger_unlimited },
- { "PARAM_ENUM", var_enum },
+ { "PARAM_BOOLEAN", param_boolean }, /* ARI: param_boolean */
+ { "PARAM_AUTO_BOOLEAN", param_auto_boolean },
+ { "PARAM_UINTEGER", param_uinteger },
+ { "PARAM_INTEGER", param_integer },
+ { "PARAM_STRING", param_string },
+ { "PARAM_STRING_NOESCAPE", param_string_noescape },
+ { "PARAM_OPTIONAL_FILENAME", param_optional_filename },
+ { "PARAM_FILENAME", param_filename },
+ { "PARAM_ZINTEGER", param_zinteger },
+ { "PARAM_ZUINTEGER", param_zuinteger },
+ { "PARAM_ZUINTEGER_UNLIMITED", param_zuinteger_unlimited },
+ { "PARAM_ENUM", param_enum },
{ NULL, 0 }
};
@@ -80,6 +126,9 @@ struct parmpy_object
/* The type of the parameter. */
enum var_types type;
+ /* Extra literals, such as `unlimited', accepted in lieu of a number. */
+ const literal_def *extra_literals;
+
/* The value of the parameter. */
union parmpy_variable value;
@@ -96,18 +145,20 @@ struct parmpy_object
static setting
make_setting (parmpy_object *s)
{
- if (var_type_uses<bool> (s->type))
- return setting (s->type, &s->value.boolval);
- else if (var_type_uses<int> (s->type))
- return setting (s->type, &s->value.intval);
- else if (var_type_uses<auto_boolean> (s->type))
- return setting (s->type, &s->value.autoboolval);
- else if (var_type_uses<unsigned int> (s->type))
- return setting (s->type, &s->value.uintval);
- else if (var_type_uses<std::string> (s->type))
- return setting (s->type, s->value.stringval);
- else if (var_type_uses<const char *> (s->type))
- return setting (s->type, &s->value.cstringval);
+ enum var_types type = s->type;
+
+ if (var_type_uses<bool> (type))
+ return setting (type, &s->value.boolval);
+ else if (var_type_uses<int> (type))
+ return setting (type, &s->value.intval, s->extra_literals);
+ else if (var_type_uses<auto_boolean> (type))
+ return setting (type, &s->value.autoboolval);
+ else if (var_type_uses<unsigned int> (type))
+ return setting (type, &s->value.uintval, s->extra_literals);
+ else if (var_type_uses<std::string> (type))
+ return setting (type, s->value.stringval);
+ else if (var_type_uses<const char *> (type))
+ return setting (type, &s->value.cstringval);
else
gdb_assert_not_reached ("unhandled var type");
}
@@ -234,68 +285,98 @@ set_parameter_value (parmpy_object *self, PyObject *value)
}
break;
- case var_integer:
- case var_zinteger:
case var_uinteger:
- case var_zuinteger:
- case var_zuinteger_unlimited:
+ case var_integer:
+ case var_pinteger:
{
- long l;
- int ok;
-
- if (value == Py_None
- && (self->type == var_uinteger || self->type == var_integer))
- l = 0;
- else if (value == Py_None && self->type == var_zuinteger_unlimited)
- l = -1;
- else if (!PyLong_Check (value))
+ const literal_def *extra_literals = self->extra_literals;
+ enum tribool allowed = TRIBOOL_UNKNOWN;
+ enum var_types var_type = self->type;
+ std::string buffer = "";
+ size_t count = 0;
+ LONGEST val;
+
+ if (extra_literals != nullptr)
{
- PyErr_SetString (PyExc_RuntimeError,
- _("The value must be integer."));
- return -1;
+ gdb::unique_xmalloc_ptr<char>
+ str (python_string_to_host_string (value));
+ const char *s = str != nullptr ? str.get () : nullptr;
+ PyErr_Clear ();
+
+ for (const literal_def *l = extra_literals;
+ l->literal != nullptr;
+ l++, count++)
+ {
+ if (count != 0)
+ buffer += ", ";
+ buffer = buffer + "'" + l->literal + "'";
+ if (allowed == TRIBOOL_UNKNOWN
+ && ((value == Py_None && !strcmp ("unlimited", l->literal))
+ || (s != nullptr && !strcmp (s, l->literal))))
+ {
+ val = l->use;
+ allowed = TRIBOOL_TRUE;
+ }
+ }
}
- else if (! gdb_py_int_as_long (value, &l))
- return -1;
- switch (self->type)
+ if (allowed == TRIBOOL_UNKNOWN)
{
- case var_uinteger:
- if (l == 0)
- l = UINT_MAX;
- /* Fall through. */
- case var_zuinteger:
- ok = (l >= 0 && l <= UINT_MAX);
- break;
-
- case var_zuinteger_unlimited:
- ok = (l >= -1 && l <= INT_MAX);
- break;
-
- case var_integer:
- ok = (l >= INT_MIN && l <= INT_MAX);
- if (l == 0)
- l = INT_MAX;
- break;
-
- case var_zinteger:
- ok = (l >= INT_MIN && l <= INT_MAX);
- break;
-
- default:
- gdb_assert_not_reached ("unknown var_ constant");
+ val = PyLong_AsLongLong (value);
+
+ if (PyErr_Occurred ())
+ {
+ if (extra_literals == nullptr)
+ PyErr_SetString (PyExc_RuntimeError,
+ _("The value must be integer."));
+ else if (count > 1)
+ PyErr_SetString (PyExc_RuntimeError,
+ string_printf (_("integer or one of: %s"),
+ buffer.c_str ()).c_str ());
+ else
+ PyErr_SetString (PyExc_RuntimeError,
+ string_printf (_("integer or %s"),
+ buffer.c_str ()).c_str ());
+ return -1;
+ }
+
+
+ if (extra_literals != nullptr)
+ for (const literal_def *l = extra_literals;
+ l->literal != nullptr;
+ l++)
+ {
+ if (l->val.has_value () && val == *l->val)
+ {
+ allowed = TRIBOOL_TRUE;
+ val = l->use;
+ break;
+ }
+ else if (val == l->use)
+ allowed = TRIBOOL_FALSE;
+ }
+ }
+
+ if (allowed == TRIBOOL_UNKNOWN)
+ {
+ if (val > UINT_MAX || val < INT_MIN
+ || (var_type == var_uinteger && val < 0)
+ || (var_type == var_integer && val > INT_MAX)
+ || (var_type == var_pinteger && val < 0)
+ || (var_type == var_pinteger && val > INT_MAX))
+ allowed = TRIBOOL_FALSE;
}
-
- if (! ok)
+ if (allowed == TRIBOOL_FALSE)
{
PyErr_SetString (PyExc_RuntimeError,
_("Range exceeded."));
return -1;
}
- if (self->type == var_uinteger || self->type == var_zuinteger)
- self->value.uintval = (unsigned) l;
+ if (self->type == var_uinteger)
+ self->value.uintval = (unsigned) val;
else
- self->value.intval = (int) l;
+ self->value.intval = (int) val;
break;
}
@@ -534,7 +615,8 @@ get_show_value (struct ui_file *file, int from_tty,
/* A helper function that dispatches to the appropriate add_setshow
function. */
static void
-add_setshow_generic (int parmclass, enum command_class cmdclass,
+add_setshow_generic (enum var_types type, const literal_def *extra_literals,
+ enum command_class cmdclass,
gdb::unique_xmalloc_ptr<char> cmd_name,
parmpy_object *self,
const char *set_doc, const char *show_doc,
@@ -544,7 +626,7 @@ add_setshow_generic (int parmclass, enum command_class cmdclass,
{
set_show_commands commands;
- switch (parmclass)
+ switch (type)
{
case var_boolean:
commands = add_setshow_boolean_cmd (cmd_name.get (), cmdclass,
@@ -564,18 +646,28 @@ add_setshow_generic (int parmclass, enum command_class cmdclass,
case var_uinteger:
commands = add_setshow_uinteger_cmd (cmd_name.get (), cmdclass,
- &self->value.uintval, set_doc,
+ &self->value.uintval,
+ extra_literals, set_doc,
show_doc, help_doc, get_set_value,
get_show_value, set_list, show_list);
break;
case var_integer:
commands = add_setshow_integer_cmd (cmd_name.get (), cmdclass,
- &self->value.intval, set_doc,
+ &self->value.intval,
+ extra_literals, set_doc,
show_doc, help_doc, get_set_value,
get_show_value, set_list, show_list);
break;
+ case var_pinteger:
+ commands = add_setshow_pinteger_cmd (cmd_name.get (), cmdclass,
+ &self->value.intval,
+ extra_literals, set_doc,
+ show_doc, help_doc, get_set_value,
+ get_show_value, set_list, show_list);
+ break;
+
case var_string:
commands = add_setshow_string_cmd (cmd_name.get (), cmdclass,
self->value.stringval, set_doc,
@@ -607,30 +699,6 @@ add_setshow_generic (int parmclass, enum command_class cmdclass,
get_show_value, set_list, show_list);
break;
- case var_zinteger:
- commands = add_setshow_zinteger_cmd (cmd_name.get (), cmdclass,
- &self->value.intval, set_doc,
- show_doc, help_doc, get_set_value,
- get_show_value, set_list, show_list);
- break;
-
- case var_zuinteger:
- commands = add_setshow_zuinteger_cmd (cmd_name.get (), cmdclass,
- &self->value.uintval, set_doc,
- show_doc, help_doc, get_set_value,
- get_show_value, set_list,
- show_list);
- break;
-
- case var_zuinteger_unlimited:
- commands = add_setshow_zuinteger_unlimited_cmd (cmd_name.get (), cmdclass,
- &self->value.intval,
- set_doc, show_doc,
- help_doc, get_set_value,
- get_show_value, set_list,
- show_list);
- break;
-
case var_enum:
/* Initialize the value, just in case. */
self->value.cstringval = self->enumeration[0];
@@ -740,6 +808,8 @@ parmpy_init (PyObject *self, PyObject *args, PyObject *kwds)
int parmclass, cmdtype;
PyObject *enum_values = NULL;
struct cmd_list_element **set_list, **show_list;
+ const literal_def *extra_literals;
+ enum var_types type;
if (! PyArg_ParseTuple (args, "sii|O", &name, &cmdtype, &parmclass,
&enum_values))
@@ -756,33 +826,36 @@ parmpy_init (PyObject *self, PyObject *args, PyObject *kwds)
return -1;
}
- if (parmclass != var_boolean /* ARI: var_boolean */
- && parmclass != var_auto_boolean
- && parmclass != var_uinteger && parmclass != var_integer
- && parmclass != var_string && parmclass != var_string_noescape
- && parmclass != var_optional_filename && parmclass != var_filename
- && parmclass != var_zinteger && parmclass != var_zuinteger
- && parmclass != var_zuinteger_unlimited && parmclass != var_enum)
+ if (parmclass != param_boolean /* ARI: param_boolean */
+ && parmclass != param_auto_boolean
+ && parmclass != param_uinteger && parmclass != param_integer
+ && parmclass != param_string && parmclass != param_string_noescape
+ && parmclass != param_optional_filename && parmclass != param_filename
+ && parmclass != param_zinteger && parmclass != param_zuinteger
+ && parmclass != param_zuinteger_unlimited && parmclass != param_enum)
{
PyErr_SetString (PyExc_RuntimeError,
_("Invalid parameter class argument."));
return -1;
}
- if (enum_values && parmclass != var_enum)
+ if (enum_values && parmclass != param_enum)
{
PyErr_SetString (PyExc_RuntimeError,
_("Only PARAM_ENUM accepts a fourth argument."));
return -1;
}
- if (parmclass == var_enum)
+ if (parmclass == param_enum)
{
if (! compute_enum_values (obj, enum_values))
return -1;
}
else
obj->enumeration = NULL;
- obj->type = (enum var_types) parmclass;
+ type = param_to_var[parmclass].type;
+ extra_literals = param_to_var[parmclass].extra_literals;
+ obj->type = type;
+ obj->extra_literals = extra_literals;
memset (&obj->value, 0, sizeof (obj->value));
if (var_type_uses<std::string> (obj->type))
@@ -805,7 +878,8 @@ parmpy_init (PyObject *self, PyObject *args, PyObject *kwds)
try
{
- add_setshow_generic (parmclass, (enum command_class) cmdtype,
+ add_setshow_generic (type, extra_literals,
+ (enum command_class) cmdtype,
std::move (cmd_name), obj,
set_doc.get (), show_doc.get (),
doc.get (), set_list, show_list);