diff options
Diffstat (limited to 'gdb/python/py-param.c')
-rw-r--r-- | gdb/python/py-param.c | 296 |
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); |