aboutsummaryrefslogtreecommitdiff
path: root/gdb/python/py-mi.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/python/py-mi.c')
-rw-r--r--gdb/python/py-mi.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/gdb/python/py-mi.c b/gdb/python/py-mi.c
index 66dc6fb..36bcb6c 100644
--- a/gdb/python/py-mi.c
+++ b/gdb/python/py-mi.c
@@ -296,3 +296,162 @@ gdbpy_execute_mi_command (PyObject *self, PyObject *args, PyObject *kw)
return uiout.result ();
}
+
+/* Convert KEY_OBJ into a string that can be used as a field name in MI
+ output. KEY_OBJ must be a Python string object, and must only contain
+ characters suitable for use as an MI field name.
+
+ If KEY_OBJ is not a string, or if KEY_OBJ contains invalid characters,
+ then an error is thrown. Otherwise, KEY_OBJ is converted to a string
+ and returned. */
+
+static gdb::unique_xmalloc_ptr<char>
+py_object_to_mi_key (PyObject *key_obj)
+{
+ /* The key must be a string. */
+ if (!PyUnicode_Check (key_obj))
+ {
+ gdbpy_ref<> key_repr (PyObject_Repr (key_obj));
+ gdb::unique_xmalloc_ptr<char> key_repr_string;
+ if (key_repr != nullptr)
+ key_repr_string = python_string_to_target_string (key_repr.get ());
+ if (key_repr_string == nullptr)
+ gdbpy_handle_exception ();
+
+ gdbpy_error (_("non-string object used as key: %s"),
+ key_repr_string.get ());
+ }
+
+ gdb::unique_xmalloc_ptr<char> key_string
+ = python_string_to_target_string (key_obj);
+ if (key_string == nullptr)
+ gdbpy_handle_exception ();
+
+ /* Predicate function, returns true if NAME is a valid field name for use
+ in MI result output, otherwise, returns false. */
+ auto is_valid_key_name = [] (const char *name) -> bool
+ {
+ gdb_assert (name != nullptr);
+
+ if (*name == '\0' || !isalpha (*name))
+ return false;
+
+ for (; *name != '\0'; ++name)
+ if (!isalnum (*name) && *name != '_' && *name != '-')
+ return false;
+
+ return true;
+ };
+
+ if (!is_valid_key_name (key_string.get ()))
+ {
+ if (*key_string.get () == '\0')
+ gdbpy_error (_("Invalid empty key in MI result"));
+ else
+ gdbpy_error (_("Invalid key in MI result: %s"), key_string.get ());
+ }
+
+ return key_string;
+}
+
+/* Serialize RESULT and print it in MI format to the current_uiout.
+ FIELD_NAME is used as the name of this result field.
+
+ RESULT can be a dictionary, a sequence, an iterator, or an object that
+ can be converted to a string, these are converted to the matching MI
+ output format (dictionaries as tuples, sequences and iterators as lists,
+ and strings as named fields).
+
+ If anything goes wrong while formatting the output then an error is
+ thrown.
+
+ This function is the recursive inner core of serialize_mi_result, and
+ should only be called from that function. */
+
+static void
+serialize_mi_result_1 (PyObject *result, const char *field_name)
+{
+ struct ui_out *uiout = current_uiout;
+
+ if (PyDict_Check (result))
+ {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ ui_out_emit_tuple tuple_emitter (uiout, field_name);
+ while (PyDict_Next (result, &pos, &key, &value))
+ {
+ gdb::unique_xmalloc_ptr<char> key_string
+ (py_object_to_mi_key (key));
+ serialize_mi_result_1 (value, key_string.get ());
+ }
+ }
+ else if (PySequence_Check (result) && !PyUnicode_Check (result))
+ {
+ ui_out_emit_list list_emitter (uiout, field_name);
+ Py_ssize_t len = PySequence_Size (result);
+ if (len == -1)
+ gdbpy_handle_exception ();
+ for (Py_ssize_t i = 0; i < len; ++i)
+ {
+ gdbpy_ref<> item (PySequence_ITEM (result, i));
+ if (item == nullptr)
+ gdbpy_handle_exception ();
+ serialize_mi_result_1 (item.get (), nullptr);
+ }
+ }
+ else if (PyIter_Check (result))
+ {
+ gdbpy_ref<> item;
+ ui_out_emit_list list_emitter (uiout, field_name);
+ while (true)
+ {
+ item.reset (PyIter_Next (result));
+ if (item == nullptr)
+ {
+ if (PyErr_Occurred () != nullptr)
+ gdbpy_handle_exception ();
+ break;
+ }
+ serialize_mi_result_1 (item.get (), nullptr);
+ }
+ }
+ else
+ {
+ if (PyLong_Check (result))
+ {
+ int overflow = 0;
+ gdb_py_longest val = gdb_py_long_as_long_and_overflow (result,
+ &overflow);
+ if (PyErr_Occurred () != nullptr)
+ gdbpy_handle_exception ();
+ if (overflow == 0)
+ {
+ uiout->field_signed (field_name, val);
+ return;
+ }
+ /* Fall through to the string case on overflow. */
+ }
+
+ gdb::unique_xmalloc_ptr<char> string (gdbpy_obj_to_string (result));
+ if (string == nullptr)
+ gdbpy_handle_exception ();
+ uiout->field_string (field_name, string.get ());
+ }
+}
+
+/* See python-internal.h. */
+
+void
+serialize_mi_results (PyObject *results)
+{
+ gdb_assert (PyDict_Check (results));
+
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next (results, &pos, &key, &value))
+ {
+ gdb::unique_xmalloc_ptr<char> key_string
+ (py_object_to_mi_key (key));
+ serialize_mi_result_1 (value, key_string.get ());
+ }
+}