diff options
-rw-r--r-- | gdb/cli-out.c | 339 | ||||
-rw-r--r-- | gdb/cli-out.h | 27 | ||||
-rw-r--r-- | gdb/ui-out.c | 1007 | ||||
-rw-r--r-- | gdb/ui-out.h | 221 | ||||
-rw-r--r-- | gdb/varobj.c | 2421 | ||||
-rw-r--r-- | gdb/varobj.h | 92 | ||||
-rw-r--r-- | gdb/wrapper.c | 165 | ||||
-rw-r--r-- | gdb/wrapper.h | 37 |
8 files changed, 4309 insertions, 0 deletions
diff --git a/gdb/cli-out.c b/gdb/cli-out.c new file mode 100644 index 00000000000..d906510aba3 --- /dev/null +++ b/gdb/cli-out.c @@ -0,0 +1,339 @@ +/* Output generating routines for GDB CLI. + Copyright 1999-2000 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + Written by Fernando Nasser for Cygnus. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "ui-out.h" +#include "cli-out.h" + +/* Convenience macro for allocting typesafe memory. */ + +#ifndef XMALLOC +#define XMALLOC(TYPE) (TYPE*) xmalloc (sizeof (TYPE)) +#endif + +struct ui_out_data + { + struct ui_file *stream; + }; + +/* These are the CLI output functions */ + +static void cli_table_begin (struct ui_out *uiout, int nbrofcols, char *tblid); +static void cli_table_body (struct ui_out *uiout); +static void cli_table_end (struct ui_out *uiout); +static void cli_table_header (struct ui_out *uiout, int width, + enum ui_align alig, char *colhdr); +static void cli_list_begin (struct ui_out *uiout, int list_flag, char *lstid); +static void cli_list_end (struct ui_out *uiout, int list_flag); +static void cli_field_int (struct ui_out *uiout, int fldno, int width, + enum ui_align alig, char *fldname, int value); +static void cli_field_skip (struct ui_out *uiout, int fldno, int width, + enum ui_align alig, char *fldname); +static void cli_field_string (struct ui_out *uiout, int fldno, int width, + enum ui_align alig, char *fldname, + const char *string); +static void cli_field_fmt (struct ui_out *uiout, int fldno, + int width, enum ui_align align, + char *fldname, char *format, va_list args); +static void cli_spaces (struct ui_out *uiout, int numspaces); +static void cli_text (struct ui_out *uiout, char *string); +static void cli_message (struct ui_out *uiout, int verbosity, char *format, + va_list args); +static void cli_wrap_hint (struct ui_out *uiout, char *identstring); +static void cli_flush (struct ui_out *uiout); + +/* This is the CLI ui-out implementation functions vector */ + +/* FIXME: This can be initialized dynamically after default is set to + handle initial output in main.c */ + +static struct ui_out_impl cli_ui_out_impl = +{ + cli_table_begin, + cli_table_body, + cli_table_end, + cli_table_header, + cli_list_begin, + cli_list_end, + cli_field_int, + cli_field_skip, + cli_field_string, + cli_field_fmt, + cli_spaces, + cli_text, + cli_message, + cli_wrap_hint, + cli_flush +}; + +/* Prototypes for local functions */ + +extern void _initialize_cli_out PARAMS ((void)); + +static void field_separator (void); + +static void out_field_fmt (struct ui_out *uiout, int fldno, char *fldname, + char *format,...); + +/* local variables */ + +/* (none yet) */ + +/* Mark beginning of a table */ + +void +cli_table_begin (uiout, nbrofcols, tblid) + struct ui_out *uiout; + int nbrofcols; + char *tblid; +{ +} + +/* Mark beginning of a table body */ + +void +cli_table_body (uiout) + struct ui_out *uiout; +{ + /* first, close the table header line */ + cli_text (uiout, "\n"); +} + +/* Mark end of a table */ + +void +cli_table_end (uiout) + struct ui_out *uiout; +{ +} + +/* Specify table header */ + +void +cli_table_header (uiout, width, alignment, colhdr) + struct ui_out *uiout; + int width; + int alignment; + char *colhdr; +{ + cli_field_string (uiout, 0, width, alignment, 0, colhdr); +} + +/* Mark beginning of a list */ + +void +cli_list_begin (uiout, list_flag, lstid) + struct ui_out *uiout; + int list_flag; + char *lstid; +{ +} + +/* Mark end of a list */ + +void +cli_list_end (uiout, list_flag) + struct ui_out *uiout; + int list_flag; +{ +} + +/* output an int field */ + +void +cli_field_int (uiout, fldno, width, alignment, fldname, value) + struct ui_out *uiout; + int fldno; + int width; + int alignment; + char *fldname; + int value; +{ + char buffer[20]; /* FIXME: how many chars long a %d can become? */ + + sprintf (buffer, "%d", value); + cli_field_string (uiout, fldno, width, alignment, fldname, buffer); +} + +/* used to ommit a field */ + +void +cli_field_skip (uiout, fldno, width, alignment, fldname) + struct ui_out *uiout; + int fldno; + int width; + int alignment; + char *fldname; +{ + cli_field_string (uiout, fldno, width, alignment, fldname, ""); +} + +/* other specific cli_field_* end up here so alignment and field + separators are both handled by cli_field_string */ + +void +cli_field_string (struct ui_out *uiout, + int fldno, + int width, + int align, + char *fldname, + const char *string) +{ + int before = 0; + int after = 0; + + if ((align != ui_noalign) && string) + { + before = width - strlen (string); + if (before <= 0) + before = 0; + else + { + if (align == ui_right) + after = 0; + else if (align == ui_left) + { + after = before; + before = 0; + } + else + /* ui_center */ + { + after = before / 2; + before -= after; + } + } + } + + if (before) + ui_out_spaces (uiout, before); + if (string) + out_field_fmt (uiout, fldno, fldname, "%s", string); + if (after) + ui_out_spaces (uiout, after); + + if (align != ui_noalign) + field_separator (); +} + +/* This is the only field function that does not align */ + +void +cli_field_fmt (struct ui_out *uiout, int fldno, + int width, enum ui_align align, + char *fldname, char *format, va_list args) +{ + struct ui_out_data *data = ui_out_data (uiout); + vfprintf_filtered (data->stream, format, args); + + if (align != ui_noalign) + field_separator (); +} + +void +cli_spaces (uiout, numspaces) + struct ui_out *uiout; + int numspaces; +{ + struct ui_out_data *data = ui_out_data (uiout); + print_spaces_filtered (numspaces, data->stream); +} + +void +cli_text (uiout, string) + struct ui_out *uiout; + char *string; +{ + struct ui_out_data *data = ui_out_data (uiout); + fputs_filtered (string, data->stream); +} + +void +cli_message (struct ui_out *uiout, int verbosity, char *format, va_list args) +{ + struct ui_out_data *data = ui_out_data (uiout); + if (ui_out_get_verblvl (uiout) >= verbosity) + vfprintf_unfiltered (data->stream, format, args); +} + +void +cli_wrap_hint (uiout, identstring) + struct ui_out *uiout; + char *identstring; +{ + wrap_here (identstring); +} + +void +cli_flush (uiout) + struct ui_out *uiout; +{ + struct ui_out_data *data = ui_out_data (uiout); + gdb_flush (data->stream); +} + +/* local functions */ + +/* Like cli_field_fmt, but takes a variable number of args + and makes a va_list and does not insert a separator */ + +/* VARARGS */ +static void +out_field_fmt (struct ui_out *uiout, int fldno, char *fldname, + char *format,...) +{ + struct ui_out_data *data = ui_out_data (uiout); + va_list args; + + va_start (args, format); + vfprintf_filtered (data->stream, format, args); + + va_end (args); +} + +/* access to ui_out format private members */ + +static void +field_separator () +{ + struct ui_out_data *data = ui_out_data (uiout); + fputc_filtered (' ', data->stream); +} + +/* initalize private members at startup */ + +struct ui_out * +cli_out_new (struct ui_file *stream) +{ + int flags = ui_source_list; + + struct ui_out_data *data = XMALLOC (struct ui_out_data); + data->stream = stream; + return ui_out_new (&cli_ui_out_impl, data, flags); +} + +/* standard gdb initialization hook */ +void +_initialize_cli_out () +{ + /* nothing needs to be done */ +} diff --git a/gdb/cli-out.h b/gdb/cli-out.h new file mode 100644 index 00000000000..f017f807a96 --- /dev/null +++ b/gdb/cli-out.h @@ -0,0 +1,27 @@ +/* Output generating routines for GDB CLI. + Copyright 1999-2000 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef CLI_OUT_H +#define CLI_OUT_H + +extern struct ui_out *cli_out_new (struct ui_file *stream); + +#endif diff --git a/gdb/ui-out.c b/gdb/ui-out.c new file mode 100644 index 00000000000..9e400111443 --- /dev/null +++ b/gdb/ui-out.c @@ -0,0 +1,1007 @@ +/* Output generating routines for GDB. + Copyright 1999, 2000 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + Written by Fernando Nasser for Cygnus. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdb_string.h" +#include "expression.h" /* For language.h */ +#include "language.h" +#include "ui-out.h" + +/* Convenience macro for allocting typesafe memory. */ + +#undef XMALLOC +#define XMALLOC(TYPE) (TYPE*) xmalloc (sizeof (TYPE)) + +/* table header structures */ + +struct ui_out_hdr + { + int colno; + int width; + int alignment; + char *colhdr; + struct ui_out_hdr *next; + }; + +/* The ui_out structure */ +/* Any change here requires a corresponding one in the initialization + of the default uiout, which is statically initialized */ + +struct ui_out + { + int flags; + /* specific implementation of ui-out */ + struct ui_out_impl *impl; + struct ui_out_data *data; + + /* if on, a table is being generated */ + int table_flag; + + /* if on, the body of a table is being generated */ + int body_flag; + + /* number of table columns (as specified in the table_begin call) */ + int table_columns; + + /* strinf identifying the table (as specified in the table_begin call) */ + char *table_id; + + /* if on, a list is being generated. The value is the level of nesting */ + int list_flag; + + /* we count each field; the first element is for non-list fields */ + int field_count[5]; + + /* points to the first header (if any) */ + struct ui_out_hdr *headerfirst; + + /* points to the last header (if any) */ + struct ui_out_hdr *headerlast; + + /* points to header of next column to format */ + struct ui_out_hdr *headercurr; + + }; + +/* These are the default implementation functions */ + +static void default_table_begin (struct ui_out *uiout, int nbrofcols, + char *tblid); +static void default_table_body (struct ui_out *uiout); +static void default_table_end (struct ui_out *uiout); +static void default_table_header (struct ui_out *uiout, int width, + enum ui_align alig, char *colhdr); +static void default_list_begin (struct ui_out *uiout, int list_flag, + char *lstid); +static void default_list_end (struct ui_out *uiout, int list_flag); +static void default_field_int (struct ui_out *uiout, int fldno, int width, + enum ui_align alig, char *fldname, int value); +static void default_field_skip (struct ui_out *uiout, int fldno, int width, + enum ui_align alig, char *fldname); +static void default_field_string (struct ui_out *uiout, int fldno, int width, + enum ui_align align, char *fldname, + const char *string); +static void default_field_fmt (struct ui_out *uiout, int fldno, + int width, enum ui_align align, + char *fldname, char *format, va_list args); +static void default_spaces (struct ui_out *uiout, int numspaces); +static void default_text (struct ui_out *uiout, char *string); +static void default_message (struct ui_out *uiout, int verbosity, char *format, + va_list args); +static void default_wrap_hint (struct ui_out *uiout, char *identstring); +static void default_flush (struct ui_out *uiout); + +/* This is the default ui-out implementation functions vector */ + +struct ui_out_impl default_ui_out_impl = +{ + default_table_begin, + default_table_body, + default_table_end, + default_table_header, + default_list_begin, + default_list_end, + default_field_int, + default_field_skip, + default_field_string, + default_field_fmt, + default_spaces, + default_text, + default_message, + default_wrap_hint, + default_flush +}; + +/* The default ui_out */ + +struct ui_out def_uiout = +{ + 0, /* flags */ + &default_ui_out_impl, /* impl */ +}; + +/* Pointer to current ui_out */ +/* FIXME: This should not be a global, but something passed down from main.c + or top.c */ + +struct ui_out *uiout = &def_uiout; + +/* These are the interfaces to implementation functions */ + +static void uo_table_begin (struct ui_out *uiout, int nbrofcols, char *tblid); +static void uo_table_body (struct ui_out *uiout); +static void uo_table_end (struct ui_out *uiout); +static void uo_table_header (struct ui_out *uiout, int width, + enum ui_align align, char *colhdr); +static void uo_list_begin (struct ui_out *uiout, int list_flag, char *lstid); +static void uo_list_end (struct ui_out *uiout, int list_flag); +static void uo_field_int (struct ui_out *uiout, int fldno, int width, + enum ui_align align, char *fldname, int value); +static void uo_field_skip (struct ui_out *uiout, int fldno, int width, + enum ui_align align, char *fldname); +static void uo_field_string (struct ui_out *uiout, int fldno, int width, + enum ui_align align, char *fldname, const char *string); +static void uo_field_fmt (struct ui_out *uiout, int fldno, int width, + enum ui_align align, char *fldname, + char *format, va_list args); +static void uo_spaces (struct ui_out *uiout, int numspaces); +static void uo_text (struct ui_out *uiout, char *string); +static void uo_message (struct ui_out *uiout, int verbosity, + char *format, va_list args); +static void uo_wrap_hint (struct ui_out *uiout, char *identstring); +static void uo_flush (struct ui_out *uiout); + +/* Prototypes for local functions */ + +extern void _initialize_ui_out (void); +static void append_header_to_list (struct ui_out *uiout, int width, int alignment, char *colhdr); +static int get_curr_header (struct ui_out *uiout, int *colno, int *width, + int *alignment, char **colhdr); +static void clear_header_list (struct ui_out *uiout); +static void verify_field_proper_position (struct ui_out *uiout); +static void verify_field_alignment (struct ui_out *uiout, int fldno, int *width, int *alignment); + +static void init_ui_out_state (struct ui_out *uiout); + +/* exported functions (ui_out API) */ + +/* Mark beginning of a table */ + +void +ui_out_table_begin (uiout, nbrofcols, tblid) + struct ui_out *uiout; + int nbrofcols; + char *tblid; +{ + if (uiout->table_flag) + internal_error ("gdb/ui_out.c: tables cannot be nested; table_begin found before \ +previous table_end."); + + uiout->table_flag = 1; + uiout->table_columns = nbrofcols; + if (tblid != NULL) + uiout->table_id = xstrdup (tblid); + else + uiout->table_id = NULL; + clear_header_list (uiout); + + uo_table_begin (uiout, nbrofcols, uiout->table_id); +} + +void +ui_out_table_body (uiout) + struct ui_out *uiout; +{ + if (!uiout->table_flag) + internal_error ("gdb/ui_out.c: table_body outside a table is not valid; it must be \ +after a table_begin and before a table_end."); + if (uiout->body_flag) + internal_error ("gdb/ui_out.c: extra table_body call not allowed; there must be \ +only one table_body after a table_begin and before a table_end."); + if (uiout->headercurr->colno != uiout->table_columns) + internal_error ("gdb/ui_out.c: number of headers differ from number of table \ +columns."); + + uiout->body_flag = 1; + uiout->headercurr = uiout->headerfirst; + + uo_table_body (uiout); +} + +void +ui_out_table_end (uiout) + struct ui_out *uiout; +{ + if (!uiout->table_flag) + internal_error ("gdb/ui_out.c: misplaced table_end or missing table_begin."); + + uiout->body_flag = 0; + uiout->table_flag = 0; + + uo_table_end (uiout); + + if (uiout->table_id) + free (uiout->table_id); + clear_header_list (uiout); +} + +void +ui_out_table_header (uiout, width, alignment, colhdr) + struct ui_out *uiout; + int width; + enum ui_align alignment; + char *colhdr; +{ + if (!uiout->table_flag || uiout->body_flag) + internal_error ("ui_out: table header must be specified after table_begin \ +and before table_body."); + + append_header_to_list (uiout, width, alignment, colhdr); + + uo_table_header (uiout, width, alignment, colhdr); +} + +void +ui_out_list_begin (uiout, lstid) + struct ui_out *uiout; + char *lstid; +{ + if (uiout->table_flag && !uiout->body_flag) + internal_error ("ui_out: table header or table_body expected; lists must be \ +specified after table_body."); + if (uiout->list_flag >= 4) + internal_error ("ui_out: list depth exceeded; only 4 levels of lists can be \ +nested."); + + uiout->list_flag++; + uiout->field_count[uiout->list_flag] = 0; + if (uiout->table_flag && (uiout->list_flag == 1)) + uiout->headercurr = uiout->headerfirst; + + uo_list_begin (uiout, uiout->list_flag, lstid); +} + +void +ui_out_list_end (uiout) + struct ui_out *uiout; +{ + if (!uiout->list_flag) + internal_error ("ui_out: misplaced list_end; there is no list to be closed."); + + uo_list_end (uiout, uiout->list_flag); + + uiout->list_flag--; +} + +void +ui_out_field_int (uiout, fldname, value) + struct ui_out *uiout; + char *fldname; + int value; +{ + int fldno; + int width; + int align; + + verify_field_proper_position (uiout); + + uiout->field_count[uiout->list_flag] += 1; + fldno = uiout->field_count[uiout->list_flag]; + + verify_field_alignment (uiout, fldno, &width, &align); + + uo_field_int (uiout, fldno, width, align, fldname, value); +} + +void +ui_out_field_core_addr (uiout, fldname, address) + struct ui_out *uiout; + char *fldname; + CORE_ADDR address; +{ + char addstr[20]; + + /* FIXME-32x64: need a print_address_numeric with field width */ + /* print_address_numeric (address, 1, local_stream); */ + strcpy (addstr, local_hex_string_custom ((unsigned long) address, "08l")); + + ui_out_field_string (uiout, fldname, addstr); +} + +void +ui_out_field_stream (uiout, fldname, buf) + struct ui_out *uiout; + char *fldname; + struct ui_stream *buf; +{ + long length; + char *buffer = ui_file_xstrdup (buf->stream, &length); + struct cleanup *old_cleanup = make_cleanup (free, buffer); + if (length > 0) + ui_out_field_string (uiout, fldname, buffer); + else + ui_out_field_skip (uiout, fldname); + ui_file_rewind (buf->stream); + do_cleanups (old_cleanup); +} + +/* used to ommit a field */ + +void +ui_out_field_skip (uiout, fldname) + struct ui_out *uiout; + char *fldname; +{ + int fldno; + int width; + int align; + + verify_field_proper_position (uiout); + + uiout->field_count[uiout->list_flag] += 1; + fldno = uiout->field_count[uiout->list_flag]; + + verify_field_alignment (uiout, fldno, &width, &align); + + uo_field_skip (uiout, fldno, width, align, fldname); +} + +void +ui_out_field_string (struct ui_out *uiout, + char *fldname, + const char *string) +{ + int fldno; + int width; + int align; + + verify_field_proper_position (uiout); + + uiout->field_count[uiout->list_flag] += 1; + fldno = uiout->field_count[uiout->list_flag]; + + verify_field_alignment (uiout, fldno, &width, &align); + + uo_field_string (uiout, fldno, width, align, fldname, string); +} + +/* VARARGS */ +void +ui_out_field_fmt (struct ui_out *uiout, char *fldname, char *format,...) +{ + va_list args; + int fldno; + int width; + int align; + + verify_field_proper_position (uiout); + + uiout->field_count[uiout->list_flag] += 1; + fldno = uiout->field_count[uiout->list_flag]; + + /* will not align, but has to call anyway */ + verify_field_alignment (uiout, fldno, &width, &align); + + va_start (args, format); + + uo_field_fmt (uiout, fldno, width, align, fldname, format, args); + + va_end (args); +} + +void +ui_out_spaces (uiout, numspaces) + struct ui_out *uiout; + int numspaces; +{ + uo_spaces (uiout, numspaces); +} + +void +ui_out_text (uiout, string) + struct ui_out *uiout; + char *string; +{ + uo_text (uiout, string); +} + +void +ui_out_message (struct ui_out *uiout, int verbosity, char *format,...) +{ + va_list args; + + va_start (args, format); + + uo_message (uiout, verbosity, format, args); + + va_end (args); +} + +struct ui_stream * +ui_out_stream_new (uiout) + struct ui_out *uiout; +{ + struct ui_stream *tempbuf; + + tempbuf = XMALLOC (struct ui_stream); + tempbuf->uiout = uiout; + tempbuf->stream = mem_fileopen (); + return tempbuf; +} + +void +ui_out_stream_delete (buf) + struct ui_stream *buf; +{ + ui_file_delete (buf->stream); + free (buf); +} + +static void +do_stream_delete (void *buf) +{ + ui_out_stream_delete (buf); +} + +struct cleanup * +make_cleanup_ui_out_stream_delete (struct ui_stream *buf) +{ + return make_cleanup (do_stream_delete, buf); +} + + +void +ui_out_wrap_hint (uiout, identstring) + struct ui_out *uiout; + char *identstring; +{ + uo_wrap_hint (uiout, identstring); +} + +void +ui_out_flush (uiout) + struct ui_out *uiout; +{ + uo_flush (uiout); +} + +/* set the flags specified by the mask given */ +int +ui_out_set_flags (uiout, mask) + struct ui_out *uiout; + int mask; +{ + int oldflags; + + uiout->flags != mask; + + return oldflags; +} + +/* clear the flags specified by the mask given */ +int +ui_out_clear_flags (uiout, mask) + struct ui_out *uiout; + int mask; +{ + int oldflags; + + uiout->flags &= ~mask; + + return oldflags; +} + +/* test the flags against the mask given */ +int +ui_out_test_flags (uiout, mask) + struct ui_out *uiout; + int mask; +{ + return (uiout->flags & mask); +} + +/* obtain the current verbosity level (as stablished by the + 'set verbositylevel' command */ + +int +ui_out_get_verblvl (uiout) + struct ui_out *uiout; +{ + /* FIXME: not implemented yet */ + return 0; +} + +#if 0 +void +ui_out_result_begin (uiout, class) + struct ui_out *uiout; + char *class; +{ +} + +void +ui_out_result_end (uiout) + struct ui_out *uiout; +{ +} + +void +ui_out_info_begin (uiout, class) + struct ui_out *uiout; + char *class; +{ +} + +void +ui_out_info_end (uiout) + struct ui_out *uiout; +{ +} + +void +ui_out_notify_begin (uiout, class) + struct ui_out *uiout; + char *class; +{ +} + +void +ui_out_notify_end (uiout) + struct ui_out *uiout; +{ +} + +void +ui_out_error_begin (uiout, class) + struct ui_out *uiout; + char *class; +{ +} + +void +ui_out_error_end (uiout) + struct ui_out *uiout; +{ +} +#endif + +#if 0 +void +gdb_error (ui_out * uiout, int severity, char *format,...) +{ + va_list args; +} + +void +gdb_query (uiout, qflags, qprompt) + struct ui_out *uiout; + int flags; + char *qprompt; +{ +} +#endif + +/* default gdb-out hook functions */ + +static void +default_table_begin (uiout, nbrofcols, tblid) + struct ui_out *uiout; + int nbrofcols; + char *tblid; +{ +} + +static void +default_table_body (uiout) + struct ui_out *uiout; +{ +} + +static void +default_table_end (uiout) + struct ui_out *uiout; +{ +} + +static void +default_table_header (uiout, width, alignment, colhdr) + struct ui_out *uiout; + int width; + enum ui_align alignment; + char *colhdr; +{ +} + +static void +default_list_begin (uiout, list_flag, lstid) + struct ui_out *uiout; + int list_flag; + char *lstid; +{ +} + +static void +default_list_end (uiout, list_flag) + struct ui_out *uiout; + int list_flag; +{ +} + +static void +default_field_int (uiout, fldno, width, align, fldname, value) + struct ui_out *uiout; + int fldno; + int width; + enum ui_align align; + char *fldname; + int value; +{ +} + +static void +default_field_skip (uiout, fldno, width, align, fldname) + struct ui_out *uiout; + int fldno; + int width; + enum ui_align align; + char *fldname; +{ +} + +static void +default_field_string (struct ui_out *uiout, + int fldno, + int width, + enum ui_align align, + char *fldname, + const char *string) +{ +} + +static void +default_field_fmt (uiout, fldno, width, align, fldname, format, args) + struct ui_out *uiout; + int fldno; + int width; + enum ui_align align; + char *fldname; + char *format; + va_list args; +{ +} + +static void +default_spaces (uiout, numspaces) + struct ui_out *uiout; + int numspaces; +{ +} + +static void +default_text (uiout, string) + struct ui_out *uiout; + char *string; +{ +} + +static void +default_message (uiout, verbosity, format, args) + struct ui_out *uiout; + int verbosity; + char *format; + va_list args; +{ +} + +static void +default_wrap_hint (uiout, identstring) + struct ui_out *uiout; + char *identstring; +{ +} + +static void +default_flush (uiout) + struct ui_out *uiout; +{ +} + +/* Interface to the implementation functions */ + +void +uo_table_begin (struct ui_out *uiout, int nbrofcols, char *tblid) +{ + if (!uiout->impl->table_begin) + return; + uiout->impl->table_begin (uiout, nbrofcols, tblid); +} + +void +uo_table_body (struct ui_out *uiout) +{ + if (!uiout->impl->table_body) + return; + uiout->impl->table_body (uiout); +} + +void +uo_table_end (struct ui_out *uiout) +{ + if (!uiout->impl->table_end) + return; + uiout->impl->table_end (uiout); +} + +void +uo_table_header (struct ui_out *uiout, int width, enum ui_align align, char *colhdr) +{ + if (!uiout->impl->table_header) + return; + uiout->impl->table_header (uiout, width, align, colhdr); +} + +void +uo_list_begin (struct ui_out *uiout, int list_flag, char *lstid) +{ + if (!uiout->impl->list_begin) + return; + uiout->impl->list_begin (uiout, list_flag, lstid); +} + +void +uo_list_end (struct ui_out *uiout, int list_flag) +{ + if (!uiout->impl->list_end) + return; + uiout->impl->list_end (uiout, list_flag); +} + +void +uo_field_int (struct ui_out *uiout, int fldno, int width, enum ui_align align, char *fldname, int value) +{ + if (!uiout->impl->field_int) + return; + uiout->impl->field_int (uiout, fldno, width, align, fldname, value); +} + +void +uo_field_skip (struct ui_out *uiout, int fldno, int width, enum ui_align align, char *fldname) +{ + if (!uiout->impl->field_skip) + return; + uiout->impl->field_skip (uiout, fldno, width, align, fldname); +} + +void +uo_field_string (struct ui_out *uiout, int fldno, int width, + enum ui_align align, char *fldname, const char *string) +{ + if (!uiout->impl->field_string) + return; + uiout->impl->field_string (uiout, fldno, width, align, fldname, string); +} + +void +uo_field_fmt (struct ui_out *uiout, int fldno, int width, enum ui_align align, char *fldname, char *format, va_list args) +{ + if (!uiout->impl->field_fmt) + return; + uiout->impl->field_fmt (uiout, fldno, width, align, fldname, format, args); +} + +void +uo_spaces (struct ui_out *uiout, int numspaces) +{ + if (!uiout->impl->spaces) + return; + uiout->impl->spaces (uiout, numspaces); +} + +void +uo_text (struct ui_out *uiout, char *string) +{ + if (!uiout->impl->text) + return; + uiout->impl->text (uiout, string); +} + +void +uo_message (struct ui_out *uiout, int verbosity, char *format, va_list args) +{ + if (!uiout->impl->message) + return; + uiout->impl->message (uiout, verbosity, format, args); +} + +void +uo_wrap_hint (struct ui_out *uiout, char *identstring) +{ + if (!uiout->impl->wrap_hint) + return; + uiout->impl->wrap_hint (uiout, identstring); +} + +void +uo_flush (struct ui_out *uiout) +{ + if (!uiout->impl->flush) + return; + uiout->impl->flush (uiout); +} + +/* local functions */ + +/* list of column headers manipulation routines */ + +static void +clear_header_list (uiout) + struct ui_out *uiout; +{ + while (uiout->headerfirst != NULL) + { + uiout->headercurr = uiout->headerfirst; + uiout->headerfirst = uiout->headerfirst->next; + if (uiout->headercurr->colhdr != NULL) + free (uiout->headercurr->colhdr); + free (uiout->headercurr); + } + uiout->headerlast = NULL; + uiout->headercurr = NULL; +} + +static void +append_header_to_list (struct ui_out *uiout, + int width, + int alignment, + char *colhdr) +{ + struct ui_out_hdr *temphdr; + + temphdr = XMALLOC (struct ui_out_hdr); + temphdr->width = width; + temphdr->alignment = alignment; + /* we have to copy the column title as the original may be an automatic */ + if (colhdr != NULL) + { + temphdr->colhdr = xmalloc (strlen (colhdr) + 1); + strcpy (temphdr->colhdr, colhdr); + } + temphdr->next = NULL; + if (uiout->headerfirst == NULL) + { + temphdr->colno = 1; + uiout->headerfirst = temphdr; + uiout->headerlast = temphdr; + } + else + { + temphdr->colno = uiout->headerlast->colno + 1; + uiout->headerlast->next = temphdr; + uiout->headerlast = temphdr; + } + uiout->headercurr = uiout->headerlast; +} + +/* returns 0 if there is no more headers */ + +static int +get_curr_header (struct ui_out *uiout, + int *colno, + int *width, + int *alignment, + char **colhdr) +{ + /* There may be no headers at all or we may have used all columns */ + if (uiout->headercurr == NULL) + return 0; + *colno = uiout->headercurr->colno; + *width = uiout->headercurr->width; + *alignment = uiout->headercurr->alignment; + *colhdr = uiout->headercurr->colhdr; + uiout->headercurr = uiout->headercurr->next; + return 1; +} + +/* makes sure the field_* calls were properly placed */ + +static void +verify_field_proper_position (struct ui_out *uiout) +{ + if (uiout->table_flag) + { + if (!uiout->body_flag) + internal_error ("ui_out: table_body missing; table fields must be \ +specified after table_body and inside a list."); + if (!uiout->list_flag) + internal_error ("ui_out: list_begin missing; table fields must be \ +specified after table_body and inside a list."); + } +} + +/* determines what is the alignment policy */ + +static void +verify_field_alignment (struct ui_out *uiout, + int fldno, + int *width, + int *align) +{ + int colno; + char *text; + + if (uiout->table_flag + && get_curr_header (uiout, &colno, width, align, &text)) + { + if (fldno != colno) + internal_error ("gdb/ui-out.c: ui-out internal error in handling headers."); + } + else + { + *width = 0; + *align = ui_noalign; + } +} + +/* access to ui_out format private members */ + +void +ui_out_get_field_separator (uiout) + struct ui_out *uiout; +{ +} + +/* Access to ui-out members data */ + +struct ui_out_data * +ui_out_data (struct ui_out *uiout) +{ + return uiout->data; +} + +/* initalize private members at startup */ + +struct ui_out * +ui_out_new (struct ui_out_impl *impl, + struct ui_out_data *data, + int flags) +{ + struct ui_out *uiout = XMALLOC (struct ui_out); + uiout->data = data; + uiout->impl = impl; + uiout->flags = flags; + uiout->table_flag = 0; + uiout->body_flag = 0; + uiout->list_flag = 0; + uiout->field_count[0] = 0; + uiout->headerfirst = NULL; + uiout->headerlast = NULL; + uiout->headercurr = NULL; + return uiout; +} + +/* standard gdb initialization hook */ + +void +_initialize_ui_out () +{ + /* nothing needs to be done */ +} diff --git a/gdb/ui-out.h b/gdb/ui-out.h new file mode 100644 index 00000000000..d8db5885457 --- /dev/null +++ b/gdb/ui-out.h @@ -0,0 +1,221 @@ +/* Output generating routines for GDB. + Copyright 1999, 2000 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + Written by Fernando Nasser for Cygnus. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef UI_OUT_H +#define UI_OUT_H 1 + +/* The ui_out structure */ + +#if __STDC__ +struct ui_out; +struct ui_out_data; +#endif + + +/* the current ui_out */ + +/* FIXME: This should not be a global but something passed down from main.c + or top.c */ +extern struct ui_out *uiout; + +/* alignment enum */ +enum ui_align + { + ui_left = -1, + ui_center, + ui_right, + ui_noalign + }; + +/* flags enum */ +enum ui_flags + { + ui_from_tty = 1, + ui_source_list = 2 + }; + + +/* The ui_out stream structure. */ +/* NOTE: cagney/2000-02-01: The ui_stream object can be subsumed by + the more generic ui_file object. */ + +struct ui_stream + { + struct ui_out *uiout; + struct ui_file *stream; + }; + + +/* Prototypes for ui-out API. */ + +extern void ui_out_table_begin PARAMS ((struct ui_out * uiout, int nbrofcols, + char *tblid)); + +extern void ui_out_table_header PARAMS ((struct ui_out * uiout, int width, + enum ui_align align, char *colhdr)); + +extern void ui_out_table_body PARAMS ((struct ui_out * uiout)); + +extern void ui_out_table_end PARAMS ((struct ui_out * uiout)); + +extern void ui_out_list_begin PARAMS ((struct ui_out * uiout, char *lstid)); + +extern void ui_out_list_end PARAMS ((struct ui_out * uiout)); + +extern void ui_out_field_int PARAMS ((struct ui_out * uiout, char *fldname, + int value)); + +extern void ui_out_field_core_addr PARAMS ((struct ui_out * uiout, char *fldname, + CORE_ADDR address)); + +extern void ui_out_field_string (struct ui_out * uiout, char *fldname, + const char *string); + +extern void ui_out_field_stream PARAMS ((struct ui_out * uiout, char *fldname, + struct ui_stream * buf)); + +extern void ui_out_field_fmt PARAMS ((struct ui_out * uiout, char *fldname, + char *format,...)); + +extern void ui_out_field_skip PARAMS ((struct ui_out * uiout, char *fldname)); + +extern void ui_out_spaces PARAMS ((struct ui_out * uiout, int numspaces)); + +extern void ui_out_text PARAMS ((struct ui_out * uiout, char *string)); + +extern void ui_out_message PARAMS ((struct ui_out * uiout, int verbosity, + char *format,...)); + +extern struct ui_stream *ui_out_stream_new PARAMS ((struct ui_out * uiout)); + +extern void ui_out_stream_delete PARAMS ((struct ui_stream * buf)); + +struct cleanup *make_cleanup_ui_out_stream_delete (struct ui_stream *buf); + +extern void ui_out_wrap_hint PARAMS ((struct ui_out * uiout, char *identstring)); + +extern void ui_out_flush PARAMS ((struct ui_out * uiout)); + +extern void ui_out_get_field_separator PARAMS ((struct ui_out * uiout)); + +extern int ui_out_set_flags PARAMS ((struct ui_out * uiout, int mask)); + +extern int ui_out_clear_flags PARAMS ((struct ui_out * uiout, int mask)); + +extern int ui_out_get_verblvl PARAMS ((struct ui_out * uiout)); + +extern int ui_out_test_flags (struct ui_out *uiout, int mask); + +#if 0 +extern void ui_out_result_begin PARAMS ((struct ui_out * uiout, char *class)); + +extern void ui_out_result_end PARAMS ((struct ui_out * uiout)); + +extern void ui_out_info_begin PARAMS ((struct ui_out * uiout, char *class)); + +extern void ui_out_info_end PARAMS ((struct ui_out * uiout)); + +extern void ui_out_notify_begin PARAMS ((struct ui_out * uiout, char *class)); + +extern void ui_out_notify_end PARAMS ((struct ui_out * uiout)); + +extern void ui_out_error_begin PARAMS ((struct ui_out * uiout, char *class)); + +extern void ui_out_error_end PARAMS ((struct ui_out * uiout)); +#endif + +#if 0 +extern void gdb_error PARAMS ((struct ui_out * uiout, int severity, + char *format,...)); + +extern void gdb_query PARAMS ((struct ui_out * uiout, + int qflags, char *qprompt)); +#endif + +/* From here on we have things that are only needed by implementation + routines and main.c. We should pehaps have a separate file for that, + like a ui-out-impl.h file */ + +/* User Interface Output Implementation Function Table */ + +/* Type definition of all implementation functions. */ + +typedef void (table_begin_ftype) (struct ui_out * uiout, + int nbrofcols, char *tblid); +typedef void (table_body_ftype) (struct ui_out * uiout); +typedef void (table_end_ftype) (struct ui_out * uiout); +typedef void (table_header_ftype) (struct ui_out * uiout, int width, + enum ui_align align, char *colhdr); +typedef void (list_begin_ftype) (struct ui_out * uiout, + int list_flag, char *lstid); +typedef void (list_end_ftype) (struct ui_out * uiout, int list_flag); +typedef void (field_int_ftype) (struct ui_out * uiout, int fldno, int width, + enum ui_align align, char *fldname, int value); +typedef void (field_skip_ftype) (struct ui_out * uiout, int fldno, int width, + enum ui_align align, char *fldname); +typedef void (field_string_ftype) (struct ui_out * uiout, int fldno, int width, + enum ui_align align, char *fldname, + const char *string); +typedef void (field_fmt_ftype) (struct ui_out * uiout, int fldno, int width, + enum ui_align align, char *fldname, + char *format, va_list args); +typedef void (spaces_ftype) (struct ui_out * uiout, int numspaces); +typedef void (text_ftype) (struct ui_out * uiout, char *string); +typedef void (message_ftype) (struct ui_out * uiout, int verbosity, + char *format, va_list args); +typedef void (wrap_hint_ftype) (struct ui_out * uiout, char *identstring); +typedef void (flush_ftype) (struct ui_out * uiout); + +/* ui-out-impl */ + +/* IMPORTANT: If you change this structure, make sure to change the default + initialization in ui-out.c */ + +struct ui_out_impl + { + table_begin_ftype *table_begin; + table_body_ftype *table_body; + table_end_ftype *table_end; + table_header_ftype *table_header; + list_begin_ftype *list_begin; + list_end_ftype *list_end; + field_int_ftype *field_int; + field_skip_ftype *field_skip; + field_string_ftype *field_string; + field_fmt_ftype *field_fmt; + spaces_ftype *spaces; + text_ftype *text; + message_ftype *message; + wrap_hint_ftype *wrap_hint; + flush_ftype *flush; + }; + +extern struct ui_out_data *ui_out_data (struct ui_out *uiout); + + +/* Create a ui_out object */ + +extern struct ui_out *ui_out_new (struct ui_out_impl *impl, + struct ui_out_data *data, + int flags); + +#endif /* UI_OUT_H */ diff --git a/gdb/varobj.c b/gdb/varobj.c new file mode 100644 index 00000000000..f0740c69672 --- /dev/null +++ b/gdb/varobj.c @@ -0,0 +1,2421 @@ +/* Implementation of the GDB variable objects API. + Copyright 1999, 2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "value.h" +#include "expression.h" +#include "frame.h" +#include "valprint.h" +#include "language.h" +#include "wrapper.h" +#include "gdbcmd.h" +#include <math.h> + +#include "varobj.h" + +/* Non-zero if we want to see trace of varobj level stuff. */ + +int varobjdebug = 0; + +/* String representations of gdb's format codes */ +char *varobj_format_string[] = +{"natural", "binary", "decimal", "hexadecimal", "octal"}; + +/* String representations of gdb's known languages */ +char *varobj_language_string[] = +{"unknown", "C", "C++", "Java"}; + +/* Data structures */ + +/* Every root variable has one of these structures saved in its + varobj. Members which must be free'd are noted. */ +struct varobj_root + { + + /* Alloc'd expression for this parent. */ + struct expression *exp; + + /* Block for which this expression is valid */ + struct block *valid_block; + + /* The frame for this expression */ + CORE_ADDR frame; + + /* Language info for this variable and its children */ + struct language_specific *lang; + + /* The varobj for this root node. */ + struct varobj *rootvar; + + /* Next root variable */ + struct varobj_root *next; + }; + +/* Every variable in the system has a structure of this type defined + for it. This structure holds all information necessary to manipulate + a particular object variable. Members which must be freed are noted. */ +struct varobj + { + + /* Alloc'd name of the variable for this object.. If this variable is a + child, then this name will be the child's source name. + (bar, not foo.bar) */ + /* NOTE: This is the "expression" */ + char *name; + + /* The alloc'd name for this variable's object. This is here for + convenience when constructing this object's children. */ + char *obj_name; + + /* Index of this variable in its parent or -1 */ + int index; + + /* The type of this variable. This may NEVER be NULL. */ + struct type *type; + + /* The value of this expression or subexpression. This may be NULL. */ + value_ptr value; + + /* Did an error occur evaluating the expression or getting its value? */ + int error; + + /* The number of (immediate) children this variable has */ + int num_children; + + /* If this object is a child, this points to its immediate parent. */ + struct varobj *parent; + + /* A list of this object's children */ + struct varobj_child *children; + + /* Description of the root variable. Points to root variable for children. */ + struct varobj_root *root; + + /* The format of the output for this object */ + enum varobj_display_formats format; + }; + +/* Every variable keeps a linked list of its children, described + by the following structure. */ +/* FIXME: Deprecated. All should use vlist instead */ + +struct varobj_child + { + + /* Pointer to the child's data */ + struct varobj *child; + + /* Pointer to the next child */ + struct varobj_child *next; + }; + +/* A stack of varobjs */ +/* FIXME: Deprecated. All should use vlist instead */ + +struct vstack + { + struct varobj *var; + struct vstack *next; + }; + +struct cpstack + { + char *name; + struct cpstack *next; + }; + +/* A list of varobjs */ + +struct vlist + { + struct varobj *var; + struct vlist *next; + }; + +/* Private function prototypes */ + +/* Helper functions for the above subcommands. */ + +static int delete_variable PARAMS ((struct cpstack **, struct varobj *, int)); + +static void delete_variable_1 PARAMS ((struct cpstack **, int *, + struct varobj *, int, int)); + +static int install_variable PARAMS ((struct varobj *)); + +static void uninstall_variable PARAMS ((struct varobj *)); + +static struct varobj *child_exists PARAMS ((struct varobj *, char *)); + +static struct varobj *create_child PARAMS ((struct varobj *, int, char *)); + +static void save_child_in_parent PARAMS ((struct varobj *, struct varobj *)); + +static void remove_child_from_parent PARAMS ((struct varobj *, struct varobj *)); + +/* Utility routines */ + +static struct varobj *new_variable PARAMS ((void)); + +static struct varobj *new_root_variable PARAMS ((void)); + +static void free_variable PARAMS ((struct varobj * var)); + +static struct type *get_type PARAMS ((struct varobj * var)); + +static struct type *get_type_deref PARAMS ((struct varobj * var)); + +static struct type *get_target_type PARAMS ((struct type *)); + +static enum varobj_display_formats variable_default_display PARAMS ((struct varobj *)); + +static int my_value_equal PARAMS ((value_ptr, value_ptr, int *)); + +static void vpush PARAMS ((struct vstack ** pstack, struct varobj * var)); + +static struct varobj *vpop PARAMS ((struct vstack ** pstack)); + +static void cppush PARAMS ((struct cpstack ** pstack, char *name)); + +static char *cppop PARAMS ((struct cpstack ** pstack)); + +/* Language-specific routines. */ + +static enum varobj_languages variable_language PARAMS ((struct varobj * var)); + +static int number_of_children PARAMS ((struct varobj *)); + +static char *name_of_variable PARAMS ((struct varobj *)); + +static char *name_of_child PARAMS ((struct varobj *, int)); + +static value_ptr value_of_root PARAMS ((struct varobj * var)); + +static value_ptr value_of_child PARAMS ((struct varobj * parent, int index)); + +static struct type *type_of_child PARAMS ((struct varobj * var)); + +static int variable_editable PARAMS ((struct varobj * var)); + +static char *my_value_of_variable PARAMS ((struct varobj * var)); + +static int type_changeable PARAMS ((struct varobj * var)); + +/* C implementation */ + +static int c_number_of_children PARAMS ((struct varobj * var)); + +static char *c_name_of_variable PARAMS ((struct varobj * parent)); + +static char *c_name_of_child PARAMS ((struct varobj * parent, int index)); + +static value_ptr c_value_of_root PARAMS ((struct varobj * var)); + +static value_ptr c_value_of_child PARAMS ((struct varobj * parent, int index)); + +static struct type *c_type_of_child PARAMS ((struct varobj * parent, int index)); + +static int c_variable_editable PARAMS ((struct varobj * var)); + +static char *c_value_of_variable PARAMS ((struct varobj * var)); + +/* C++ implementation */ + +static int cplus_number_of_children PARAMS ((struct varobj * var)); + +static void cplus_class_num_children PARAMS ((struct type * type, int children[3])); + +static char *cplus_name_of_variable PARAMS ((struct varobj * parent)); + +static char *cplus_name_of_child PARAMS ((struct varobj * parent, int index)); + +static value_ptr cplus_value_of_root PARAMS ((struct varobj * var)); + +static value_ptr cplus_value_of_child PARAMS ((struct varobj * parent, int index)); + +static struct type *cplus_type_of_child PARAMS ((struct varobj * parent, int index)); + +static int cplus_variable_editable PARAMS ((struct varobj * var)); + +static char *cplus_value_of_variable PARAMS ((struct varobj * var)); + +/* Java implementation */ + +static int java_number_of_children PARAMS ((struct varobj * var)); + +static char *java_name_of_variable PARAMS ((struct varobj * parent)); + +static char *java_name_of_child PARAMS ((struct varobj * parent, int index)); + +static value_ptr java_value_of_root PARAMS ((struct varobj * var)); + +static value_ptr java_value_of_child PARAMS ((struct varobj * parent, int index)); + +static struct type *java_type_of_child PARAMS ((struct varobj * parent, int index)); + +static int java_variable_editable PARAMS ((struct varobj * var)); + +static char *java_value_of_variable PARAMS ((struct varobj * var)); + +/* The language specific vector */ + +struct language_specific + { + + /* The language of this variable */ + enum varobj_languages language; + + /* The number of children of PARENT. */ + int (*number_of_children) PARAMS ((struct varobj * parent)); + + /* The name (expression) of a root varobj. */ + char *(*name_of_variable) PARAMS ((struct varobj * parent)); + + /* The name of the INDEX'th child of PARENT. */ + char *(*name_of_child) PARAMS ((struct varobj * parent, int index)); + + /* The value_ptr of the root variable ROOT. */ + value_ptr (*value_of_root) PARAMS ((struct varobj * root)); + + /* The value_ptr of the INDEX'th child of PARENT. */ + value_ptr (*value_of_child) PARAMS ((struct varobj * parent, int index)); + + /* The type of the INDEX'th child of PARENT. */ + struct type *(*type_of_child) PARAMS ((struct varobj * parent, int index)); + + /* Is VAR editable? */ + int (*variable_editable) PARAMS ((struct varobj * var)); + + /* The current value of VAR. */ + char *(*value_of_variable) PARAMS ((struct varobj * var)); + }; + +/* Array of known source language routines. */ +static struct language_specific + languages[vlang_end][sizeof (struct language_specific)] = +{ + /* Unknown (try treating as C */ + { + vlang_unknown, + c_number_of_children, + c_name_of_variable, + c_name_of_child, + c_value_of_root, + c_value_of_child, + c_type_of_child, + c_variable_editable, + c_value_of_variable + } + , + /* C */ + { + vlang_c, + c_number_of_children, + c_name_of_variable, + c_name_of_child, + c_value_of_root, + c_value_of_child, + c_type_of_child, + c_variable_editable, + c_value_of_variable + } + , + /* C++ */ + { + vlang_cplus, + cplus_number_of_children, + cplus_name_of_variable, + cplus_name_of_child, + cplus_value_of_root, + cplus_value_of_child, + cplus_type_of_child, + cplus_variable_editable, + cplus_value_of_variable + } + , + /* Java */ + { + vlang_java, + java_number_of_children, + java_name_of_variable, + java_name_of_child, + java_value_of_root, + java_value_of_child, + java_type_of_child, + java_variable_editable, + java_value_of_variable + } +}; + +/* A little convenience enum for dealing with C++/Java */ +enum vsections + { + v_public = 0, v_private, v_protected + }; + +/* Private data */ + +/* Mappings of varobj_display_formats enums to gdb's format codes */ +static int format_code[] = +{0, 't', 'd', 'x', 'o'}; + +/* Header of the list of root variable objects */ +static struct varobj_root *rootlist; +static int rootcount = 0; /* number of root varobjs in the list */ + +/* Prime number indicating the number of buckets in the hash table */ +/* A prime large enough to avoid too many colisions */ +#define VAROBJ_TABLE_SIZE 227 + +/* Pointer to the varobj hash table (built at run time) */ +static struct vlist **varobj_table; + +#if defined(FREEIF) +#undef FREEIF +#endif +#define FREEIF(x) if (x != NULL) free((char *) (x)) + +/* Is the variable X one of our "fake" children? */ +#define CPLUS_FAKE_CHILD(x) \ +((x) != NULL && (x)->type == NULL && (x)->value == NULL) + + +/* API Implementation */ + +/* Creates a varobj (not its children) */ + +struct varobj * +varobj_create (char *objname, + char *expression, CORE_ADDR frame) +{ + struct varobj *var; + struct frame_info *fi, *old_fi; + struct block *block; + struct cleanup *old_chain; + + /* Fill out a varobj structure for the (root) variable being constructed. */ + var = new_root_variable (); + old_chain = make_cleanup ((make_cleanup_func) free_variable, var); + + if (expression != NULL) + { + char *p; + enum varobj_languages lang; + + /* Parse and evaluate the expression, filling in as much + of the variable's data as possible */ + + /* Allow creator to specify context of variable */ + if (frame == (CORE_ADDR) -1) + fi = selected_frame; + else + fi = find_frame_addr_in_frame_chain (frame); + + block = NULL; + if (fi != NULL) + block = get_frame_block (fi); + + p = expression; + innermost_block = NULL; + /* Callee may longjump */ + var->root->exp = parse_exp_1 (&p, block, 0); + + /* Don't allow variables to be created for types. */ + if (var->root->exp->elts[0].opcode == OP_TYPE) + { + do_cleanups (old_chain); + fprintf_unfiltered (gdb_stderr, + "Attempt to use a type name as an expression."); + return NULL; + } + + var->format = variable_default_display (var); + var->root->valid_block = innermost_block; + var->name = savestring (expression, strlen (expression)); + + /* When the frame is different from the current frame, + we must select the appropriate frame before parsing + the expression, otherwise the value will not be current. + Since select_frame is so benign, just call it for all cases. */ + if (fi != NULL) + { + var->root->frame = FRAME_FP (fi); + old_fi = selected_frame; + select_frame (fi, -1); + } + + /* We definitively need to catch errors here. + If evaluate_expression succeeds we got the value we wanted. + But if it fails, we still go on with a call to evaluate_type() */ + if (gdb_evaluate_expression (var->root->exp, &var->value)) + { + /* no error */ + release_value (var->value); + if (VALUE_LAZY (var->value)) + gdb_value_fetch_lazy (var->value); + } + else + var->value = evaluate_type (var->root->exp); + + var->type = VALUE_TYPE (var->value); + + /* Set language info */ + lang = variable_language (var); + var->root->lang = languages[lang]; + + /* Set ourselves as our root */ + var->root->rootvar = var; + + /* Reset the selected frame */ + if (fi != NULL) + select_frame (old_fi, -1); + } + + if (var != NULL) + { + var->obj_name = savestring (objname, strlen (objname)); + + /* If a varobj name is duplicated, the install will fail so + we must clenup */ + if (!install_variable (var)) + { + do_cleanups (old_chain); + return NULL; + } + } + + discard_cleanups (old_chain); + return var; +} + +/* Generates an unique name that can be used for a varobj */ + +char * +varobj_gen_name (void) +{ + static int id = 0; + char obj_name[31]; + + /* generate a name for this object */ + id++; + sprintf (obj_name, "var%d", id); + + return xstrdup (obj_name); +} + +/* Given an "objname", returns the pointer to the corresponding varobj + or NULL if not found */ + +struct varobj * +varobj_get_handle (char *objname) +{ + struct vlist *cv; + const char *chp; + unsigned int index = 0; + unsigned int i = 1; + + for (chp = objname; *chp; chp++) + { + index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE; + } + + cv = *(varobj_table + index); + while ((cv != NULL) && (strcmp (cv->var->obj_name, objname) != 0)) + cv = cv->next; + + if (cv == NULL) + error ("Variable object not found"); + + return cv->var; +} + +/* Given the handle, return the name of the object */ + +char * +varobj_get_objname (struct varobj *var) +{ + return var->obj_name; +} + +/* Given the handle, return the expression represented by the object */ + +char * +varobj_get_expression (struct varobj *var) +{ + return name_of_variable (var); +} + +/* Deletes a varobj and all its children if only_children == 0, + otherwise deletes only the children; returns a malloc'ed list of all the + (malloc'ed) names of the variables that have been deleted (NULL terminated) */ + +int +varobj_delete (struct varobj *var, char ***dellist, int only_children) +{ + int delcount; + int mycount; + struct cpstack *result = NULL; + char **cp; + + /* Initialize a stack for temporary results */ + cppush (&result, NULL); + + if (only_children) + /* Delete only the variable children */ + delcount = delete_variable (&result, var, 1 /* only the children */ ); + else + /* Delete the variable and all its children */ + delcount = delete_variable (&result, var, 0 /* parent+children */ ); + + /* We may have been asked to return a list of what has been deleted */ + if (dellist != NULL) + { + *dellist = xmalloc ((delcount + 1) * sizeof (char *)); + + cp = *dellist; + mycount = delcount; + *cp = cppop (&result); + while ((*cp != NULL) && (mycount > 0)) + { + mycount--; + cp++; + *cp = cppop (&result); + } + + if (mycount || (*cp != NULL)) + warning ("varobj_delete: assertion failed - mycount(=%d) <> 0", mycount); + } + + return delcount; +} + +/* Set/Get variable object display format */ + +enum varobj_display_formats +varobj_set_display_format (struct varobj *var, + enum varobj_display_formats format) +{ + switch (format) + { + case FORMAT_NATURAL: + case FORMAT_BINARY: + case FORMAT_DECIMAL: + case FORMAT_HEXADECIMAL: + case FORMAT_OCTAL: + var->format = format; + break; + + default: + var->format = variable_default_display (var); + } + + return var->format; +} + +enum varobj_display_formats +varobj_get_display_format (struct varobj *var) +{ + return var->format; +} + +int +varobj_get_num_children (struct varobj *var) +{ + if (var->num_children == -1) + var->num_children = number_of_children (var); + + return var->num_children; +} + +/* Creates a list of the immediate children of a variable object; + the return code is the number of such children or -1 on error */ + +int +varobj_list_children (struct varobj *var, struct varobj ***childlist) +{ + struct varobj *child; + char *name; + int i; + + /* sanity check: have we been passed a pointer? */ + if (childlist == NULL) + return -1; + + *childlist = NULL; + + if (var->num_children == -1) + var->num_children = number_of_children (var); + + /* List of children */ + *childlist = xmalloc ((var->num_children + 1) * sizeof (struct varobj *)); + + for (i = 0; i < var->num_children; i++) + { + /* Mark as the end in case we bail out */ + *((*childlist) + i) = NULL; + + /* check if child exists, if not create */ + name = name_of_child (var, i); + child = child_exists (var, name); + if (child == NULL) + child = create_child (var, i, name); + + *((*childlist) + i) = child; + } + + /* End of list is marked by a NULL pointer */ + *((*childlist) + i) = NULL; + + return var->num_children; +} + +/* Obtain the type of an object Variable as a string similar to the one gdb + prints on the console */ + +char * +varobj_get_type (struct varobj *var) +{ + value_ptr val; + struct cleanup *old_chain; + struct ui_file *stb; + char *thetype; + long length; + + /* For the "fake" variables, do not return a type. (It's type is + NULL, too.) */ + if (CPLUS_FAKE_CHILD (var)) + return NULL; + + stb = mem_fileopen (); + old_chain = make_cleanup_ui_file_delete (stb); + + /* To print the type, we simply create a zero value_ptr and + cast it to our type. We then typeprint this variable. */ + val = value_zero (var->type, not_lval); + type_print (VALUE_TYPE (val), "", stb, -1); + + thetype = ui_file_xstrdup (stb, &length); + do_cleanups (old_chain); + return thetype; +} + +enum varobj_languages +varobj_get_language (struct varobj *var) +{ + return variable_language (var); +} + +int +varobj_get_attributes (struct varobj *var) +{ + int attributes = 0; + + if (variable_editable (var)) + /* FIXME: define masks for attributes */ + attributes |= 0x00000001; /* Editable */ + + return attributes; +} + +char * +varobj_get_value (struct varobj *var) +{ + return my_value_of_variable (var); +} + +/* Set the value of an object variable (if it is editable) to the + value of the given expression */ +/* Note: Invokes functions that can call error() */ + +int +varobj_set_value (struct varobj *var, char *expression) +{ + value_ptr val; + int offset = 0; + + /* The argument "expression" contains the variable's new value. + We need to first construct a legal expression for this -- ugh! */ + /* Does this cover all the bases? */ + struct expression *exp; + value_ptr value; + int saved_input_radix = input_radix; + + if (variable_editable (var) && !var->error) + { + char *s = expression; + int i; + value_ptr temp; + + input_radix = 10; /* ALWAYS reset to decimal temporarily */ + /* FIXME: Callee may longjump */ + exp = parse_exp_1 (&s, 0, 0); + if (!gdb_evaluate_expression (exp, &value)) + { + /* We cannot proceed without a valid expression. */ + FREEIF (exp); + return 0; + } + + /* If our parent is "public", "private", or "protected", we could + be asking to modify the value of a baseclass. If so, we need to + adjust our address by the offset of our baseclass in the subclass, + since VALUE_ADDRESS (var->value) points at the start of the subclass. + For some reason, value_cast doesn't take care of this properly. */ + temp = var->value; + if (var->parent != NULL && CPLUS_FAKE_CHILD (var->parent)) + { + struct varobj *super, *sub; + struct type *type; + super = var->parent->parent; + sub = super->parent; + if (sub != NULL) + { + /* Yes, it is a baseclass */ + type = get_type_deref (sub); + + if (super->index < TYPE_N_BASECLASSES (type)) + { + temp = value_copy (var->value); + for (i = 0; i < super->index; i++) + offset += TYPE_LENGTH (TYPE_FIELD_TYPE (type, i)); + } + } + } + + VALUE_ADDRESS (temp) += offset; + val = value_assign (temp, value); + VALUE_ADDRESS (val) -= offset; + value_free (var->value); + release_value (val); + var->value = val; + input_radix = saved_input_radix; + return 1; + } + + return 0; +} + +/* Returns a malloc'ed list with all root variable objects */ +int +varobj_list (struct varobj ***varlist) +{ + struct varobj **cv; + struct varobj_root *croot; + int mycount = rootcount; + + /* Alloc (rootcount + 1) entries for the result */ + *varlist = xmalloc ((rootcount + 1) * sizeof (struct varobj *)); + + cv = *varlist; + croot = rootlist; + while ((croot != NULL) && (mycount > 0)) + { + *cv = croot->rootvar; + mycount--; + cv++; + croot = croot->next; + } + /* Mark the end of the list */ + *cv = NULL; + + if (mycount || (croot != NULL)) + warning ("varobj_list: assertion failed - wrong tally of root vars (%d:%d)", + rootcount, mycount); + + return rootcount; +} + +/* Update the values for a variable and its children. This is a + two-pronged attack. First, re-parse the value for the root's + expression to see if it's changed. Then go all the way + through its children, reconstructing them and noting if they've + changed. + + Only root variables can be updated... */ + +int +varobj_update (struct varobj *var, struct varobj ***changelist) +{ + int changed = 0; + int i; + int vleft; + int error2; + struct varobj *v; + struct varobj **cv; + struct varobj **templist; + value_ptr new; + struct vstack *stack = NULL; + struct vstack *result = NULL; + struct frame_info *old_fi; + + /* sanity check: have we been passed a pointer? */ + if (changelist == NULL) + return -1; + + /* Only root variables can be updated... */ + if (var->root->rootvar != var) + /* Not a root var */ + return -1; + + /* Save the selected stack frame, since we will need to change it + in order to evaluate expressions. */ + old_fi = selected_frame; + + /* Update the root variable. value_of_root can return NULL + if the variable is no longer around, i.e. we stepped out of + the frame in which a local existed. */ + new = value_of_root (var); + if (new == NULL) + return -1; + + /* Initialize a stack for temporary results */ + vpush (&result, NULL); + + if (!my_value_equal (var->value, new, &error2)) + { + /* Note that it's changed There a couple of exceptions here, + though. We don't want some types to be reported as "changed". */ + if (type_changeable (var)) + { + vpush (&result, var); + changed++; + } + } + /* error2 replaces var->error since this new value + WILL replace the old one. */ + var->error = error2; + + /* We must always keep around the new value for this root + variable expression, or we lose the updated children! */ + value_free (var->value); + var->value = new; + + /* Initialize a stack */ + vpush (&stack, NULL); + + /* Push the root's children */ + if (var->children != NULL) + { + struct varobj_child *c; + for (c = var->children; c != NULL; c = c->next) + vpush (&stack, c->child); + } + + /* Walk through the children, reconstructing them all. */ + v = vpop (&stack); + while (v != NULL) + { + /* Push any children */ + if (v->children != NULL) + { + struct varobj_child *c; + for (c = v->children; c != NULL; c = c->next) + vpush (&stack, c->child); + } + + /* Update this variable */ + new = value_of_child (v->parent, v->index); + if (type_changeable (v) && !my_value_equal (v->value, new, &error2)) + { + /* Note that it's changed */ + vpush (&result, v); + changed++; + } + /* error2 replaces v->error since this new value + WILL replace the old one. */ + v->error = error2; + + /* We must always keep new values, since children depend on it. */ + if (v->value != NULL) + value_free (v->value); + v->value = new; + + /* Get next child */ + v = vpop (&stack); + } + + /* Alloc (changed + 1) list entries */ + /* FIXME: add a cleanup for the allocated list(s) + because one day the select_frame called below can longjump */ + *changelist = xmalloc ((changed + 1) * sizeof (struct varobj *)); + if (changed > 1) + { + templist = xmalloc ((changed + 1) * sizeof (struct varobj *)); + cv = templist; + } + else + cv = *changelist; + + /* Copy from result stack to list */ + vleft = changed; + *cv = vpop (&result); + while ((*cv != NULL) && (vleft > 0)) + { + vleft--; + cv++; + *cv = vpop (&result); + } + if (vleft) + warning ("varobj_update: assertion failed - vleft <> 0"); + + if (changed > 1) + { + /* Now we revert the order. */ + for (i=0; i < changed; i++) + *(*changelist + i) = *(templist + changed -1 - i); + *(*changelist + changed) = NULL; + } + + /* Restore selected frame */ + select_frame (old_fi, -1); + + return changed; +} + + +/* Helper functions */ + +/* + * Variable object construction/destruction + */ + +static int +delete_variable (resultp, var, only_children_p) + struct cpstack **resultp; + struct varobj *var; + int only_children_p; +{ + int delcount = 0; + + delete_variable_1 (resultp, &delcount, var, + only_children_p, 1 /* remove_from_parent_p */ ); + + return delcount; +} + +/* Delete the variable object VAR and its children */ +/* IMPORTANT NOTE: If we delete a variable which is a child + and the parent is not removed we dump core. It must be always + initially called with remove_from_parent_p set */ +static void +delete_variable_1 (resultp, delcountp, var, + only_children_p, remove_from_parent_p) + struct cpstack **resultp; + int *delcountp; + struct varobj *var; + int only_children_p; + int remove_from_parent_p; +{ + struct varobj_child *vc; + struct varobj_child *next; + + /* Delete any children of this variable, too. */ + for (vc = var->children; vc != NULL; vc = next) + { + if (!remove_from_parent_p) + vc->child->parent = NULL; + delete_variable_1 (resultp, delcountp, vc->child, 0, only_children_p); + next = vc->next; + free (vc); + } + + /* if we were called to delete only the children we are done here */ + if (only_children_p) + return; + + /* Otherwise, add it to the list of deleted ones and proceed to do so */ + if (var->obj_name == NULL) + warning ("Assertion failed: NULL var->obj_name unexpectdly found"); + else + { + cppush (resultp, strdup (var->obj_name)); + *delcountp = *delcountp + 1; + } + + /* If this variable has a parent, remove it from its parent's list */ + /* OPTIMIZATION: if the parent of this variable is also being deleted, + (as indicated by remove_from_parent_p) we don't bother doing an + expensive list search to find the element to remove when we are + discarding the list afterwards */ + if ((remove_from_parent_p) && + (var->parent != NULL)) + { + remove_child_from_parent (var->parent, var); + } + + uninstall_variable (var); + + /* Free memory associated with this variable */ + free_variable (var); +} + +/* Install the given variable VAR with the object name VAR->OBJ_NAME. */ +static int +install_variable (var) + struct varobj *var; +{ + struct vlist *cv; + struct vlist *newvl; + const char *chp; + unsigned int index = 0; + unsigned int i = 1; + + for (chp = var->obj_name; *chp; chp++) + { + index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE; + } + + cv = *(varobj_table + index); + while ((cv != NULL) && (strcmp (cv->var->obj_name, var->obj_name) != 0)) + cv = cv->next; + + if (cv != NULL) + error ("Duplicate variable object name"); + + /* Add varobj to hash table */ + newvl = xmalloc (sizeof (struct vlist)); + newvl->next = *(varobj_table + index); + newvl->var = var; + *(varobj_table + index) = newvl; + + /* If root, add varobj to root list */ + if (var->root->rootvar == var) + { + /* Add to list of root variables */ + if (rootlist == NULL) + var->root->next = NULL; + else + var->root->next = rootlist; + rootlist = var->root; + rootcount++; + } + + return 1; /* OK */ +} + +/* Unistall the object VAR. */ +static void +uninstall_variable (var) + struct varobj *var; +{ + struct vlist *cv; + struct vlist *prev; + struct varobj_root *cr; + struct varobj_root *prer; + const char *chp; + unsigned int index = 0; + unsigned int i = 1; + + /* Remove varobj from hash table */ + for (chp = var->obj_name; *chp; chp++) + { + index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE; + } + + cv = *(varobj_table + index); + prev = NULL; + while ((cv != NULL) && (strcmp (cv->var->obj_name, var->obj_name) != 0)) + { + prev = cv; + cv = cv->next; + } + + if (varobjdebug) + fprintf_unfiltered (gdb_stdlog, "Deleting %s\n", var->obj_name); + + if (cv == NULL) + { + warning ("Assertion failed: Could not find variable object \"%s\" to delete", var->obj_name); + return; + } + + if (prev == NULL) + *(varobj_table + index) = cv->next; + else + prev->next = cv->next; + + free (cv); + + /* If root, remove varobj from root list */ + if (var->root->rootvar == var) + { + /* Remove from list of root variables */ + if (rootlist == var->root) + rootlist = var->root->next; + else + { + prer = NULL; + cr = rootlist; + while ((cr != NULL) && (cr->rootvar != var)) + { + prer = cr; + cr = cr->next; + } + if (cr == NULL) + { + warning ("Assertion failed: Could not find varobj \"%s\" in root list", var->obj_name); + return; + } + if (prer == NULL) + rootlist = NULL; + else + prer->next = cr->next; + } + rootcount--; + } + +} + +/* Does a child with the name NAME exist in VAR? If so, return its data. + If not, return NULL. */ +static struct varobj * +child_exists (var, name) + struct varobj *var; /* Parent */ + char *name; /* name of child */ +{ + struct varobj_child *vc; + + for (vc = var->children; vc != NULL; vc = vc->next) + { + if (STREQ (vc->child->name, name)) + return vc->child; + } + + return NULL; +} + +/* Create and install a child of the parent of the given name */ +static struct varobj * +create_child (parent, index, name) + struct varobj *parent; + int index; + char *name; +{ + struct varobj *child; + char *childs_name; + + child = new_variable (); + + /* name is allocated by name_of_child */ + child->name = name; + child->index = index; + child->value = value_of_child (parent, index); + if (child->value == NULL || parent->error) + child->error = 1; + child->parent = parent; + child->root = parent->root; + childs_name = (char *) xmalloc ((strlen (parent->obj_name) + strlen (name) + 2) + * sizeof (char)); + sprintf (childs_name, "%s.%s", parent->obj_name, name); + child->obj_name = childs_name; + install_variable (child); + + /* Save a pointer to this child in the parent */ + save_child_in_parent (parent, child); + + /* Note the type of this child */ + child->type = type_of_child (child); + + return child; +} + +/* FIXME: This should be a generic add to list */ +/* Save CHILD in the PARENT's data. */ +static void +save_child_in_parent (parent, child) + struct varobj *parent; + struct varobj *child; +{ + struct varobj_child *vc; + + /* Insert the child at the top */ + vc = parent->children; + parent->children = + (struct varobj_child *) xmalloc (sizeof (struct varobj_child)); + + parent->children->next = vc; + parent->children->child = child; +} + +/* FIXME: This should be a generic remove from list */ +/* Remove the CHILD from the PARENT's list of children. */ +static void +remove_child_from_parent (parent, child) + struct varobj *parent; + struct varobj *child; +{ + struct varobj_child *vc, *prev; + + /* Find the child in the parent's list */ + prev = NULL; + for (vc = parent->children; vc != NULL;) + { + if (vc->child == child) + break; + prev = vc; + vc = vc->next; + } + + if (prev == NULL) + parent->children = vc->next; + else + prev->next = vc->next; + +} + + +/* + * Miscellaneous utility functions. + */ + +/* Allocate memory and initialize a new variable */ +static struct varobj * +new_variable (void) +{ + struct varobj *var; + + var = (struct varobj *) xmalloc (sizeof (struct varobj)); + var->name = NULL; + var->obj_name = NULL; + var->index = -1; + var->type = NULL; + var->value = NULL; + var->error = 0; + var->num_children = -1; + var->parent = NULL; + var->children = NULL; + var->format = 0; + var->root = NULL; + + return var; +} + +/* Allocate memory and initialize a new root variable */ +static struct varobj * +new_root_variable (void) +{ + struct varobj *var = new_variable (); + var->root = (struct varobj_root *) xmalloc (sizeof (struct varobj_root));; + var->root->lang = NULL; + var->root->exp = NULL; + var->root->valid_block = NULL; + var->root->frame = (CORE_ADDR) -1; + var->root->rootvar = NULL; + + return var; +} + +/* Free any allocated memory associated with VAR. */ +static void +free_variable (var) + struct varobj *var; +{ + /* Free the expression if this is a root variable. */ + if (var->root->rootvar == var) + { + free_current_contents ((char **) &var->root->exp); + FREEIF (var->root); + } + + FREEIF (var->name); + FREEIF (var->obj_name); + FREEIF (var); +} + +/* This returns the type of the variable. This skips past typedefs + and returns the real type of the variable. It also dereferences + pointers and references. */ +static struct type * +get_type (var) + struct varobj *var; +{ + struct type *type; + type = var->type; + + while (type != NULL && TYPE_CODE (type) == TYPE_CODE_TYPEDEF) + type = TYPE_TARGET_TYPE (type); + + return type; +} + +/* This returns the type of the variable, dereferencing pointers, too. */ +static struct type * +get_type_deref (var) + struct varobj *var; +{ + struct type *type; + + type = get_type (var); + + if (type != NULL && (TYPE_CODE (type) == TYPE_CODE_PTR + || TYPE_CODE (type) == TYPE_CODE_REF)) + type = get_target_type (type); + + return type; +} + +/* This returns the target type (or NULL) of TYPE, also skipping + past typedefs, just like get_type (). */ +static struct type * +get_target_type (type) + struct type *type; +{ + if (type != NULL) + { + type = TYPE_TARGET_TYPE (type); + while (type != NULL && TYPE_CODE (type) == TYPE_CODE_TYPEDEF) + type = TYPE_TARGET_TYPE (type); + } + + return type; +} + +/* What is the default display for this variable? We assume that + everything is "natural". Any exceptions? */ +static enum varobj_display_formats +variable_default_display (var) + struct varobj *var; +{ + return FORMAT_NATURAL; +} + +/* This function is similar to gdb's value_equal, except that this + one is "safe" -- it NEVER longjmps. It determines if the VAR's + value is the same as VAL2. */ +static int +my_value_equal (val1, val2, error2) + value_ptr val1; + value_ptr val2; + int *error2; +{ + int r, err1, err2; + + *error2 = 0; + /* Special case: NULL values. If both are null, say + they're equal. */ + if (val1 == NULL && val2 == NULL) + return 1; + else if (val1 == NULL || val2 == NULL) + return 0; + + /* This is bogus, but unfortunately necessary. We must know + exactly what caused an error -- reading val1 or val2 -- so + that we can really determine if we think that something has changed. */ + err1 = 0; + err2 = 0; + /* We do need to catch errors here because the whole purpose + is to test if value_equal() has errored */ + if (!gdb_value_equal (val1, val1, &r)) + err1 = 1; + + if (!gdb_value_equal (val2, val2, &r)) + *error2 = err2 = 1; + + if (err1 != err2) + return 0; + + if (!gdb_value_equal (val1, val2, &r)) + { + /* An error occurred, this could have happened if + either val1 or val2 errored. ERR1 and ERR2 tell + us which of these it is. If both errored, then + we assume nothing has changed. If one of them is + valid, though, then something has changed. */ + if (err1 == err2) + { + /* both the old and new values caused errors, so + we say the value did not change */ + /* This is indeterminate, though. Perhaps we should + be safe and say, yes, it changed anyway?? */ + return 1; + } + else + { + return 0; + } + } + + return r; +} + +/* FIXME: The following should be generic for any pointer */ +static void +vpush (pstack, var) + struct vstack **pstack; + struct varobj *var; +{ + struct vstack *s; + + s = (struct vstack *) xmalloc (sizeof (struct vstack)); + s->var = var; + s->next = *pstack; + *pstack = s; +} + +/* FIXME: The following should be generic for any pointer */ +static struct varobj * +vpop (pstack) + struct vstack **pstack; +{ + struct vstack *s; + struct varobj *v; + + if ((*pstack)->var == NULL && (*pstack)->next == NULL) + return NULL; + + s = *pstack; + v = s->var; + *pstack = (*pstack)->next; + free (s); + + return v; +} + +/* FIXME: The following should be generic for any pointer */ +static void +cppush (pstack, name) + struct cpstack **pstack; + char *name; +{ + struct cpstack *s; + + s = (struct cpstack *) xmalloc (sizeof (struct cpstack)); + s->name = name; + s->next = *pstack; + *pstack = s; +} + +/* FIXME: The following should be generic for any pointer */ +static char * +cppop (pstack) + struct cpstack **pstack; +{ + struct cpstack *s; + char *v; + + if ((*pstack)->name == NULL && (*pstack)->next == NULL) + return NULL; + + s = *pstack; + v = s->name; + *pstack = (*pstack)->next; + free (s); + + return v; +} + +/* + * Language-dependencies + */ + +/* Common entry points */ + +/* Get the language of variable VAR. */ +static enum varobj_languages +variable_language (var) + struct varobj *var; +{ + enum varobj_languages lang; + + switch (var->root->exp->language_defn->la_language) + { + default: + case language_c: + lang = vlang_c; + break; + case language_cplus: + lang = vlang_cplus; + break; + case language_java: + lang = vlang_java; + break; + } + + return lang; +} + +/* Return the number of children for a given variable. + The result of this function is defined by the language + implementation. The number of children returned by this function + is the number of children that the user will see in the variable + display. */ +static int +number_of_children (var) + struct varobj *var; +{ + return (*var->root->lang->number_of_children) (var);; +} + +/* What is the expression for the root varobj VAR? Returns a malloc'd string. */ +static char * +name_of_variable (var) + struct varobj *var; +{ + return (*var->root->lang->name_of_variable) (var); +} + +/* What is the name of the INDEX'th child of VAR? Returns a malloc'd string. */ +static char * +name_of_child (var, index) + struct varobj *var; + int index; +{ + return (*var->root->lang->name_of_child) (var, index); +} + +/* What is the value_ptr of the root variable VAR? */ +static value_ptr +value_of_root (var) + struct varobj *var; +{ + return (*var->root->lang->value_of_root) (var); +} + +/* What is the value_ptr for the INDEX'th child of PARENT? */ +static value_ptr +value_of_child (parent, index) + struct varobj *parent; + int index; +{ + value_ptr value; + + value = (*parent->root->lang->value_of_child) (parent, index); + + /* If we're being lazy, fetch the real value of the variable. */ + if (value != NULL && VALUE_LAZY (value)) + gdb_value_fetch_lazy (value); + + return value; +} + +/* What is the type of VAR? */ +static struct type * +type_of_child (var) + struct varobj *var; +{ + + /* If the child had no evaluation errors, var->value + will be non-NULL and contain a valid type. */ + if (var->value != NULL) + return VALUE_TYPE (var->value); + + /* Otherwise, we must compute the type. */ + return (*var->root->lang->type_of_child) (var->parent, var->index); +} + +/* Is this variable editable? Use the variable's type to make + this determination. */ +static int +variable_editable (var) + struct varobj *var; +{ + return (*var->root->lang->variable_editable) (var); +} + +/* GDB already has a command called "value_of_variable". Sigh. */ +static char * +my_value_of_variable (var) + struct varobj *var; +{ + return (*var->root->lang->value_of_variable) (var); +} + +/* Is VAR something that can change? Depending on language, + some variable's values never change. For example, + struct and unions never change values. */ +static int +type_changeable (var) + struct varobj *var; +{ + int r; + struct type *type; + + if (CPLUS_FAKE_CHILD (var)) + return 0; + + type = get_type (var); + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + r = 0; + break; + + default: + r = 1; + } + + return r; +} + +/* C */ +static int +c_number_of_children (var) + struct varobj *var; +{ + struct type *type; + struct type *target; + int children; + + type = get_type (var); + target = get_target_type (type); + children = 0; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (target) > 0 + && TYPE_ARRAY_UPPER_BOUND_TYPE (type) != BOUND_CANNOT_BE_DETERMINED) + children = TYPE_LENGTH (type) / TYPE_LENGTH (target); + else + children = -1; + break; + + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + children = TYPE_NFIELDS (type); + break; + + case TYPE_CODE_PTR: + /* This is where things get compilcated. All pointers have one child. + Except, of course, for struct and union ptr, which we automagically + dereference for the user and function ptrs, which have no children. */ + switch (TYPE_CODE (target)) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + children = TYPE_NFIELDS (target); + break; + + case TYPE_CODE_FUNC: + children = 0; + break; + + default: + /* Don't dereference char* or void*. */ + if (TYPE_NAME (target) != NULL + && (STREQ (TYPE_NAME (target), "char") + || STREQ (TYPE_NAME (target), "void"))) + children = 0; + else + children = 1; + } + break; + + default: + /* Other types have no children */ + break; + } + + return children; +} + +static char * +c_name_of_variable (parent) + struct varobj *parent; +{ + return savestring (parent->name, strlen (parent->name)); +} + +static char * +c_name_of_child (parent, index) + struct varobj *parent; + int index; +{ + struct type *type; + struct type *target; + char *name; + char *string; + + type = get_type (parent); + target = get_target_type (type); + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + { + /* We never get here unless parent->num_children is greater than 0... */ + int len = 1; + while ((int) pow ((double) 10, (double) len) < index) + len++; + name = (char *) xmalloc (1 + len * sizeof (char)); + sprintf (name, "%d", index); + } + break; + + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + string = TYPE_FIELD_NAME (type, index); + name = savestring (string, strlen (string)); + break; + + case TYPE_CODE_PTR: + switch (TYPE_CODE (target)) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + string = TYPE_FIELD_NAME (target, index); + name = savestring (string, strlen (string)); + break; + + default: + name = (char *) xmalloc ((strlen (parent->name) + 2) * sizeof (char)); + sprintf (name, "*%s", parent->name); + break; + } + break; + + default: + /* This should not happen */ + name = xstrdup ("???"); + } + + return name; +} + +static value_ptr +c_value_of_root (var) + struct varobj *var; +{ + value_ptr new_val; + struct frame_info *fi; + int within_scope; + + /* Determine whether the variable is still around. */ + if (var->root->valid_block == NULL) + within_scope = 1; + else + { + reinit_frame_cache (); + fi = find_frame_addr_in_frame_chain (var->root->frame); + within_scope = fi != NULL; + /* FIXME: select_frame could fail */ + if (within_scope) + select_frame (fi, -1); + } + + if (within_scope) + { + /* We need to catch errors here, because if evaluate expression fails + we just want to make val->error = 1 and go on */ + if (gdb_evaluate_expression (var->root->exp, &new_val)) + { + if (VALUE_LAZY (new_val)) + { + /* We need to catch errors because if value_fetch_lazy fails we + still want to continue (after making val->error = 1) */ + /* FIXME: Shouldn't be using VALUE_CONTENTS? The comment on + value_fetch_lazy() says it is only called from the macro... */ + if (!gdb_value_fetch_lazy (new_val)) + var->error = 1; + else + var->error = 0; + } + } + else + var->error = 1; + + release_value (new_val); + return new_val; + } + + return NULL; +} + +static value_ptr +c_value_of_child (parent, index) + struct varobj *parent; + int index; +{ + value_ptr value, temp; + struct type *type, *target; + char *name; + + type = get_type (parent); + target = get_target_type (type); + name = name_of_child (parent, index); + temp = parent->value; + value = NULL; + + if (temp != NULL) + { + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + value = value_slice (temp, index, 1); + temp = value_coerce_array (value); + gdb_value_ind (temp, &value); + break; + + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + value = value_struct_elt (&temp, NULL, name, NULL, "vstructure"); + break; + + case TYPE_CODE_PTR: + switch (TYPE_CODE (target)) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + value = value_struct_elt (&temp, NULL, name, NULL, "vstructure"); + break; + + default: + gdb_value_ind (temp, &value); + break; + } + break; + + default: + break; + } + } + + if (value != NULL) + release_value (value); + + return value; +} + +static struct type * +c_type_of_child (parent, index) + struct varobj *parent; + int index; +{ + struct type *type; + char *name = name_of_child (parent, index); + + switch (TYPE_CODE (parent->type)) + { + case TYPE_CODE_ARRAY: + type = TYPE_TARGET_TYPE (parent->type); + break; + + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + type = lookup_struct_elt_type (parent->type, name, 0); + break; + + case TYPE_CODE_PTR: + switch (TYPE_CODE (TYPE_TARGET_TYPE (parent->type))) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + type = lookup_struct_elt_type (parent->type, name, 0); + break; + + default: + type = TYPE_TARGET_TYPE (parent->type); + break; + } + break; + + default: + /* This should not happen as only the above types have children */ + warning ("Child of parent whose type does not allow children"); + /* FIXME: Can we still go on? */ + type = NULL; + break; + } + + return type; +} + +static int +c_variable_editable (var) + struct varobj *var; +{ + switch (TYPE_CODE (get_type (var))) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_ARRAY: + case TYPE_CODE_FUNC: + case TYPE_CODE_MEMBER: + case TYPE_CODE_METHOD: + return 0; + break; + + default: + return 1; + break; + } +} + +static char * +c_value_of_variable (var) + struct varobj *var; +{ + struct type *type; + value_ptr val; + + if (var->value != NULL) + val = var->value; + else + { + /* This can happen if we attempt to get the value of a struct + member when the parent is an invalid pointer. */ + return xstrdup ("???"); + } + + /* BOGUS: if val_print sees a struct/class, it will print out its + children instead of "{...}" */ + type = get_type (var); + switch (TYPE_CODE (type)) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + return xstrdup ("{...}"); + /* break; */ + + case TYPE_CODE_ARRAY: + { + char number[18]; + sprintf (number, "[%d]", var->num_children); + return xstrdup (number); + } + /* break; */ + + default: + { + long dummy; + struct ui_file *stb = mem_fileopen (); + struct cleanup *old_chain = make_cleanup_ui_file_delete (stb); + char *thevalue; + + if (VALUE_LAZY (val)) + gdb_value_fetch_lazy (val); + val_print (VALUE_TYPE (val), VALUE_CONTENTS_RAW (val), 0, + VALUE_ADDRESS (val), + stb, format_code[(int) var->format], 1, 0, 0); + thevalue = ui_file_xstrdup (stb, &dummy); + do_cleanups (old_chain); + return thevalue; + } + /* break; */ + } +} + + +/* C++ */ + +static int +cplus_number_of_children (var) + struct varobj *var; +{ + struct type *type; + int children, dont_know; + + dont_know = 1; + children = 0; + + if (!CPLUS_FAKE_CHILD (var)) + { + type = get_type_deref (var); + + if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) || + ((TYPE_CODE (type)) == TYPE_CODE_UNION)) + { + int kids[3]; + + cplus_class_num_children (type, kids); + if (kids[v_public] != 0) + children++; + if (kids[v_private] != 0) + children++; + if (kids[v_protected] != 0) + children++; + + /* Add any baseclasses */ + children += TYPE_N_BASECLASSES (type); + dont_know = 0; + + /* FIXME: save children in var */ + } + } + else + { + int kids[3]; + + type = get_type_deref (var->parent); + + cplus_class_num_children (type, kids); + if (STREQ (var->name, "public")) + children = kids[v_public]; + else if (STREQ (var->name, "private")) + children = kids[v_private]; + else + children = kids[v_protected]; + dont_know = 0; + } + + if (dont_know) + children = c_number_of_children (var); + + return children; +} + +/* Compute # of public, private, and protected variables in this class. + That means we need to descend into all baseclasses and find out + how many are there, too. */ +static void +cplus_class_num_children (type, children) + struct type *type; + int children[3]; +{ + int i; + + children[v_public] = 0; + children[v_private] = 0; + children[v_protected] = 0; + + for (i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); i++) + { + /* If we have a virtual table pointer, omit it. */ + if (TYPE_VPTR_BASETYPE (type) == type + && TYPE_VPTR_FIELDNO (type) == i) + continue; + + if (TYPE_FIELD_PROTECTED (type, i)) + children[v_protected]++; + else if (TYPE_FIELD_PRIVATE (type, i)) + children[v_private]++; + else + children[v_public]++; + } +} + +static char * +cplus_name_of_variable (parent) + struct varobj *parent; +{ + return c_name_of_variable (parent); +} + +static char * +cplus_name_of_child (parent, index) + struct varobj *parent; + int index; +{ + char *name; + struct type *type; + int children[3]; + + if (CPLUS_FAKE_CHILD (parent)) + { + /* Looking for children of public, private, or protected. */ + type = get_type_deref (parent->parent); + } + else + type = get_type_deref (parent); + + name = NULL; + switch (TYPE_CODE (type)) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + cplus_class_num_children (type, children); + + if (CPLUS_FAKE_CHILD (parent)) + { + /* FIXME: This assumes that type orders + inherited, public, private, protected */ + int i = index + TYPE_N_BASECLASSES (type); + if (STREQ (parent->name, "private") || STREQ (parent->name, "protected")) + i += children[v_public]; + if (STREQ (parent->name, "protected")) + i += children[v_private]; + + name = TYPE_FIELD_NAME (type, i); + } + else if (index < TYPE_N_BASECLASSES (type)) + name = TYPE_FIELD_NAME (type, index); + else + { + /* Everything beyond the baseclasses can + only be "public", "private", or "protected" */ + index -= TYPE_N_BASECLASSES (type); + switch (index) + { + case 0: + if (children[v_public] != 0) + { + name = "public"; + break; + } + case 1: + if (children[v_private] != 0) + { + name = "private"; + break; + } + case 2: + if (children[v_protected] != 0) + { + name = "protected"; + break; + } + default: + /* error! */ + break; + } + } + break; + + default: + break; + } + + if (name == NULL) + return c_name_of_child (parent, index); + else + { + if (name != NULL) + name = savestring (name, strlen (name)); + } + + return name; +} + +static value_ptr +cplus_value_of_root (var) + struct varobj *var; +{ + return c_value_of_root (var); +} + +static value_ptr +cplus_value_of_child (parent, index) + struct varobj *parent; + int index; +{ + struct type *type; + value_ptr value; + char *name; + + if (CPLUS_FAKE_CHILD (parent)) + type = get_type_deref (parent->parent); + else + type = get_type_deref (parent); + + value = NULL; + name = name_of_child (parent, index); + + if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) || + ((TYPE_CODE (type)) == TYPE_CODE_UNION)) + { + if (CPLUS_FAKE_CHILD (parent)) + { + value_ptr temp = parent->parent->value; + value = value_struct_elt (&temp, NULL, name, + NULL, "cplus_structure"); + release_value (value); + } + else if (index >= TYPE_N_BASECLASSES (type)) + { + /* public, private, or protected */ + return NULL; + } + else + { + /* Baseclass */ + if (parent->value != NULL) + { + value_ptr temp; + + if (TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_PTR + || TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_REF) + gdb_value_ind (parent->value, &temp); + else + temp = parent->value; + + value = value_cast (TYPE_FIELD_TYPE (type, index), temp); + release_value (value); + } + } + } + + if (value == NULL) + return c_value_of_child (parent, index); + + return value; +} + +static struct type * +cplus_type_of_child (parent, index) + struct varobj *parent; + int index; +{ + struct type *type, *t; + + t = get_type_deref (parent); + type = NULL; + switch (TYPE_CODE (t)) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + if (index >= TYPE_N_BASECLASSES (t)) + { + /* special */ + return NULL; + } + else + { + /* Baseclass */ + type = TYPE_FIELD_TYPE (t, index); + } + break; + + default: + break; + } + + if (type == NULL) + return c_type_of_child (parent, index); + + return type; +} + +static int +cplus_variable_editable (var) + struct varobj *var; +{ + if (CPLUS_FAKE_CHILD (var)) + return 0; + + return c_variable_editable (var); +} + +static char * +cplus_value_of_variable (var) + struct varobj *var; +{ + + /* If we have one of our special types, don't print out + any value. */ + if (CPLUS_FAKE_CHILD (var)) + return xstrdup (""); + + return c_value_of_variable (var); +} + +/* Java */ + +static int +java_number_of_children (var) + struct varobj *var; +{ + return cplus_number_of_children (var); +} + +static char * +java_name_of_variable (parent) + struct varobj *parent; +{ + char *p, *name; + + name = cplus_name_of_variable (parent); + /* If the name has "-" in it, it is because we + needed to escape periods in the name... */ + p = name; + + while (*p != '\000') + { + if (*p == '-') + *p = '.'; + p++; + } + + return name; +} + +static char * +java_name_of_child (parent, index) + struct varobj *parent; + int index; +{ + char *name, *p; + + name = cplus_name_of_child (parent, index); + /* Escape any periods in the name... */ + p = name; + + while (*p != '\000') + { + if (*p == '.') + *p = '-'; + p++; + } + + return name; +} + +static value_ptr +java_value_of_root (var) + struct varobj *var; +{ + return cplus_value_of_root (var); +} + +static value_ptr +java_value_of_child (parent, index) + struct varobj *parent; + int index; +{ + return cplus_value_of_child (parent, index); +} + +static struct type * +java_type_of_child (parent, index) + struct varobj *parent; + int index; +{ + return cplus_type_of_child (parent, index); +} + +static int +java_variable_editable (var) + struct varobj *var; +{ + return cplus_variable_editable (var); +} + +static char * +java_value_of_variable (var) + struct varobj *var; +{ + return cplus_value_of_variable (var); +} + +extern void _initialize_varobj (void); +void +_initialize_varobj (void) +{ + int sizeof_table = sizeof (struct vlist *) * VAROBJ_TABLE_SIZE; + + varobj_table = xmalloc (sizeof_table); + memset (varobj_table, 0, sizeof_table); + + add_show_from_set ( + add_set_cmd ("debugvarobj", class_maintenance, var_zinteger, + (char *) &varobjdebug, + "Set varobj debugging.\n\ +When non-zero, varobj debugging is enabled.", &setlist), + &showlist); +} diff --git a/gdb/varobj.h b/gdb/varobj.h new file mode 100644 index 00000000000..28c5fac4d16 --- /dev/null +++ b/gdb/varobj.h @@ -0,0 +1,92 @@ +/* GDB variable objects API. + Copyright 1999 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef VAROBJ_H +#define VAROBJ_H 1 + +#include "symtab.h" +#include "gdbtypes.h" + +/* Enumeration for the format types */ +enum varobj_display_formats + { + FORMAT_NATURAL, /* What gdb actually calls 'natural' */ + FORMAT_BINARY, /* Binary display */ + FORMAT_DECIMAL, /* Decimal display */ + FORMAT_HEXADECIMAL, /* Hex display */ + FORMAT_OCTAL /* Octal display */ + }; + +/* String representations of gdb's format codes (defined in varobj.c) */ +extern char *varobj_format_string[]; + +/* Languages supported by this variable objects system. */ +enum varobj_languages + { + vlang_unknown = 0, vlang_c, vlang_cplus, vlang_java, vlang_end + }; + +/* String representations of gdb's known languages (defined in varobj.c) */ +extern char *varobj_language_string[]; + +/* Struct thar describes a variable object instance */ +struct varobj; + +/* API functions */ + +extern struct varobj *varobj_create (char *objname, + char *expression, CORE_ADDR frame); + +extern char *varobj_gen_name (void); + +extern struct varobj *varobj_get_handle (char *name); + +extern char *varobj_get_objname (struct varobj *var); + +extern char *varobj_get_expression (struct varobj *var); + +extern int varobj_delete (struct varobj *var, char ***dellist, + int only_children); + +extern enum varobj_display_formats varobj_set_display_format ( + struct varobj *var, + enum varobj_display_formats format); + +extern enum varobj_display_formats varobj_get_display_format ( + struct varobj *var); + +extern int varobj_get_num_children (struct varobj *var); + +extern int varobj_list_children (struct varobj *var, + struct varobj ***childlist); + +extern char *varobj_get_type (struct varobj *var); + +extern enum varobj_languages varobj_get_language (struct varobj *var); + +extern int varobj_get_attributes (struct varobj *var); + +extern char *varobj_get_value (struct varobj *var); + +extern int varobj_set_value (struct varobj *var, char *expression); + +extern int varobj_list (struct varobj ***rootlist); + +extern int varobj_update (struct varobj *var, struct varobj ***changelist); + +#endif /* VAROBJ_H */ diff --git a/gdb/wrapper.c b/gdb/wrapper.c new file mode 100644 index 00000000000..be7d4e27391 --- /dev/null +++ b/gdb/wrapper.c @@ -0,0 +1,165 @@ +/* Longjump free calls to gdb internal routines. + Copyright 1999 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "value.h" +#include "frame.h" +#include "wrapper.h" + +/* Use this struct used to pass arguments to wrapper routines. We assume + (arbitrarily) that no gdb function takes more than ten arguments. */ +struct gdb_wrapper_arguments + { + + /* Pointer to some result from the gdb function call, if any */ + char *result; + + /* The list of arguments. */ + char *args[10]; + }; + +int gdb_evaluate_expression PARAMS ((struct expression *, value_ptr *)); +int wrap_evaluate_expression PARAMS ((char *)); + +int gdb_value_fetch_lazy PARAMS ((value_ptr)); +int wrap_value_fetch_lazy PARAMS ((char *)); + +int gdb_value_equal PARAMS ((value_ptr, value_ptr, int *)); +int wrap_value_equal PARAMS ((char *)); + +int gdb_value_ind PARAMS ((value_ptr val, value_ptr * rval)); +int wrap_value_ind PARAMS ((char *opaque_arg)); + +int +gdb_evaluate_expression (exp, value) + struct expression *exp; + value_ptr *value; +{ + struct gdb_wrapper_arguments args; + args.args[0] = (char *) exp; + + if (!catch_errors ((catch_errors_ftype *) wrap_evaluate_expression, &args, + "", RETURN_MASK_ERROR)) + { + /* An error occurred */ + return 0; + } + + *value = (value_ptr) args.result; + return 1; +} + +int +wrap_evaluate_expression (a) + char *a; +{ + struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a; + + (args)->result = + (char *) evaluate_expression ((struct expression *) (args)->args[0]); + return 1; +} + +int +gdb_value_fetch_lazy (value) + value_ptr value; +{ + struct gdb_wrapper_arguments args; + + args.args[0] = (char *) value; + return catch_errors ((catch_errors_ftype *) wrap_value_fetch_lazy, &args, + "", RETURN_MASK_ERROR); +} + +int +wrap_value_fetch_lazy (a) + char *a; +{ + struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a; + + value_fetch_lazy ((value_ptr) (args)->args[0]); + return 1; +} + +int +gdb_value_equal (val1, val2, result) + value_ptr val1; + value_ptr val2; + int *result; +{ + struct gdb_wrapper_arguments args; + + args.args[0] = (char *) val1; + args.args[1] = (char *) val2; + + if (!catch_errors ((catch_errors_ftype *) wrap_value_equal, &args, + "", RETURN_MASK_ERROR)) + { + /* An error occurred */ + return 0; + } + + *result = (int) args.result; + return 1; +} + +int +wrap_value_equal (a) + char *a; +{ + struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a; + value_ptr val1, val2; + + val1 = (value_ptr) (args)->args[0]; + val2 = (value_ptr) (args)->args[1]; + + (args)->result = (char *) value_equal (val1, val2); + return 1; +} + +int +gdb_value_ind (val, rval) + value_ptr val; + value_ptr *rval; +{ + struct gdb_wrapper_arguments args; + + args.args[0] = (char *) val; + + if (!catch_errors ((catch_errors_ftype *) wrap_value_ind, &args, + "", RETURN_MASK_ERROR)) + { + /* An error occurred */ + return 0; + } + + *rval = (value_ptr) args.result; + return 1; +} + +int +wrap_value_ind (opaque_arg) + char *opaque_arg; +{ + struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) opaque_arg; + value_ptr val; + + val = (value_ptr) (args)->args[0]; + (args)->result = (char *) value_ind (val); + return 1; +} diff --git a/gdb/wrapper.h b/gdb/wrapper.h new file mode 100644 index 00000000000..f4303b2264b --- /dev/null +++ b/gdb/wrapper.h @@ -0,0 +1,37 @@ +/* Longjump free calls to gdb internal routines. + Copyright 1999 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef WRAPPER_H +#define WRAPPER_H 1 + +/* Use this struct used to pass arguments to wrapper routines. */ +struct gdb_wrapper_arguments; + +extern int gdb_evaluate_expression PARAMS ((struct expression *, value_ptr *)); +extern int wrap_evaluate_expression PARAMS ((char *)); + +extern int gdb_value_fetch_lazy PARAMS ((value_ptr)); +extern int wrap_value_fetch_lazy PARAMS ((char *)); + +extern int gdb_value_equal PARAMS ((value_ptr, value_ptr, int *)); +extern int wrap_value_equal PARAMS ((char *)); + +extern int gdb_value_ind PARAMS ((value_ptr val, value_ptr * rval)); +extern int wrap_value_ind PARAMS ((char *opaque_arg)); + +#endif /* WRAPPER_H */ |