[2/4,v14] Add xmethod (was debug method) interface to the extension language API
Commit Message
This part of the patch series was previously approved but sending out
for review again because of the following changes:
1. The name "debug methods" has been changed to "xmethods". The
attached patch does not change the name at every instance, but only
with the new changes made after v13. The reason is that I am not sure
if we are going to stick with the name "xmethod". I thought leaving
in both the names for now would help is deciding which seems better,
but if it makes reading difficult, I can change it all places.
2. "xmethods" now have an associated type, TYPE_CODE_XMETHOD. The
function find_overload_match returns a value of type TYPE_CODE_XMETHOD
if the best matching method is an xmethod. This change is in part 3/4
of this series, but the required infrastructure is added in this part.
ChangeLog
2014-04-28 Siva Chandra Reddy <sivachandra@google.com>
* defs.h (enum lval_type): New enumerator "lval_xmethod".
* extension-priv.h (struct extension_language_ops): Add the
debug method interface.
* extension.c (new_debug_method_worker, clone_debug_method_worker,
get_matching_debug_method_workers, get_debug_method_argtypes,
invoke_debug_method, free_xmethod_worker,
free_debug_method_worker_vec,
make_debug_method_worker_vec_cleanup): New functions.
* extension.h: #include "common/vec.h".
New function declarations.
(struct debug_method_worker): New struct.
(VEC (debug_method_worker_ptr)): New vector type.
(debug_method_worker_ptr): New typedef.
(debug_method_worker_vec): Likewise.
* gdbtypes.h (enum type_code): New enumerator TYPE_CODE_XMETHOD.
(struct builtin_type): New field "xmethod".
* gdbtypes.c (gdbtypes_post_init): Initialize "xmethod" field of
builtin_type.
* value.c: #include "extension.h".
(struct value): New field XM_WORKER in the field LOCATION.
(value_of_xmethod, call_xmethod, free_xmethod_value): New
functions.
* value.h: Declare new functions value_of_xmethod, call_xmethod
and free_xmethod_value.
Comments
Siva Chandra writes:
> This part of the patch series was previously approved but sending out
> for review again because of the following changes:
>
> 1. The name "debug methods" has been changed to "xmethods". The
> attached patch does not change the name at every instance, but only
> with the new changes made after v13. The reason is that I am not sure
> if we are going to stick with the name "xmethod". I thought leaving
> in both the names for now would help is deciding which seems better,
> but if it makes reading difficult, I can change it all places.
Yeah, I hear you. :-)
I'm totally ok with "xmethods".
We may be on our own on this one,
or someone may step up to wish something else.
Let's proceed as if we're on our own.
This patch series has been out there for long enough.
> 2. "xmethods" now have an associated type, TYPE_CODE_XMETHOD. The
> function find_overload_match returns a value of type TYPE_CODE_XMETHOD
> if the best matching method is an xmethod. This change is in part 3/4
> of this series, but the required infrastructure is added in this part.
Righto.
> ChangeLog
> 2014-04-28 Siva Chandra Reddy <sivachandra@google.com>
>
> * defs.h (enum lval_type): New enumerator "lval_xmethod".
IWBN to avoid creating a new lval_foo enum.
I gather you're using lval_internalvar as a guide
(since that's what's used for TYPE_CODE_INTERNAL_FUNCTION).
lval_foo is used in lots of places, and if you go this route
you're going to need to grep for all occurrences of lval_internalvar
and see if you need to handle lval_xmethod too. Chances are you will,
and that's going to complicate this patch.
E.g., I see appearances in ada-lang.c and py-prettyprint.c.
Plus will we also need lval_xfunction?
Bleah. What to do ... :-(
Since TYPE_CODE_INTERNAL_FUNCTION provides the ability to
specify an arbitrary function and closure, I'm tempted to
try using it for xmethods. Or invent a new lval_foo enum,
but for use by call "functions".
Thoughts?
> * extension-priv.h (struct extension_language_ops): Add the
> debug method interface.
> * extension.c (new_debug_method_worker, clone_debug_method_worker,
> get_matching_debug_method_workers, get_debug_method_argtypes,
> invoke_debug_method, free_xmethod_worker,
> free_debug_method_worker_vec,
> make_debug_method_worker_vec_cleanup): New functions.
> * extension.h: #include "common/vec.h".
> New function declarations.
> (struct debug_method_worker): New struct.
> (VEC (debug_method_worker_ptr)): New vector type.
> (debug_method_worker_ptr): New typedef.
> (debug_method_worker_vec): Likewise.
> * gdbtypes.h (enum type_code): New enumerator TYPE_CODE_XMETHOD.
> (struct builtin_type): New field "xmethod".
> * gdbtypes.c (gdbtypes_post_init): Initialize "xmethod" field of
> builtin_type.
> * value.c: #include "extension.h".
> (struct value): New field XM_WORKER in the field LOCATION.
> (value_of_xmethod, call_xmethod, free_xmethod_value): New
> functions.
> * value.h: Declare new functions value_of_xmethod, call_xmethod
> and free_xmethod_value.
> diff --git a/gdb/defs.h b/gdb/defs.h
> index 47da43a..6750585 100644
> --- a/gdb/defs.h
> +++ b/gdb/defs.h
> @@ -388,6 +388,8 @@ enum lval_type
> lval_register,
> /* * In a gdb internal variable. */
> lval_internalvar,
> + /* * Value is an xmethod. */
> + lval_xmethod,
> /* * Part of a gdb internal variable (structure field). */
> lval_internalvar_component,
> /* * Value's bits are fetched and stored using functions provided
> diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h
> index 9e63a9c..b862dd3 100644
> --- a/gdb/extension-priv.h
> +++ b/gdb/extension-priv.h
> @@ -256,6 +256,54 @@ struct extension_language_ops
> changed or an error occurs no further languages are called. */
> enum ext_lang_rc (*before_prompt) (const struct extension_language_defn *,
> const char *current_gdb_prompt);
> +
> + /* Debug method support:
> + clone_debug_method_worker_data, free_debug_method_worker_data,
> + get_matching_debug_method_workers, get_debug_method_arg_types,
> + invoke_debug_method.
> + These methods are optional and may be NULL, but if one of them is
> + implemented then they all must be. */
> +
> + /* Clone DATA and return a new but identical debug method worker data
> + object for this extension language. */
> + void * (*clone_debug_method_worker_data)
> + (const struct extension_language_defn *extlang, void *data);
> +
> + /* Free the DATA object of this extension language. */
> + void (*free_debug_method_worker_data)
> + (const struct extension_language_defn *extlang, void *data);
> +
> + /* Return a vector of matching debug method workers defined in this
> + extension language. The workers service methods with name
> + METHOD_NAME on objects of type OBJ_TYPE. The vector is returned
> + in DM_VEC. */
> + enum ext_lang_rc (*get_matching_debug_method_workers)
> + (const struct extension_language_defn *extlang,
> + struct type *obj_type,
> + const char *method_name,
> + debug_method_worker_vec **dm_vec);
> +
> + /* Given a WORKER servicing a particular method, return the types
> + of the arguments the method takes. The number of arguments is
> + returned in NARGS, and their types are returned in the array
> + ARGTYPES. */
> + enum ext_lang_rc (*get_debug_method_arg_types)
> + (const struct extension_language_defn *extlang,
> + struct debug_method_worker *worker,
> + int *nargs,
> + struct type ***arg_types);
> +
> + /* Invoke the debug method serviced by WORKER. The method is invoked
> + on OBJECT with arguments in the array ARGS. NARGS is the length of
> + this array. The value returned by the method is returned in
> + RESULT. */
> + enum ext_lang_rc (*invoke_debug_method)
> + (const struct extension_language_defn *extlang,
> + struct debug_method_worker *worker,
> + struct value *object,
> + struct value **args,
> + int nargs,
> + struct value **result);
> };
Filing for future reference.
If/When we add xfunctions, do we want invoke_xfunction here,
in addition to invoke_xmethod, or will we want just one invoke_foo
function that handles both.
Dunno, we can decide then, no need to change this part now.
>
> /* State necessary to restore a signal handler to its previous value. */
> diff --git a/gdb/extension.c b/gdb/extension.c
> index 1146cc7..2cb1cbe 100644
> --- a/gdb/extension.c
> +++ b/gdb/extension.c
> @@ -834,6 +834,182 @@ check_quit_flag (void)
> return result;
> }
>
> +/* Debug method support. */
> +
> +/* Debug method API routines do not have "ext_lang" in the name because
> +the name "debug_method" implies that this routine deals with extension
> +languages. Plus some of the methods take a debug_method_foo * "self/this"
> +arg, not an extension_language_defn * arg. */
Bad indentation.
> +
> +static void free_debug_method_worker_vec (void *vec);
> +
> +/* Returns a new debug_method_worker with EXTLANG and DATA. Space for the
> + result is allocated using malloc. Caller must free. */
> +
> +struct debug_method_worker *
> +new_debug_method_worker (const struct extension_language_defn *extlang,
> + void *data)
> +{
> + struct debug_method_worker *worker = XCNEW (struct debug_method_worker);
> +
> + worker->extlang = extlang;
> + worker->data = data;
> + worker->value = NULL;
> +
> + return worker;
> +}
> +
> +/* Clones WORKER and returns a new but identical worker.
> + The function get_matching_debug_method_workers (see below), returns a
> + vector of matching workers. If a particular worker is selected by GDB
> + to invoke a method, then this function can help in cloning the
> + selected worker and freeing up the vector via a cleanup (see
> + make_debug_method_worker_vec_cleanup below).
> +
> + Space for the result is allocated using malloc. Caller must free. */
> +
> +struct debug_method_worker *
> +clone_debug_method_worker (struct debug_method_worker *worker)
> +{
> + struct debug_method_worker *new_worker;
> + const struct extension_language_defn *extlang = worker->extlang;
> +
> + gdb_assert (extlang->ops->clone_debug_method_worker_data != NULL);
> +
> + new_worker = new_debug_method_worker
> + (extlang,
> + extlang->ops->clone_debug_method_worker_data (extlang, worker->data));
> +
> + return new_worker;
> +}
> +
> +/* If a method with name METHOD_NAME is to be invoked on an object of type
> + TYPE, then all entension languages are searched for implementations of
> + methods with name METHOD. All matches found are returned as a vector
> + of 'debug_method_worker_ptr' objects. If no matching methods are
> + found, NULL is returned. */
> +
> +VEC (debug_method_worker_ptr) *
> +get_matching_debug_method_workers (struct type *type, const char *method_name)
> +{
> + VEC (debug_method_worker_ptr) *workers = NULL;
> + int i;
> + const struct extension_language_defn *extlang;
> +
> + ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
> + {
> + VEC (debug_method_worker_ptr) *lang_workers, *new_vec;
> + enum ext_lang_rc rc;
> +
> + /* If an extension language does not support debug methods, ignore
> + it. */
> + if (extlang->ops->get_matching_debug_method_workers == NULL)
> + continue;
> +
> + rc = extlang->ops->get_matching_debug_method_workers (extlang,
> + type, method_name,
> + &lang_workers);
> + if (rc == EXT_LANG_RC_ERROR)
> + {
> + free_debug_method_worker_vec (workers);
> + error (_("Error while looking for matching debug method workers "
> + "defined in %s."), extlang->capitalized_name);
> + }
> +
> + new_vec = VEC_merge (debug_method_worker_ptr, workers, lang_workers);
> + /* Free only the vectors and not the elements as NEW_VEC still
> + contains them. */
> + VEC_free (debug_method_worker_ptr, workers);
> + VEC_free (debug_method_worker_ptr, lang_workers);
> + workers = new_vec;
> + }
> +
> + return workers;
> +}
> +
> +/* Return the arg types of the debug method encapsulated in WORKER.
> + An array of arg types is returned. The length of the array is returned in
> + NARGS. The type of the 'this' object is returned as the first element of
> + array. */
> +
> +struct type **
> +get_debug_method_arg_types (struct debug_method_worker *worker, int *nargs)
> +{
> + enum ext_lang_rc rc;
> + struct type **type_array = NULL;
> + const struct extension_language_defn *extlang = worker->extlang;
> +
> + gdb_assert (extlang->ops->get_debug_method_arg_types != NULL);
> +
> + rc = extlang->ops->get_debug_method_arg_types (extlang, worker, nargs,
> + &type_array);
> + if (rc == EXT_LANG_RC_ERROR)
> + {
> + error (_("Error while looking for arg types of a debug method worker "
> + "defined in %s."), extlang->capitalized_name);
> + }
> +
> + return type_array;
> +}
> +
> +/* Invokes the debug method encapsulated in WORKER and returns the result.
> + The method is invoked on OBJ with arguments in the ARGS array. NARGS is
> + the length of the this array. */
> +
> +struct value *
> +invoke_debug_method (struct debug_method_worker *worker, struct value *obj,
> + struct value **args, int nargs)
> +{
> + struct value *result = NULL;
> + enum ext_lang_rc rc;
> +
> + gdb_assert (worker->extlang->ops->invoke_debug_method != NULL);
> +
> + rc = worker->extlang->ops->invoke_debug_method (worker->extlang, worker,
> + obj, args, nargs, &result);
> + if (rc == EXT_LANG_RC_ERROR)
> + {
> + error (_("Error while invoking a debug method defined in %s"),
> + worker->extlang->capitalized_name);
> + }
> +
> + return result;
> +}
> +
> +/* Frees the xmethod worker WORKER. */
> +
> +void
> +free_xmethod_worker (struct debug_method_worker *worker)
> +{
> + gdb_assert (worker->extlang->ops->free_debug_method_worker_data != NULL);
> + worker->extlang->ops->free_debug_method_worker_data (worker->extlang,
> + worker->data);
> + xfree (worker);
> +}
> +
> +/* Frees a vector of debug_method_workers VEC. */
> +
> +static void
> +free_debug_method_worker_vec (void *vec)
> +{
> + int i;
> + struct debug_method_worker *worker;
> + VEC (debug_method_worker_ptr) *v = (VEC (debug_method_worker_ptr) *) vec;
> +
> + for (i = 0; VEC_iterate (debug_method_worker_ptr, v, i, worker); i++)
> + free_xmethod_worker (worker);
> +
> + VEC_free (debug_method_worker_ptr, v);
> +}
> +
> +/* Return a cleanup object to free the vector VEC of debug method workers. */
> +
> +struct cleanup *
> +make_debug_method_worker_vec_cleanup (VEC (debug_method_worker_ptr) *vec)
I believe we now frown on writing new make_cleanup wrappers,
and prefer people just write make_cleanup (foo, bar) as needed.
If that means needing to export free_debug_method_worker_vec then that's ok.
[Sorry if I didn't catch this sooner.]
> +{
> + return make_cleanup (free_debug_method_worker_vec, (void *) vec);
The void * cast shouldn't be necessary.
> +}
> +
> /* Called via an observer before gdb prints its prompt.
> Iterate over the extension languages giving them a chance to
> change the prompt. The first one to change the prompt wins,
> diff --git a/gdb/extension.h b/gdb/extension.h
> index 61dc81b..7bc6b42 100644
> --- a/gdb/extension.h
> +++ b/gdb/extension.h
> @@ -21,6 +21,7 @@
> #define EXTENSION_H
>
> #include "mi/mi-cmds.h" /* For PRINT_NO_VALUES, etc. */
> +#include "common/vec.h"
>
> struct breakpoint;
> struct command_line;
> @@ -138,6 +139,27 @@ struct ext_lang_type_printers
> /* Type-printers from Python. */
> void *py_type_printers;
> };
> +
> +/* A type which holds its extension language specific debug method worker
> + data. */
> +
> +struct debug_method_worker
> +{
> + /* The language the debug method worker is implemented in. */
> + const struct extension_language_defn *extlang;
> +
> + /* The extension language specific data for this debug method worker. */
> + void *data;
> +
> + /* The TYPE_CODE_XMETHOD value corresponding to this worker.
> + Always Use value_of_xmethod to access it. */
use
> + struct value *value;
> +};
> +
> +typedef struct debug_method_worker *debug_method_worker_ptr;
> +DEF_VEC_P (debug_method_worker_ptr);
> +typedef VEC (debug_method_worker_ptr) debug_method_worker_vec;
> +
>
> /* The interface for gdb's own extension(/scripting) language. */
> extern const struct extension_language_defn extension_language_gdb;
> @@ -212,4 +234,25 @@ extern const struct extension_language_defn *get_breakpoint_cond_ext_lang
>
> extern int breakpoint_ext_lang_cond_says_stop (struct breakpoint *);
>
> +extern struct value *invoke_debug_method (struct debug_method_worker *,
> + struct value *,
> + struct value **, int nargs);
> +
> +extern struct debug_method_worker *clone_debug_method_worker
> + (struct debug_method_worker *);
> +
> +extern struct debug_method_worker *new_debug_method_worker
> + (const struct extension_language_defn *extlang, void *data);
> +
> +extern void free_xmethod_worker (struct debug_method_worker *);
> +
> +extern debug_method_worker_vec *get_matching_debug_method_workers
> + (struct type *, const char *);
> +
> +extern struct type **get_debug_method_arg_types
> + (struct debug_method_worker *, int *);
> +
> +extern struct cleanup *make_debug_method_worker_vec_cleanup
> + (debug_method_worker_vec *vec);
> +
> #endif /* EXTENSION_H */
> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
> index 8b528b8..fdfc311 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -4366,6 +4366,10 @@ gdbtypes_post_init (struct gdbarch *gdbarch)
> = arch_type (gdbarch, TYPE_CODE_INTERNAL_FUNCTION, 0,
> "<internal function>");
>
> + /* This type represents an xmethod. */
> + builtin_type->xmethod
> + = arch_type (gdbarch, TYPE_CODE_XMETHOD, 0, "<xmethod>");
> +
> return builtin_type;
> }
>
> diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
> index 86b1d62..26133d6 100644
> --- a/gdb/gdbtypes.h
> +++ b/gdb/gdbtypes.h
> @@ -179,7 +179,10 @@ enum type_code
> TYPE_CODE_MODULE, /**< Fortran module. */
>
> /* * Internal function type. */
> - TYPE_CODE_INTERNAL_FUNCTION
> + TYPE_CODE_INTERNAL_FUNCTION,
> +
> + /* * Methods implmented in extension languages. */
implemented
> + TYPE_CODE_XMETHOD
> };
>
> /* * For now allow source to use TYPE_CODE_CLASS for C++ classes, as
> @@ -1468,6 +1471,9 @@ struct builtin_type
> /* * This type is used to represent a GDB internal function. */
>
> struct type *internal_fn;
> +
> + /* * This type is used to represent an xmethod. */
> + struct type *xmethod;
> };
>
> /* * Return the type table for the specified architecture. */
> diff --git a/gdb/value.c b/gdb/value.c
> index d125a09..85c2a88 100644
> --- a/gdb/value.c
> +++ b/gdb/value.c
> @@ -230,6 +230,9 @@ struct value
> /* Pointer to internal variable. */
> struct internalvar *internalvar;
>
> + /* Pointer to xmethod worker. */
> + struct debug_method_worker *xm_worker;
> +
> /* If lval == lval_computed, this is a set of function pointers
> to use to access and describe the value, and a closure pointer
> for them to use. */
> @@ -1433,6 +1436,8 @@ value_free (struct value *val)
> if (funcs->free_closure)
> funcs->free_closure (val);
> }
> + else if (VALUE_LVAL (val) == lval_xmethod)
> + free_xmethod_worker (val->location.xm_worker);
>
> xfree (val->contents);
> VEC_free (range_s, val->unavailable);
> @@ -2456,6 +2461,56 @@ show_convenience (char *ignore, int from_tty)
> }
> }
>
> +/* Return the TYPE_CODE_XMETHOD value corresponding to WORKER. When done with
> + the value and the WORKER, free it using free_xmethod_value. Free-ing the
Freeing
> + value frees the WORKER as well. */
> +
> +struct value *
> +value_of_xmethod (struct debug_method_worker *worker)
> +{
> + struct value *v;
> +
> + if (worker->value != NULL)
> + v = worker->value;
> + else
> + {
> + v = allocate_value (builtin_type (target_gdbarch ())->xmethod);
> + v->lval = lval_xmethod;
> + v->location.xm_worker = worker;
> + worker->value = v;
> + }
> +
> + return v;
> +}
What this code is doing is caching the struct value in the
struct debug_method_worker. This code would be easier to read
if written as:
if (worker->value == NULL)
{
struct value *v;
v = allocate_value (builtin_type (target_gdbarch ())->xmethod);
v->lval = lval_xmethod;
v->location.xm_worker = worker;
worker->value = v;
}
return worker->value;
> +
> +/* Call the xmethod corresponding to the TYPE_CODE_XMETHOD value METHOD. */
> +
> +struct value *
> +call_xmethod (struct value *method, int argc, struct value **argv)
> +{
> + gdb_assert (TYPE_CODE (value_type (method)) == TYPE_CODE_XMETHOD
> + && method->lval == lval_xmethod && argc > 0);
> +
> + return invoke_debug_method (method->location.xm_worker,
> + argv[0], argv + 1, argc - 1);
> +}
> +
> +/* Free the TYPE_CODE_XMETHOD value XM_VALUE. Releases the value from the
> + value chain and frees it. The xmethod worker object corresponding to
> + this value is also freed. */
> +
> +void
> +free_xmethod_value (void *xm_value)
> +{
> + struct value *v = xm_value;
> +
> + gdb_assert (TYPE_CODE (value_type (v)) == TYPE_CODE_XMETHOD
> + && v->lval == lval_xmethod);
> +
> + release_value (v);
> + value_free (v);
> +}
> +
> /* Extract a value as a C number (either long or double).
> Knows how to convert fixed values to double, or
> floating values to long.
> diff --git a/gdb/value.h b/gdb/value.h
> index 144e182..55cdb53 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -31,6 +31,7 @@ struct type;
> struct ui_file;
> struct language_defn;
> struct value_print_options;
> +struct debug_method_worker;
>
> /* The structure which defines the type of a value. It should never
> be possible for a program lval value to survive over a call to the
> @@ -857,6 +858,8 @@ extern int compile_internalvar_to_ax (struct internalvar *var,
>
> extern struct internalvar *lookup_internalvar (const char *name);
>
> +extern struct value *value_of_xmethod (struct debug_method_worker *);
> +
> extern int value_equal (struct value *arg1, struct value *arg2);
>
> extern int value_equal_contents (struct value *arg1, struct value *arg2);
> @@ -1011,4 +1014,9 @@ struct value *call_internal_function (struct gdbarch *gdbarch,
>
> char *value_internal_function_name (struct value *);
>
> +struct value *call_xmethod (struct value *function,
> + int argc, struct value **argv);
> +
> +extern void free_xmethod_value (void *);
> +
> #endif /* !defined (VALUE_H) */
@@ -388,6 +388,8 @@ enum lval_type
lval_register,
/* * In a gdb internal variable. */
lval_internalvar,
+ /* * Value is an xmethod. */
+ lval_xmethod,
/* * Part of a gdb internal variable (structure field). */
lval_internalvar_component,
/* * Value's bits are fetched and stored using functions provided
@@ -256,6 +256,54 @@ struct extension_language_ops
changed or an error occurs no further languages are called. */
enum ext_lang_rc (*before_prompt) (const struct extension_language_defn *,
const char *current_gdb_prompt);
+
+ /* Debug method support:
+ clone_debug_method_worker_data, free_debug_method_worker_data,
+ get_matching_debug_method_workers, get_debug_method_arg_types,
+ invoke_debug_method.
+ These methods are optional and may be NULL, but if one of them is
+ implemented then they all must be. */
+
+ /* Clone DATA and return a new but identical debug method worker data
+ object for this extension language. */
+ void * (*clone_debug_method_worker_data)
+ (const struct extension_language_defn *extlang, void *data);
+
+ /* Free the DATA object of this extension language. */
+ void (*free_debug_method_worker_data)
+ (const struct extension_language_defn *extlang, void *data);
+
+ /* Return a vector of matching debug method workers defined in this
+ extension language. The workers service methods with name
+ METHOD_NAME on objects of type OBJ_TYPE. The vector is returned
+ in DM_VEC. */
+ enum ext_lang_rc (*get_matching_debug_method_workers)
+ (const struct extension_language_defn *extlang,
+ struct type *obj_type,
+ const char *method_name,
+ debug_method_worker_vec **dm_vec);
+
+ /* Given a WORKER servicing a particular method, return the types
+ of the arguments the method takes. The number of arguments is
+ returned in NARGS, and their types are returned in the array
+ ARGTYPES. */
+ enum ext_lang_rc (*get_debug_method_arg_types)
+ (const struct extension_language_defn *extlang,
+ struct debug_method_worker *worker,
+ int *nargs,
+ struct type ***arg_types);
+
+ /* Invoke the debug method serviced by WORKER. The method is invoked
+ on OBJECT with arguments in the array ARGS. NARGS is the length of
+ this array. The value returned by the method is returned in
+ RESULT. */
+ enum ext_lang_rc (*invoke_debug_method)
+ (const struct extension_language_defn *extlang,
+ struct debug_method_worker *worker,
+ struct value *object,
+ struct value **args,
+ int nargs,
+ struct value **result);
};
/* State necessary to restore a signal handler to its previous value. */
@@ -834,6 +834,182 @@ check_quit_flag (void)
return result;
}
+/* Debug method support. */
+
+/* Debug method API routines do not have "ext_lang" in the name because
+the name "debug_method" implies that this routine deals with extension
+languages. Plus some of the methods take a debug_method_foo * "self/this"
+arg, not an extension_language_defn * arg. */
+
+static void free_debug_method_worker_vec (void *vec);
+
+/* Returns a new debug_method_worker with EXTLANG and DATA. Space for the
+ result is allocated using malloc. Caller must free. */
+
+struct debug_method_worker *
+new_debug_method_worker (const struct extension_language_defn *extlang,
+ void *data)
+{
+ struct debug_method_worker *worker = XCNEW (struct debug_method_worker);
+
+ worker->extlang = extlang;
+ worker->data = data;
+ worker->value = NULL;
+
+ return worker;
+}
+
+/* Clones WORKER and returns a new but identical worker.
+ The function get_matching_debug_method_workers (see below), returns a
+ vector of matching workers. If a particular worker is selected by GDB
+ to invoke a method, then this function can help in cloning the
+ selected worker and freeing up the vector via a cleanup (see
+ make_debug_method_worker_vec_cleanup below).
+
+ Space for the result is allocated using malloc. Caller must free. */
+
+struct debug_method_worker *
+clone_debug_method_worker (struct debug_method_worker *worker)
+{
+ struct debug_method_worker *new_worker;
+ const struct extension_language_defn *extlang = worker->extlang;
+
+ gdb_assert (extlang->ops->clone_debug_method_worker_data != NULL);
+
+ new_worker = new_debug_method_worker
+ (extlang,
+ extlang->ops->clone_debug_method_worker_data (extlang, worker->data));
+
+ return new_worker;
+}
+
+/* If a method with name METHOD_NAME is to be invoked on an object of type
+ TYPE, then all entension languages are searched for implementations of
+ methods with name METHOD. All matches found are returned as a vector
+ of 'debug_method_worker_ptr' objects. If no matching methods are
+ found, NULL is returned. */
+
+VEC (debug_method_worker_ptr) *
+get_matching_debug_method_workers (struct type *type, const char *method_name)
+{
+ VEC (debug_method_worker_ptr) *workers = NULL;
+ int i;
+ const struct extension_language_defn *extlang;
+
+ ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+ {
+ VEC (debug_method_worker_ptr) *lang_workers, *new_vec;
+ enum ext_lang_rc rc;
+
+ /* If an extension language does not support debug methods, ignore
+ it. */
+ if (extlang->ops->get_matching_debug_method_workers == NULL)
+ continue;
+
+ rc = extlang->ops->get_matching_debug_method_workers (extlang,
+ type, method_name,
+ &lang_workers);
+ if (rc == EXT_LANG_RC_ERROR)
+ {
+ free_debug_method_worker_vec (workers);
+ error (_("Error while looking for matching debug method workers "
+ "defined in %s."), extlang->capitalized_name);
+ }
+
+ new_vec = VEC_merge (debug_method_worker_ptr, workers, lang_workers);
+ /* Free only the vectors and not the elements as NEW_VEC still
+ contains them. */
+ VEC_free (debug_method_worker_ptr, workers);
+ VEC_free (debug_method_worker_ptr, lang_workers);
+ workers = new_vec;
+ }
+
+ return workers;
+}
+
+/* Return the arg types of the debug method encapsulated in WORKER.
+ An array of arg types is returned. The length of the array is returned in
+ NARGS. The type of the 'this' object is returned as the first element of
+ array. */
+
+struct type **
+get_debug_method_arg_types (struct debug_method_worker *worker, int *nargs)
+{
+ enum ext_lang_rc rc;
+ struct type **type_array = NULL;
+ const struct extension_language_defn *extlang = worker->extlang;
+
+ gdb_assert (extlang->ops->get_debug_method_arg_types != NULL);
+
+ rc = extlang->ops->get_debug_method_arg_types (extlang, worker, nargs,
+ &type_array);
+ if (rc == EXT_LANG_RC_ERROR)
+ {
+ error (_("Error while looking for arg types of a debug method worker "
+ "defined in %s."), extlang->capitalized_name);
+ }
+
+ return type_array;
+}
+
+/* Invokes the debug method encapsulated in WORKER and returns the result.
+ The method is invoked on OBJ with arguments in the ARGS array. NARGS is
+ the length of the this array. */
+
+struct value *
+invoke_debug_method (struct debug_method_worker *worker, struct value *obj,
+ struct value **args, int nargs)
+{
+ struct value *result = NULL;
+ enum ext_lang_rc rc;
+
+ gdb_assert (worker->extlang->ops->invoke_debug_method != NULL);
+
+ rc = worker->extlang->ops->invoke_debug_method (worker->extlang, worker,
+ obj, args, nargs, &result);
+ if (rc == EXT_LANG_RC_ERROR)
+ {
+ error (_("Error while invoking a debug method defined in %s"),
+ worker->extlang->capitalized_name);
+ }
+
+ return result;
+}
+
+/* Frees the xmethod worker WORKER. */
+
+void
+free_xmethod_worker (struct debug_method_worker *worker)
+{
+ gdb_assert (worker->extlang->ops->free_debug_method_worker_data != NULL);
+ worker->extlang->ops->free_debug_method_worker_data (worker->extlang,
+ worker->data);
+ xfree (worker);
+}
+
+/* Frees a vector of debug_method_workers VEC. */
+
+static void
+free_debug_method_worker_vec (void *vec)
+{
+ int i;
+ struct debug_method_worker *worker;
+ VEC (debug_method_worker_ptr) *v = (VEC (debug_method_worker_ptr) *) vec;
+
+ for (i = 0; VEC_iterate (debug_method_worker_ptr, v, i, worker); i++)
+ free_xmethod_worker (worker);
+
+ VEC_free (debug_method_worker_ptr, v);
+}
+
+/* Return a cleanup object to free the vector VEC of debug method workers. */
+
+struct cleanup *
+make_debug_method_worker_vec_cleanup (VEC (debug_method_worker_ptr) *vec)
+{
+ return make_cleanup (free_debug_method_worker_vec, (void *) vec);
+}
+
/* Called via an observer before gdb prints its prompt.
Iterate over the extension languages giving them a chance to
change the prompt. The first one to change the prompt wins,
@@ -21,6 +21,7 @@
#define EXTENSION_H
#include "mi/mi-cmds.h" /* For PRINT_NO_VALUES, etc. */
+#include "common/vec.h"
struct breakpoint;
struct command_line;
@@ -138,6 +139,27 @@ struct ext_lang_type_printers
/* Type-printers from Python. */
void *py_type_printers;
};
+
+/* A type which holds its extension language specific debug method worker
+ data. */
+
+struct debug_method_worker
+{
+ /* The language the debug method worker is implemented in. */
+ const struct extension_language_defn *extlang;
+
+ /* The extension language specific data for this debug method worker. */
+ void *data;
+
+ /* The TYPE_CODE_XMETHOD value corresponding to this worker.
+ Always Use value_of_xmethod to access it. */
+ struct value *value;
+};
+
+typedef struct debug_method_worker *debug_method_worker_ptr;
+DEF_VEC_P (debug_method_worker_ptr);
+typedef VEC (debug_method_worker_ptr) debug_method_worker_vec;
+
/* The interface for gdb's own extension(/scripting) language. */
extern const struct extension_language_defn extension_language_gdb;
@@ -212,4 +234,25 @@ extern const struct extension_language_defn *get_breakpoint_cond_ext_lang
extern int breakpoint_ext_lang_cond_says_stop (struct breakpoint *);
+extern struct value *invoke_debug_method (struct debug_method_worker *,
+ struct value *,
+ struct value **, int nargs);
+
+extern struct debug_method_worker *clone_debug_method_worker
+ (struct debug_method_worker *);
+
+extern struct debug_method_worker *new_debug_method_worker
+ (const struct extension_language_defn *extlang, void *data);
+
+extern void free_xmethod_worker (struct debug_method_worker *);
+
+extern debug_method_worker_vec *get_matching_debug_method_workers
+ (struct type *, const char *);
+
+extern struct type **get_debug_method_arg_types
+ (struct debug_method_worker *, int *);
+
+extern struct cleanup *make_debug_method_worker_vec_cleanup
+ (debug_method_worker_vec *vec);
+
#endif /* EXTENSION_H */
@@ -4366,6 +4366,10 @@ gdbtypes_post_init (struct gdbarch *gdbarch)
= arch_type (gdbarch, TYPE_CODE_INTERNAL_FUNCTION, 0,
"<internal function>");
+ /* This type represents an xmethod. */
+ builtin_type->xmethod
+ = arch_type (gdbarch, TYPE_CODE_XMETHOD, 0, "<xmethod>");
+
return builtin_type;
}
@@ -179,7 +179,10 @@ enum type_code
TYPE_CODE_MODULE, /**< Fortran module. */
/* * Internal function type. */
- TYPE_CODE_INTERNAL_FUNCTION
+ TYPE_CODE_INTERNAL_FUNCTION,
+
+ /* * Methods implmented in extension languages. */
+ TYPE_CODE_XMETHOD
};
/* * For now allow source to use TYPE_CODE_CLASS for C++ classes, as
@@ -1468,6 +1471,9 @@ struct builtin_type
/* * This type is used to represent a GDB internal function. */
struct type *internal_fn;
+
+ /* * This type is used to represent an xmethod. */
+ struct type *xmethod;
};
/* * Return the type table for the specified architecture. */
@@ -230,6 +230,9 @@ struct value
/* Pointer to internal variable. */
struct internalvar *internalvar;
+ /* Pointer to xmethod worker. */
+ struct debug_method_worker *xm_worker;
+
/* If lval == lval_computed, this is a set of function pointers
to use to access and describe the value, and a closure pointer
for them to use. */
@@ -1433,6 +1436,8 @@ value_free (struct value *val)
if (funcs->free_closure)
funcs->free_closure (val);
}
+ else if (VALUE_LVAL (val) == lval_xmethod)
+ free_xmethod_worker (val->location.xm_worker);
xfree (val->contents);
VEC_free (range_s, val->unavailable);
@@ -2456,6 +2461,56 @@ show_convenience (char *ignore, int from_tty)
}
}
+/* Return the TYPE_CODE_XMETHOD value corresponding to WORKER. When done with
+ the value and the WORKER, free it using free_xmethod_value. Free-ing the
+ value frees the WORKER as well. */
+
+struct value *
+value_of_xmethod (struct debug_method_worker *worker)
+{
+ struct value *v;
+
+ if (worker->value != NULL)
+ v = worker->value;
+ else
+ {
+ v = allocate_value (builtin_type (target_gdbarch ())->xmethod);
+ v->lval = lval_xmethod;
+ v->location.xm_worker = worker;
+ worker->value = v;
+ }
+
+ return v;
+}
+
+/* Call the xmethod corresponding to the TYPE_CODE_XMETHOD value METHOD. */
+
+struct value *
+call_xmethod (struct value *method, int argc, struct value **argv)
+{
+ gdb_assert (TYPE_CODE (value_type (method)) == TYPE_CODE_XMETHOD
+ && method->lval == lval_xmethod && argc > 0);
+
+ return invoke_debug_method (method->location.xm_worker,
+ argv[0], argv + 1, argc - 1);
+}
+
+/* Free the TYPE_CODE_XMETHOD value XM_VALUE. Releases the value from the
+ value chain and frees it. The xmethod worker object corresponding to
+ this value is also freed. */
+
+void
+free_xmethod_value (void *xm_value)
+{
+ struct value *v = xm_value;
+
+ gdb_assert (TYPE_CODE (value_type (v)) == TYPE_CODE_XMETHOD
+ && v->lval == lval_xmethod);
+
+ release_value (v);
+ value_free (v);
+}
+
/* Extract a value as a C number (either long or double).
Knows how to convert fixed values to double, or
floating values to long.
@@ -31,6 +31,7 @@ struct type;
struct ui_file;
struct language_defn;
struct value_print_options;
+struct debug_method_worker;
/* The structure which defines the type of a value. It should never
be possible for a program lval value to survive over a call to the
@@ -857,6 +858,8 @@ extern int compile_internalvar_to_ax (struct internalvar *var,
extern struct internalvar *lookup_internalvar (const char *name);
+extern struct value *value_of_xmethod (struct debug_method_worker *);
+
extern int value_equal (struct value *arg1, struct value *arg2);
extern int value_equal_contents (struct value *arg1, struct value *arg2);
@@ -1011,4 +1014,9 @@ struct value *call_internal_function (struct gdbarch *gdbarch,
char *value_internal_function_name (struct value *);
+struct value *call_xmethod (struct value *function,
+ int argc, struct value **argv);
+
+extern void free_xmethod_value (void *);
+
#endif /* !defined (VALUE_H) */