From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31453 invoked by alias); 23 Oct 2008 19:14:01 -0000 Received: (qmail 31432 invoked by uid 22791); 23 Oct 2008 19:13:58 -0000 X-Spam-Check-By: sourceware.org Received: from mx2.redhat.com (HELO mx2.redhat.com) (66.187.237.31) by sourceware.org (qpsmtpd/0.31) with ESMTP; Thu, 23 Oct 2008 19:13:22 +0000 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id m9NJDJNv005532; Thu, 23 Oct 2008 15:13:19 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id m9NJDImF028983; Thu, 23 Oct 2008 15:13:18 -0400 Received: from opsy.redhat.com (vpn-12-211.rdu.redhat.com [10.11.12.211]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id m9NJDHUR005304; Thu, 23 Oct 2008 15:13:17 -0400 Received: by opsy.redhat.com (Postfix, from userid 500) id 824B488810D; Thu, 23 Oct 2008 13:13:16 -0600 (MDT) To: Rob Quill Cc: gdb-patches@sourceware.org Subject: Re: Convenience functions References: <8f2776cb0801301557t2e265b62u56d6df7cbcec1c84@mail.gmail.com> <20081023134150.GA21234@caradoc.them.org> <20081023152146.GA29371@caradoc.them.org> From: Tom Tromey Reply-To: Tom Tromey X-Attribution: Tom Date: Thu, 23 Oct 2008 19:14:00 -0000 In-Reply-To: <20081023152146.GA29371@caradoc.them.org> (Daniel Jacobowitz's message of "Thu\, 23 Oct 2008 11\:21\:46 -0400") Message-ID: User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-10/txt/msg00581.txt.bz2 Daniel> Maybe I can convince one of you to submit that pair of patches... I looked at this a little bit today. There are two problems. First, in_scope ought to take a string argument. However, converting a string value to a char* is a pain. At least, I couldn't find any predefined way to do this. This area could use a lot of work, I think. Second, Rob's in_scope patch uses lookup_minimal_symbol. This function seems misnamed, in that to me "scope" implies scoping -- but this is just checking for global symbols. I did write some docs. And, you can see the rest in the appended. I wouldn't recommend moving forward with this patch, unless somebody wants to clean it up. I think a different convenience function would be a better starting point. I probably won't work on this any more for the time being. Tom 2008-10-23 Tom Tromey * symtab.c (in_scope_internal_function): New function. (_initialize_symtab): Register it. * value.h (lookup_only_internalvar, create_internalvar, lookup_internalvar): Update. (internal_function_fn, add_internal_function, call_internal_function, value_internal_function_name): Declare. * value.c (struct internal_function): New struct. (functionlist): New global. (internal_fn_type): Likewise. (lookup_only_internalvar): Made argument const. (create_internalvar): Likewise. (lookup_internalvar): Likewise. (value_create_internal_function): New function. (value_internal_function_name): Likewise. (call_internal_function): Likewise. (function_command): Likewise. (add_internal_function): Likewise. (_initialize_values): Add the "function" command. Initialize internal_fn_type. * valprint.c (value_check_printable): Handle TYPE_CODE_INTERNAL_FUNCTION. * gdbtypes.h (enum type_code) : New constant. * eval.c: (evaluate_subexp_standard) : Handle TYPE_CODE_INTERNAL_FUNCTION. 2008-10-23 Tom Tromey * gdb.texinfo (Convenience Vars): Document convenience functions. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index c003cd4..baa5993 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -7390,6 +7390,29 @@ On HP-UX systems, if you refer to a function or variable name that begins with a dollar sign, @value{GDBN} searches for a user or system name first, before it searches for a convenience variable. +@cindex convenience functions +@value{GDBN} also supplies some @dfn{convenience functions}. These +have a syntax similar to convenience variables. A convenience +function can be used in an expression just like an ordinary function; +however, a convenience function is implemented internally to +@value{GDBN}. + +@table @code +@item help function +@kindex help function +@cindex show all convenience functions +Print a list of all convenience functions. +@end table + +Currently there is a single defined convenience function: + +@table @code +@kindex $in_scope +@item $in_scope (@var{name}) +Evaluate to @samp{1} if the symbol @var{name} is defined in the +program, or @samp{0} otherwise. +@end table + @node Registers @section Registers diff --git a/gdb/eval.c b/gdb/eval.c index cf3e876..2d4551d 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -1515,6 +1515,9 @@ evaluate_subexp_standard (struct type *expect_type, else error (_("Expression of type other than \"Function returning ...\" used as function")); } + if (TYPE_CODE (value_type (argvec[0])) == TYPE_CODE_INTERNAL_FUNCTION) + return call_internal_function (argvec[0], nargs, argvec + 1); + return call_function_by_hand (argvec[0], nargs, argvec + 1); /* pai: FIXME save value from call_function_by_hand, then adjust pc by adjust_fn_pc if +ve */ diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 2a41c5b..dc944b1 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -133,7 +133,10 @@ enum type_code TYPE_CODE_NAMESPACE, /* C++ namespace. */ - TYPE_CODE_DECFLOAT /* Decimal floating point. */ + TYPE_CODE_DECFLOAT, /* Decimal floating point. */ + + /* Internal function type. */ + TYPE_CODE_INTERNAL_FUNCTION }; /* For now allow source to use TYPE_CODE_CLASS for C++ classes, as an diff --git a/gdb/symtab.c b/gdb/symtab.c index 3af3e8a..514bc97 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -4578,6 +4578,36 @@ expand_line_sal (struct symtab_and_line sal) } +/* The implementation of the "in_scope" internal function. */ +static struct value * +in_scope_internal_function (void *ignore, int argc, struct value **argv) +{ + const gdb_byte *contents; + struct type *type; + struct minimal_symbol *minsym; + + if (argc != 1) + error (_("in_scope requires a single argument")); + + type = check_typedef (value_type (argv[0])); + if (TYPE_CODE (type) == TYPE_CODE_STRING + || (TYPE_CODE (type) == TYPE_CODE_ARRAY + && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CHAR + || (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_INT + && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) == 1)))) + { + /* Ok. */ + } + else + error (_("in_scope argument must have string type")); + + contents = value_contents (argv[0]); + /* FIXME: host/target charset confusion here. */ + minsym = lookup_minimal_symbol ((char *) contents, NULL, NULL); + return value_from_longest (builtin_type (current_gdbarch)->builtin_int, + minsym != 0); +} + void _initialize_symtab (void) { @@ -4625,6 +4655,13 @@ Show how the debugger handles ambiguities in expressions."), _("\ Valid values are \"ask\", \"all\", \"cancel\", and the default is \"all\"."), NULL, NULL, &setlist, &showlist); + add_internal_function ("in_scope", _("\ +Test whether a name is defined in the current scope.\n\ +This function takes a single argument, a string. It returns one\n\ +if a symbol of that name is available, or zero if no symbol of that\n\ +name appears."), + in_scope_internal_function, NULL); + /* Initialize the one built-in type that isn't language dependent... */ builtin_type_error = init_type (TYPE_CODE_ERROR, 0, 0, "", (struct objfile *) NULL); diff --git a/gdb/valprint.c b/gdb/valprint.c index 99c376f..617a3f4 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -259,6 +259,13 @@ value_check_printable (struct value *val, struct ui_file *stream) return 0; } + if (TYPE_CODE (value_type (val)) == TYPE_CODE_INTERNAL_FUNCTION) + { + fprintf_filtered (stream, _(""), + value_internal_function_name (val)); + return 0; + } + return 1; } diff --git a/gdb/value.c b/gdb/value.c index 0b530f0..b5aa853 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -43,6 +43,24 @@ void _initialize_values (void); +/* Definition of a user function. */ +struct internal_function +{ + /* The name of the function. It is a bit odd to have this in the + function itself -- the user might use a differently-named + convenience variable to hold the function. */ + char *name; + + /* The handler. */ + internal_function_fn handler; + + /* User data for the handler. */ + void *cookie; +}; + +/* Command list holding internal functions. */ +static struct cmd_list_element *functionlist; + struct value { /* Type of value; either not an lval, or one of the various @@ -205,6 +223,10 @@ struct value_history_chunk static struct value_history_chunk *value_history_chain; static int value_history_count; /* Abs number of last entry stored */ + +/* The type of internal functions. */ + +static struct type *internal_fn_type; /* List of all value objects currently allocated (except for those released by calls to release_value) @@ -774,7 +796,7 @@ init_if_undefined_command (char* args, int from_tty) the return value is NULL. */ struct internalvar * -lookup_only_internalvar (char *name) +lookup_only_internalvar (const char *name) { struct internalvar *var; @@ -790,7 +812,7 @@ lookup_only_internalvar (char *name) NAME should not normally include a dollar sign. */ struct internalvar * -create_internalvar (char *name) +create_internalvar (const char *name) { struct internalvar *var; var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); @@ -811,7 +833,7 @@ create_internalvar (char *name) one is created, with a void value. */ struct internalvar * -lookup_internalvar (char *name) +lookup_internalvar (const char *name) { struct internalvar *var; @@ -915,6 +937,81 @@ internalvar_name (struct internalvar *var) return var->name; } +/* Create a value which represents an internal function. + NAME is the name of the function. + HANDLER is a pointer to a function which is called when this + internal function is invoked during expression evaluation. + COOKIE is a pointer which is passed verbatim to HANDLER. */ +static struct value * +value_create_internal_function (const char *name, + internal_function_fn handler, + void *cookie) +{ + struct value *result = allocate_value (internal_fn_type); + gdb_byte *addr = value_contents_writeable (result); + struct internal_function **fnp = (struct internal_function **) addr; + /* The internal_function object is leaked here -- to make it truly + deletable, we would have to reference count it and add special + code to value_free and value_copy. */ + struct internal_function *ifn = XNEW (struct internal_function); + ifn->name = xstrdup (name); + ifn->handler = handler; + ifn->cookie = cookie; + *fnp = ifn; + return result; +} + +/* Return the name of the value VAL, which is assumed to be of + "internal function" type. The result is not copied and should not + be freed or modified. */ +char * +value_internal_function_name (struct value *val) +{ + gdb_byte *addr = value_contents_writeable (val); + struct internal_function *ifn = * (struct internal_function **) addr; + return ifn->name; +} + +/* Call an internal function. FUNC is a value which is assumed to be + of "internal function" type. ARGC is the number of arguments to + pass to it, and ARGV is a vector holding the arguments. */ +struct value * +call_internal_function (struct value *func, int argc, struct value **argv) +{ + gdb_byte *addr = value_contents_writeable (func); + struct internal_function *ifn = * (struct internal_function **) addr; + return (*ifn->handler) (ifn->cookie, argc, argv); +} + +/* The 'function' command. This does nothing -- it is just a + placeholder to let "help function NAME" work. This is also used as + the implementation of the sub-command that is created when + registering an internal function. */ +static void +function_command (char *command, int from_tty) +{ + /* Do nothing. */ +} + +/* Add a new internal function. NAME is the name of the function; DOC + is a documentation string describing the function. HANDLER is + called when the function is invoked. COOKIE is an arbitrary + pointer which is passed to HANDLER and is intended for "user + data". */ +void +add_internal_function (const char *name, const char *doc, + internal_function_fn handler, + void *cookie) +{ + struct internalvar *var = lookup_internalvar (name); + struct value *fnval = value_create_internal_function (name, handler, cookie); + release_value (fnval); + set_internalvar (var, fnval); + + add_cmd (xstrdup (name), no_class, function_command, (char *) doc, + &functionlist); +} + /* Update VALUE before discarding OBJFILE. COPIED_TYPES is used to prevent cycles / duplicates. */ @@ -1795,4 +1892,13 @@ init-if-undefined VARIABLE = EXPRESSION\n\ Set an internal VARIABLE to the result of the EXPRESSION if it does not\n\ exist or does not contain a value. The EXPRESSION is not evaluated if the\n\ VARIABLE is already initialized.")); + + add_prefix_cmd ("function", no_class, function_command, _("\ +Placeholder command for showing help on convenience functions."), + &functionlist, "function ", 0, &cmdlist); + + internal_fn_type = alloc_type (NULL); + TYPE_CODE (internal_fn_type) = TYPE_CODE_INTERNAL_FUNCTION; + TYPE_LENGTH (internal_fn_type) = sizeof (struct internal_function *); + TYPE_NAME (internal_fn_type) = ""; } diff --git a/gdb/value.h b/gdb/value.h index f53d333..e1ea5dc 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -465,11 +465,11 @@ extern void set_internalvar_component (struct internalvar *var, int bitpos, int bitsize, struct value *newvalue); -extern struct internalvar *lookup_only_internalvar (char *name); +extern struct internalvar *lookup_only_internalvar (const char *name); -extern struct internalvar *create_internalvar (char *name); +extern struct internalvar *create_internalvar (const char *name); -extern struct internalvar *lookup_internalvar (char *name); +extern struct internalvar *lookup_internalvar (const char *name); extern int value_equal (struct value *arg1, struct value *arg2); @@ -585,4 +585,19 @@ extern struct value *value_allocate_space_in_inferior (int); extern struct value *value_of_local (const char *name, int complain); extern struct value * value_subscripted_rvalue (struct value *array, struct value *idx, int lowerbound); + +/* User function handler. */ + +typedef struct value *(*internal_function_fn) (void *cookie, + int argc, + struct value **argv); + +void add_internal_function (const char *name, const char *doc, + internal_function_fn handler, void *cookie); + +struct value *call_internal_function (struct value *function, + int argc, struct value **argv); + +char *value_internal_function_name (struct value *); + #endif /* !defined (VALUE_H) */