mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 10:03:47 +08:00
Add xmethod interface to the extension language API.
* defs.h (enum lval_type): New enumerator "lval_xcallable". * extension-priv.h (struct extension_language_ops): Add the xmethod interface. * extension.c (new_xmethod_worker, clone_xmethod_worker, get_matching_xmethod_workers, get_xmethod_argtypes, invoke_xmethod, free_xmethod_worker, free_xmethod_worker_vec): New functions. * extension.h: #include "common/vec.h". New function declarations. (struct xmethod_worker): New struct. (VEC (xmethod_worker_ptr)): New vector type. (xmethod_worker_ptr): New typedef. (xmethod_worker_vec): Likewise. * gdbtypes.c (gdbtypes_post_init): Initialize "xmethod" field of builtin_type. * gdbtypes.h (enum type_code): New enumerator TYPE_CODE_XMETHOD. (struct builtin_type): New field "xmethod". * valarith.c (value_ptradd): Assert that the value argument is not lval_xcallable. * valops.c (value_must_coerce_to_target): Return 0 for lval_xcallable values. * value.c (struct value): New field XM_WORKER in the field LOCATION. (value_address, value_raw_address): Return 0 for lval_xcallable values. (set_value_address): Assert that the value is not an lval_xcallable. (value_free): Free the associated xmethod worker when freeing lval_xcallable values. (set_value_component_location): Assert that the WHOLE value is not lval_xcallable. (value_of_xmethod, call_xmethod): New functions. * value.h: Declare "struct xmethod_worker". Declare new functions value_of_xmethod, call_xmethod.
This commit is contained in:
parent
ef370185fc
commit
e81e7f5e38
@ -1,3 +1,40 @@
|
||||
2014-06-03 Siva Chandra Reddy <sivachandra@google.com>
|
||||
|
||||
* defs.h (enum lval_type): New enumerator "lval_xcallable".
|
||||
* extension-priv.h (struct extension_language_ops): Add the
|
||||
xmethod interface.
|
||||
* extension.c (new_xmethod_worker, clone_xmethod_worker,
|
||||
get_matching_xmethod_workers, get_xmethod_argtypes,
|
||||
invoke_xmethod, free_xmethod_worker,
|
||||
free_xmethod_worker_vec): New functions.
|
||||
* extension.h: #include "common/vec.h".
|
||||
New function declarations.
|
||||
(struct xmethod_worker): New struct.
|
||||
(VEC (xmethod_worker_ptr)): New vector type.
|
||||
(xmethod_worker_ptr): New typedef.
|
||||
(xmethod_worker_vec): Likewise.
|
||||
* gdbtypes.c (gdbtypes_post_init): Initialize "xmethod" field of
|
||||
builtin_type.
|
||||
* gdbtypes.h (enum type_code): New enumerator TYPE_CODE_XMETHOD.
|
||||
(struct builtin_type): New field "xmethod".
|
||||
* valarith.c (value_ptradd): Assert that the value argument is not
|
||||
lval_xcallable.
|
||||
* valops.c (value_must_coerce_to_target): Return 0 for
|
||||
lval_xcallable values.
|
||||
* value.c (struct value): New field XM_WORKER in the field
|
||||
LOCATION.
|
||||
(value_address, value_raw_address): Return 0 for lval_xcallable
|
||||
values.
|
||||
(set_value_address): Assert that the value is not an
|
||||
lval_xcallable.
|
||||
(value_free): Free the associated xmethod worker when freeing
|
||||
lval_xcallable values.
|
||||
(set_value_component_location): Assert that the WHOLE value is not
|
||||
lval_xcallable.
|
||||
(value_of_xmethod, call_xmethod): New functions.
|
||||
* value.h: Declare "struct xmethod_worker".
|
||||
Declare new functions value_of_xmethod, call_xmethod.
|
||||
|
||||
2014-06-03 Joel Brobecker <brobecker@adacore.com>
|
||||
Pedro Alves <palves@redhat.com>
|
||||
|
||||
|
@ -388,6 +388,8 @@ enum lval_type
|
||||
lval_register,
|
||||
/* * In a gdb internal variable. */
|
||||
lval_internalvar,
|
||||
/* * Value encapsulates a callable defined in an extension language. */
|
||||
lval_xcallable,
|
||||
/* * Part of a gdb internal variable (structure field). */
|
||||
lval_internalvar_component,
|
||||
/* * Value's bits are fetched and stored using functions provided
|
||||
|
@ -256,6 +256,52 @@ 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);
|
||||
|
||||
/* xmethod support:
|
||||
clone_xmethod_worker_data, free_xmethod_worker_data,
|
||||
get_matching_xmethod_workers, get_xmethod_arg_types,
|
||||
invoke_xmethod.
|
||||
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 xmethod worker data
|
||||
object for this extension language. */
|
||||
void * (*clone_xmethod_worker_data)
|
||||
(const struct extension_language_defn *extlang, void *data);
|
||||
|
||||
/* Free the DATA object of this extension language. */
|
||||
void (*free_xmethod_worker_data)
|
||||
(const struct extension_language_defn *extlang, void *data);
|
||||
|
||||
/* Return a vector of matching xmethod 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_xmethod_workers)
|
||||
(const struct extension_language_defn *extlang,
|
||||
struct type *obj_type,
|
||||
const char *method_name,
|
||||
xmethod_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_xmethod_arg_types)
|
||||
(const struct extension_language_defn *extlang,
|
||||
struct xmethod_worker *worker,
|
||||
int *nargs,
|
||||
struct type ***arg_types);
|
||||
|
||||
/* Invoke the xmethod serviced by WORKER. The xmethod is invoked
|
||||
on OBJECT with arguments in the array ARGS. NARGS is the length of
|
||||
this array. Returns the value returned by the xmethod. */
|
||||
struct value * (*invoke_xmethod)
|
||||
(const struct extension_language_defn *extlang,
|
||||
struct xmethod_worker *worker,
|
||||
struct value *object,
|
||||
struct value **args,
|
||||
int nargs);
|
||||
};
|
||||
|
||||
/* State necessary to restore a signal handler to its previous value. */
|
||||
|
154
gdb/extension.c
154
gdb/extension.c
@ -834,6 +834,160 @@ check_quit_flag (void)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* xmethod support. */
|
||||
|
||||
/* The xmethod API routines do not have "ext_lang" in the name because
|
||||
the name "xmethod" implies that this routine deals with extension
|
||||
languages. Plus some of the methods take a xmethod_foo * "self/this"
|
||||
arg, not an extension_language_defn * arg. */
|
||||
|
||||
/* Returns a new xmethod_worker with EXTLANG and DATA. Space for the
|
||||
result must be freed with free_xmethod_worker. */
|
||||
|
||||
struct xmethod_worker *
|
||||
new_xmethod_worker (const struct extension_language_defn *extlang, void *data)
|
||||
{
|
||||
struct xmethod_worker *worker = XCNEW (struct xmethod_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_xmethod_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.
|
||||
|
||||
Space for the result must be freed with free_xmethod_worker. */
|
||||
|
||||
struct xmethod_worker *
|
||||
clone_xmethod_worker (struct xmethod_worker *worker)
|
||||
{
|
||||
struct xmethod_worker *new_worker;
|
||||
const struct extension_language_defn *extlang = worker->extlang;
|
||||
|
||||
gdb_assert (extlang->ops->clone_xmethod_worker_data != NULL);
|
||||
|
||||
new_worker = new_xmethod_worker
|
||||
(extlang,
|
||||
extlang->ops->clone_xmethod_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 'xmethod_worker_ptr' objects. If no matching methods are
|
||||
found, NULL is returned. */
|
||||
|
||||
VEC (xmethod_worker_ptr) *
|
||||
get_matching_xmethod_workers (struct type *type, const char *method_name)
|
||||
{
|
||||
VEC (xmethod_worker_ptr) *workers = NULL;
|
||||
int i;
|
||||
const struct extension_language_defn *extlang;
|
||||
|
||||
ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
|
||||
{
|
||||
VEC (xmethod_worker_ptr) *lang_workers, *new_vec;
|
||||
enum ext_lang_rc rc;
|
||||
|
||||
/* If an extension language does not support xmethods, ignore
|
||||
it. */
|
||||
if (extlang->ops->get_matching_xmethod_workers == NULL)
|
||||
continue;
|
||||
|
||||
rc = extlang->ops->get_matching_xmethod_workers (extlang,
|
||||
type, method_name,
|
||||
&lang_workers);
|
||||
if (rc == EXT_LANG_RC_ERROR)
|
||||
{
|
||||
free_xmethod_worker_vec (workers);
|
||||
error (_("Error while looking for matching xmethod workers "
|
||||
"defined in %s."), extlang->capitalized_name);
|
||||
}
|
||||
|
||||
new_vec = VEC_merge (xmethod_worker_ptr, workers, lang_workers);
|
||||
/* Free only the vectors and not the elements as NEW_VEC still
|
||||
contains them. */
|
||||
VEC_free (xmethod_worker_ptr, workers);
|
||||
VEC_free (xmethod_worker_ptr, lang_workers);
|
||||
workers = new_vec;
|
||||
}
|
||||
|
||||
return workers;
|
||||
}
|
||||
|
||||
/* Return the arg types of the xmethod 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_xmethod_arg_types (struct xmethod_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_xmethod_arg_types != NULL);
|
||||
|
||||
rc = extlang->ops->get_xmethod_arg_types (extlang, worker, nargs,
|
||||
&type_array);
|
||||
if (rc == EXT_LANG_RC_ERROR)
|
||||
{
|
||||
error (_("Error while looking for arg types of a xmethod worker "
|
||||
"defined in %s."), extlang->capitalized_name);
|
||||
}
|
||||
|
||||
return type_array;
|
||||
}
|
||||
|
||||
/* Invokes the xmethod 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_xmethod (struct xmethod_worker *worker, struct value *obj,
|
||||
struct value **args, int nargs)
|
||||
{
|
||||
gdb_assert (worker->extlang->ops->invoke_xmethod != NULL);
|
||||
|
||||
return worker->extlang->ops->invoke_xmethod (worker->extlang, worker,
|
||||
obj, args, nargs);
|
||||
}
|
||||
|
||||
/* Frees the xmethod worker WORKER. */
|
||||
|
||||
void
|
||||
free_xmethod_worker (struct xmethod_worker *worker)
|
||||
{
|
||||
gdb_assert (worker->extlang->ops->free_xmethod_worker_data != NULL);
|
||||
worker->extlang->ops->free_xmethod_worker_data (worker->extlang,
|
||||
worker->data);
|
||||
xfree (worker);
|
||||
}
|
||||
|
||||
/* Frees a vector of xmethod_workers VEC. */
|
||||
|
||||
void
|
||||
free_xmethod_worker_vec (void *vec)
|
||||
{
|
||||
int i;
|
||||
struct xmethod_worker *worker;
|
||||
VEC (xmethod_worker_ptr) *v = (VEC (xmethod_worker_ptr) *) vec;
|
||||
|
||||
for (i = 0; VEC_iterate (xmethod_worker_ptr, v, i, worker); i++)
|
||||
free_xmethod_worker (worker);
|
||||
|
||||
VEC_free (xmethod_worker_ptr, v);
|
||||
}
|
||||
|
||||
/* 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,26 @@ struct ext_lang_type_printers
|
||||
/* Type-printers from Python. */
|
||||
void *py_type_printers;
|
||||
};
|
||||
|
||||
/* A type which holds its extension language specific xmethod worker data. */
|
||||
|
||||
struct xmethod_worker
|
||||
{
|
||||
/* The language the xmethod worker is implemented in. */
|
||||
const struct extension_language_defn *extlang;
|
||||
|
||||
/* The extension language specific data for this xmethod 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 xmethod_worker *xmethod_worker_ptr;
|
||||
DEF_VEC_P (xmethod_worker_ptr);
|
||||
typedef VEC (xmethod_worker_ptr) xmethod_worker_vec;
|
||||
|
||||
|
||||
/* The interface for gdb's own extension(/scripting) language. */
|
||||
extern const struct extension_language_defn extension_language_gdb;
|
||||
@ -212,4 +233,22 @@ 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_xmethod (struct xmethod_worker *,
|
||||
struct value *,
|
||||
struct value **, int nargs);
|
||||
|
||||
extern struct xmethod_worker *clone_xmethod_worker (struct xmethod_worker *);
|
||||
|
||||
extern struct xmethod_worker *new_xmethod_worker
|
||||
(const struct extension_language_defn *extlang, void *data);
|
||||
|
||||
extern void free_xmethod_worker (struct xmethod_worker *);
|
||||
|
||||
extern void free_xmethod_worker_vec (void *vec);
|
||||
|
||||
extern xmethod_worker_vec *get_matching_xmethod_workers
|
||||
(struct type *, const char *);
|
||||
|
||||
extern struct type **get_xmethod_arg_types (struct xmethod_worker *, int *);
|
||||
|
||||
#endif /* EXTENSION_H */
|
||||
|
@ -4387,6 +4387,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 implemented 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. */
|
||||
|
@ -1372,7 +1372,8 @@ value_must_coerce_to_target (struct value *val)
|
||||
|
||||
/* The only lval kinds which do not live in target memory. */
|
||||
if (VALUE_LVAL (val) != not_lval
|
||||
&& VALUE_LVAL (val) != lval_internalvar)
|
||||
&& VALUE_LVAL (val) != lval_internalvar
|
||||
&& VALUE_LVAL (val) != lval_xcallable)
|
||||
return 0;
|
||||
|
||||
valtype = check_typedef (value_type (val));
|
||||
|
47
gdb/value.c
47
gdb/value.c
@ -230,6 +230,9 @@ struct value
|
||||
/* Pointer to internal variable. */
|
||||
struct internalvar *internalvar;
|
||||
|
||||
/* Pointer to xmethod worker. */
|
||||
struct xmethod_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. */
|
||||
@ -1340,7 +1343,8 @@ CORE_ADDR
|
||||
value_address (const struct value *value)
|
||||
{
|
||||
if (value->lval == lval_internalvar
|
||||
|| value->lval == lval_internalvar_component)
|
||||
|| value->lval == lval_internalvar_component
|
||||
|| value->lval == lval_xcallable)
|
||||
return 0;
|
||||
if (value->parent != NULL)
|
||||
return value_address (value->parent) + value->offset;
|
||||
@ -1352,7 +1356,8 @@ CORE_ADDR
|
||||
value_raw_address (struct value *value)
|
||||
{
|
||||
if (value->lval == lval_internalvar
|
||||
|| value->lval == lval_internalvar_component)
|
||||
|| value->lval == lval_internalvar_component
|
||||
|| value->lval == lval_xcallable)
|
||||
return 0;
|
||||
return value->location.address;
|
||||
}
|
||||
@ -1361,7 +1366,8 @@ void
|
||||
set_value_address (struct value *value, CORE_ADDR addr)
|
||||
{
|
||||
gdb_assert (value->lval != lval_internalvar
|
||||
&& value->lval != lval_internalvar_component);
|
||||
&& value->lval != lval_internalvar_component
|
||||
&& value->lval != lval_xcallable);
|
||||
value->location.address = addr;
|
||||
}
|
||||
|
||||
@ -1433,6 +1439,8 @@ value_free (struct value *val)
|
||||
if (funcs->free_closure)
|
||||
funcs->free_closure (val);
|
||||
}
|
||||
else if (VALUE_LVAL (val) == lval_xcallable)
|
||||
free_xmethod_worker (val->location.xm_worker);
|
||||
|
||||
xfree (val->contents);
|
||||
VEC_free (range_s, val->unavailable);
|
||||
@ -1623,6 +1631,8 @@ void
|
||||
set_value_component_location (struct value *component,
|
||||
const struct value *whole)
|
||||
{
|
||||
gdb_assert (whole->lval != lval_xcallable);
|
||||
|
||||
if (whole->lval == lval_internalvar)
|
||||
VALUE_LVAL (component) = lval_internalvar_component;
|
||||
else
|
||||
@ -2456,6 +2466,37 @@ show_convenience (char *ignore, int from_tty)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the TYPE_CODE_XMETHOD value corresponding to WORKER. */
|
||||
|
||||
struct value *
|
||||
value_of_xmethod (struct xmethod_worker *worker)
|
||||
{
|
||||
if (worker->value == NULL)
|
||||
{
|
||||
struct value *v;
|
||||
|
||||
v = allocate_value (builtin_type (target_gdbarch ())->xmethod);
|
||||
v->lval = lval_xcallable;
|
||||
v->location.xm_worker = worker;
|
||||
v->modifiable = 0;
|
||||
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_xcallable && argc > 0);
|
||||
|
||||
return invoke_xmethod (method->location.xm_worker,
|
||||
argv[0], argv + 1, argc - 1);
|
||||
}
|
||||
|
||||
/* 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 xmethod_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
|
||||
@ -1011,4 +1012,9 @@ struct value *call_internal_function (struct gdbarch *gdbarch,
|
||||
|
||||
char *value_internal_function_name (struct value *);
|
||||
|
||||
extern struct value *value_of_xmethod (struct xmethod_worker *);
|
||||
|
||||
struct value *call_xmethod (struct value *function,
|
||||
int argc, struct value **argv);
|
||||
|
||||
#endif /* !defined (VALUE_H) */
|
||||
|
Loading…
Reference in New Issue
Block a user