if (PyObject_HasAttrString (py_bp, stop_func))
{
- gdbpy_ref<> result (PyObject_CallMethod (py_bp, stop_func, NULL));
+ gdbpy_ref<> result (gdbpy_call_method (py_bp, stop_func));
stop = 1;
if (result != NULL)
/* Now call the DisassembleInfo.read_memory method. This might have been
overridden by the user. */
- gdbpy_ref<> result_obj (PyObject_CallMethod ((PyObject *) obj,
- "read_memory",
- "I" GDB_PY_LL_ARG, len, offset));
+ gdbpy_ref<> result_obj (gdbpy_call_method ((PyObject *) obj, "read_memory",
+ len, offset));
/* Handle any exceptions. */
if (result_obj == nullptr)
if (bpfinish_obj->py_bp.bp->enable_state == bp_enabled
&& PyObject_HasAttrString (py_obj, outofscope_func))
{
- gdbpy_ref<> meth_result (PyObject_CallMethod (py_obj, outofscope_func,
- NULL));
+ gdbpy_ref<> meth_result (gdbpy_call_method (py_obj, outofscope_func));
if (meth_result == NULL)
gdbpy_print_stack ();
}
struct symbol **sym, const struct block **sym_block,
const struct language_defn **language)
{
- gdbpy_ref<> result (PyObject_CallMethod (obj, "symbol", NULL));
+ gdbpy_ref<> result (gdbpy_call_method (obj, "symbol"));
if (result == NULL)
return EXT_LANG_BT_ERROR;
{
if (PyObject_HasAttrString (obj, "value"))
{
- gdbpy_ref<> vresult (PyObject_CallMethod (obj, "value", NULL));
+ gdbpy_ref<> vresult (gdbpy_call_method (obj, "value"));
if (vresult == NULL)
return EXT_LANG_BT_ERROR;
{
if (PyObject_HasAttrString (filter, func))
{
- gdbpy_ref<> result (PyObject_CallMethod (filter, func, NULL));
+ gdbpy_ref<> result (gdbpy_call_method (filter, func));
if (result != NULL)
{
/* Get the underlying frame. This is needed to determine GDB
architecture, and also, in the cases of frame variables/arguments to
read them if they returned filter object requires us to do so. */
- gdbpy_ref<> py_inf_frame (PyObject_CallMethod (filter, "inferior_frame",
- NULL));
+ gdbpy_ref<> py_inf_frame (gdbpy_call_method (filter, "inferior_frame"));
if (py_inf_frame == NULL)
return EXT_LANG_BT_ERROR;
address printing. */
if (PyObject_HasAttrString (filter, "address"))
{
- gdbpy_ref<> paddr (PyObject_CallMethod (filter, "address", NULL));
+ gdbpy_ref<> paddr (gdbpy_call_method (filter, "address"));
if (paddr == NULL)
return EXT_LANG_BT_ERROR;
/* Print frame function name. */
if (PyObject_HasAttrString (filter, "function"))
{
- gdbpy_ref<> py_func (PyObject_CallMethod (filter, "function", NULL));
+ gdbpy_ref<> py_func (gdbpy_call_method (filter, "function"));
const char *function = NULL;
if (py_func == NULL)
if (PyObject_HasAttrString (filter, "filename"))
{
- gdbpy_ref<> py_fn (PyObject_CallMethod (filter, "filename", NULL));
+ gdbpy_ref<> py_fn (gdbpy_call_method (filter, "filename"));
if (py_fn == NULL)
return EXT_LANG_BT_ERROR;
if (PyObject_HasAttrString (filter, "line"))
{
- gdbpy_ref<> py_line (PyObject_CallMethod (filter, "line", NULL));
+ gdbpy_ref<> py_line (gdbpy_call_method (filter, "line"));
int line;
if (py_line == NULL)
if (m_window != nullptr
&& PyObject_HasAttrString (m_window.get (), "close"))
{
- gdbpy_ref<> result (PyObject_CallMethod (m_window.get (), "close",
- nullptr));
+ gdbpy_ref<> result (gdbpy_call_method (m_window.get (), "close"));
if (result == nullptr)
gdbpy_print_stack ();
}
if (PyObject_HasAttrString (m_window.get (), "render"))
{
- gdbpy_ref<> result (PyObject_CallMethod (m_window.get (), "render",
- nullptr));
+ gdbpy_ref<> result (gdbpy_call_method (m_window.get (), "render"));
if (result == nullptr)
gdbpy_print_stack ();
}
if (PyObject_HasAttrString (m_window.get (), "hscroll"))
{
- gdbpy_ref<> result (PyObject_CallMethod (m_window.get(), "hscroll",
- "i", num_to_scroll, nullptr));
+ gdbpy_ref<> result (gdbpy_call_method (m_window.get (), "hscroll",
+ num_to_scroll));
if (result == nullptr)
gdbpy_print_stack ();
}
if (PyObject_HasAttrString (m_window.get (), "vscroll"))
{
- gdbpy_ref<> result (PyObject_CallMethod (m_window.get (), "vscroll",
- "i", num_to_scroll, nullptr));
+ gdbpy_ref<> result (gdbpy_call_method (m_window.get (), "vscroll",
+ num_to_scroll));
if (result == nullptr)
gdbpy_print_stack ();
}
if (PyObject_HasAttrString (m_window.get (), "click"))
{
- gdbpy_ref<> result (PyObject_CallMethod (m_window.get (), "click",
- "iii", mouse_x, mouse_y,
- mouse_button));
+ gdbpy_ref<> result (gdbpy_call_method (m_window.get (), "click",
+ mouse_x, mouse_y, mouse_button));
if (result == nullptr)
gdbpy_print_stack ();
}
#define PyMem_RawMalloc PyMem_Malloc
#endif
-/* PyObject_CallMethod's 'method' and 'format' parameters were missing
- the 'const' qualifier before Python 3.4. Hence, we wrap the
- function in our own version to avoid errors with string literals.
- Note, this is a variadic template because PyObject_CallMethod is a
- varargs function and Python doesn't have a "PyObject_VaCallMethod"
- variant taking a va_list that we could defer to instead. */
+/* A template variable holding the format character (as for
+ Py_BuildValue) for a given type. */
+template<typename T>
+constexpr char gdbpy_method_format;
+
+template<>
+constexpr char gdbpy_method_format<gdb_py_longest> = GDB_PY_LL_ARG[0];
+
+template<>
+constexpr char gdbpy_method_format<gdb_py_ulongest> = GDB_PY_LLU_ARG[0];
+
+template<>
+constexpr char gdbpy_method_format<int> = 'i';
+
+template<>
+constexpr char gdbpy_method_format<unsigned> = 'I';
+
+/* A helper function to compute the PyObject_CallMethod /
+ Py_BuildValue format given the argument types. */
template<typename... Args>
+constexpr std::array<char, sizeof... (Args) + 1>
+gdbpy_make_fmt ()
+{
+ return { gdbpy_method_format<Args>..., '\0' };
+}
+
+/* Typesafe wrapper around PyObject_CallMethod.
+
+ This variant accepts no arguments. */
+
static inline PyObject *
-gdb_PyObject_CallMethod (PyObject *o, const char *method, const char *format,
- Args... args) /* ARI: editCase function */
+gdbpy_call_method (PyObject *o, const char *method)
{
+ /* PyObject_CallMethod's 'method' and 'format' parameters were missing the
+ 'const' qualifier before Python 3.4. */
return PyObject_CallMethod (o,
const_cast<char *> (method),
- const_cast<char *> (format),
- args...);
+ nullptr);
}
+/* Typesafe wrapper around PyObject_CallMethod.
+
+ This variant accepts any number of arguments and automatically
+ computes the format string, ensuring that format/argument
+ mismatches are impossible. */
+
+template<typename Arg, typename... Args>
+static inline PyObject *
+gdbpy_call_method (PyObject *o, const char *method,
+ Arg arg, Args... args)
+{
+ constexpr const auto fmt = gdbpy_make_fmt<Arg, Args...> ();
+
+ /* PyObject_CallMethod's 'method' and 'format' parameters were missing the
+ 'const' qualifier before Python 3.4. */
+ return PyObject_CallMethod (o,
+ const_cast<char *> (method),
+ const_cast<char *> (fmt.data ()),
+ arg, args...);
+}
+
+/* Poison PyObject_CallMethod. The typesafe wrapper gdbpy_call_method should be
+ used instead. */
#undef PyObject_CallMethod
-#define PyObject_CallMethod gdb_PyObject_CallMethod
+template<typename... Args>
+PyObject *
+PyObject_CallMethod (Args...);
/* The 'name' parameter of PyErr_NewException was missing the 'const'
qualifier in Python <= 3.4. Hence, we wrap it in a function to