From: Siva Chandra Date: Tue, 20 May 2014 13:30:29 +0000 (-0700) Subject: Add xmethod interface to the extension language API. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e81e7f5e38bf0da52d9e88a94e4df9aeecd80357;p=binutils-gdb.git 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. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2b2a9f48c12..0f87a60d0cd 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,40 @@ +2014-06-03 Siva Chandra Reddy + + * 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 Pedro Alves diff --git a/gdb/defs.h b/gdb/defs.h index 47da43a6652..b7e9ff46b17 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 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 diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h index 9e63a9c2913..9237273564c 100644 --- a/gdb/extension-priv.h +++ b/gdb/extension-priv.h @@ -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. */ diff --git a/gdb/extension.c b/gdb/extension.c index 1146cc7d03c..93359c58656 100644 --- a/gdb/extension.c +++ b/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, diff --git a/gdb/extension.h b/gdb/extension.h index 61dc81b551c..c08d98dadbc 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,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 */ diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index d58193e82f4..0d7b793c6ec 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -4387,6 +4387,10 @@ gdbtypes_post_init (struct gdbarch *gdbarch) = arch_type (gdbarch, TYPE_CODE_INTERNAL_FUNCTION, 0, ""); + /* This type represents an xmethod. */ + builtin_type->xmethod + = arch_type (gdbarch, TYPE_CODE_XMETHOD, 0, ""); + return builtin_type; } diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 86b1d629f44..bb6352d74a1 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 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. */ diff --git a/gdb/valops.c b/gdb/valops.c index ff25f1a67d9..e915e34e596 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -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)); diff --git a/gdb/value.c b/gdb/value.c index d125a0913a9..1cdb1093ed3 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 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. diff --git a/gdb/value.h b/gdb/value.h index 144e18264a2..65fd203b960 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 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) */