aboutsummaryrefslogtreecommitdiff
path: root/gdb/RCS/printcmd.c,v
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/RCS/printcmd.c,v')
-rw-r--r--gdb/RCS/printcmd.c,v1707
1 files changed, 1707 insertions, 0 deletions
diff --git a/gdb/RCS/printcmd.c,v b/gdb/RCS/printcmd.c,v
new file mode 100644
index 0000000..2ab3acc
--- /dev/null
+++ b/gdb/RCS/printcmd.c,v
@@ -0,0 +1,1707 @@
+head 1.2;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.2
+date 89.04.26.00.54.22; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.04.25.15.38.49; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.2
+log
+@(1) Depend on XXX_BIG_ENDIAN rather than testing gdb's object code.
+(2) Print to the STREAM parameter, not to stdout.
+(3) Use is_nan with new arguments.
+(4) Use unpack_double with new args, and deal with invalid results.
+(5) Don't print history numbers in the "print" command for things
+that weren't recorded in history (because they were invalid values).
+@
+text
+@/* Print values for GNU debugger GDB.
+ Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "symtab.h"
+#include "value.h"
+#include "expression.h"
+
+struct format_data
+{
+ int count;
+ char format;
+ char size;
+};
+
+/* Last specified output format. */
+
+static char last_format = 'x';
+
+/* Last specified examination size. 'b', 'h', 'w' or `q'. */
+
+static char last_size = 'w';
+
+/* Default address to examine next. */
+
+static CORE_ADDR next_address;
+
+/* Last address examined. */
+
+static CORE_ADDR last_examine_address;
+
+/* Contents of last address examined.
+ This is not valid past the end of the `x' command! */
+
+static value last_examine_value;
+
+/* Number of auto-display expression currently being displayed.
+ So that we can deleted it if we get an error or a signal within it.
+ -1 when not doing one. */
+
+int current_display_number;
+
+static void do_one_display ();
+
+void do_displays ();
+void print_address ();
+void print_scalar_formatted ();
+
+
+/* Decode a format specification. *STRING_PTR should point to it.
+ OFORMAT and OSIZE are used as defaults for the format and size
+ if none are given in the format specification.
+ The structure returned describes all the data
+ found in the specification. In addition, *STRING_PTR is advanced
+ past the specification and past all whitespace following it. */
+
+struct format_data
+decode_format (string_ptr, oformat, osize)
+ char **string_ptr;
+ char oformat;
+ char osize;
+{
+ struct format_data val;
+ register char *p = *string_ptr;
+
+ val.format = oformat;
+ val.size = osize;
+ val.count = 1;
+
+ if (*p >= '0' && *p <= '9')
+ val.count = atoi (p);
+ while (*p >= '0' && *p <= '9') p++;
+
+ /* Now process size or format letters that follow. */
+
+ while (1)
+ {
+ if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g')
+ val.size = *p++;
+#ifdef LONG_LONG
+ else if (*p == 'l')
+ {
+ val.size = 'g';
+ p++;
+ }
+#endif
+ else if (*p >= 'a' && *p <= 'z')
+ val.format = *p++;
+ else
+ break;
+ }
+
+#ifndef LONG_LONG
+ /* Make sure 'g' size is not used on integer types.
+ Well, actually, we can handle hex. */
+ if (val.size == 'g' && val.format != 'f' && val.format != 'x')
+ val.size = 'w';
+#endif
+
+ while (*p == ' ' || *p == '\t') p++;
+ *string_ptr = p;
+
+ return val;
+}
+
+/* Print value VAL on stdout according to FORMAT, a letter or 0.
+ Do not end with a newline.
+ 0 means print VAL according to its own type.
+ SIZE is the letter for the size of datum being printed.
+ This is used to pad hex numbers so they line up. */
+
+static void
+print_formatted (val, format, size)
+ register value val;
+ register char format;
+ char size;
+{
+ int len = TYPE_LENGTH (VALUE_TYPE (val));
+
+ if (VALUE_LVAL (val) == lval_memory)
+ next_address = VALUE_ADDRESS (val) + len;
+
+ switch (format)
+ {
+ case 's':
+ next_address = VALUE_ADDRESS (val)
+ + value_print (value_addr (val), stdout, 0);
+ break;
+
+ case 'i':
+ next_address = VALUE_ADDRESS (val)
+ + print_insn (VALUE_ADDRESS (val), stdout);
+ break;
+
+ default:
+ if (format == 0
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_ARRAY
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_UNION
+ || VALUE_REPEATED (val))
+ value_print (val, stdout, format);
+ else
+ print_scalar_formatted (VALUE_CONTENTS (val), VALUE_TYPE (val),
+ format, size, stdout);
+ }
+}
+
+/* Print a scalar of data of type TYPE, pointed to in GDB by VALADDR,
+ according to letters FORMAT and SIZE on STREAM.
+ FORMAT may not be zero. Formats s and i are not supported at this level.
+
+ This is how the elements of an array or structure are printed
+ with a format. */
+
+void
+print_scalar_formatted (valaddr, type, format, size, stream)
+ char *valaddr;
+ struct type *type;
+ char format;
+ int size;
+ FILE *stream;
+{
+ LONGEST val_long;
+ int len = TYPE_LENGTH (type);
+
+ if (size == 'g' && sizeof (LONGEST) < 8
+ && format == 'x')
+ {
+ /* ok, we're going to have to get fancy here. Assumption: a
+ long is four bytes. */
+ unsigned long v1, v2, tmp;
+
+ v1 = unpack_long (builtin_type_long, valaddr);
+ v2 = unpack_long (builtin_type_long, valaddr + 4);
+
+#ifdef BYTES_BIG_ENDIAN
+#else
+ /* Little endian -- swap the two for printing */
+ tmp = v1;
+ v1 = v2;
+ v2 = tmp;
+#endif
+
+ switch (format)
+ {
+ case 'x':
+ fprintf (stream, "0x%08x%08x", v1, v2);
+ break;
+ default:
+ error ("Output size \"g\" unimplemented for format \"%c\".",
+ format);
+ }
+ return;
+ }
+
+ val_long = unpack_long (type, valaddr);
+
+ /* If value is unsigned, truncate it in case negative. */
+ if (format != 'd')
+ {
+ if (len == sizeof (char))
+ val_long &= (1 << 8 * sizeof(char)) - 1;
+ else if (len == sizeof (short))
+ val_long &= (1 << 8 * sizeof(short)) - 1;
+ else if (len == sizeof (long))
+ val_long &= (unsigned long) - 1;
+ }
+
+ switch (format)
+ {
+ case 'x':
+#ifdef LONG_LONG
+ if (!size)
+ size = (len < sizeof (long long) ? 'w' : 'g');
+ switch (size)
+ {
+ case 'b':
+ fprintf (stream, "0x%02llx", val_long);
+ break;
+ case 'h':
+ fprintf (stream, "0x%04llx", val_long);
+ break;
+ case 0: /* no size specified, like in print */
+ case 'w':
+ fprintf (stream, "0x%08llx", val_long);
+ break;
+ case 'g':
+ fprintf (stream, "0x%16llx", val_long);
+ break;
+ default:
+ error ("Undefined output size \"%c\".", size);
+ }
+#else
+ switch (size)
+ {
+ case 'b':
+ fprintf (stream, "0x%02x", val_long);
+ break;
+ case 'h':
+ fprintf (stream, "0x%04x", val_long);
+ break;
+ case 0: /* no size specified, like in print */
+ case 'w':
+ fprintf (stream, "0x%08x", val_long);
+ break;
+ case 'g':
+ fprintf (stream, "0x%16x", val_long);
+ break;
+ default:
+ error ("Undefined output size \"%c\".", size);
+ }
+#endif /* not LONG_LONG */
+ break;
+
+ case 'd':
+#ifdef LONG_LONG
+ fprintf (stream, "%lld", val_long);
+#else
+ fprintf (stream, "%d", val_long);
+#endif
+ break;
+
+ case 'u':
+#ifdef LONG_LONG
+ fprintf (stream, "%llu", val_long);
+#else
+ fprintf (stream, "%u", val_long);
+#endif
+ break;
+
+ case 'o':
+ if (val_long)
+#ifdef LONG_LONG
+ fprintf (stream, "0%llo", val_long);
+#else
+ fprintf (stream, "0%o", val_long);
+#endif
+ else
+ fprintf (stream, "0");
+ break;
+
+ case 'a':
+ print_address ((CORE_ADDR) val_long, stream);
+ break;
+
+ case 'c':
+ value_print (value_from_long (builtin_type_char, val_long), stream, 0);
+ break;
+
+ case 'f':
+ if (len == sizeof (float))
+ type = builtin_type_float;
+ else if (len == sizeof (double))
+ type = builtin_type_double;
+ else abort();
+
+#ifdef IEEE_FLOAT
+ if (is_nan (valaddr, len))
+ {
+ fprintf (stream, "NaN");
+ break;
+ }
+#endif
+ {
+ double doub;
+ int inv;
+
+ doub = unpack_double (type, valaddr, &inv);
+ if (inv)
+ fprintf (stream, "Invalid float value");
+ else
+ fprintf (stream, len > 4? "%.16g": "%.6g", doub);
+ }
+ break;
+
+ case 0:
+ abort ();
+
+ default:
+ error ("Undefined output format \"%c\".", format);
+ }
+}
+
+/* Specify default address for `x' command.
+ `info lines' uses this. */
+
+void
+set_next_address (addr)
+ CORE_ADDR addr;
+{
+ next_address = addr;
+
+ /* Make address available to the user as $_. */
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_long (builtin_type_int, (LONGEST) addr));
+}
+
+/* Print address ADDR symbolically on STREAM.
+ First print it as a number. Then perhaps print
+ <SYMBOL + OFFSET> after the number. */
+
+void
+print_address (addr, stream)
+ CORE_ADDR addr;
+ FILE *stream;
+{
+ register int i;
+ struct symbol *fs;
+ char *name;
+ int name_location;
+
+ fprintf (stream, "0x%x", addr);
+
+ fs = find_pc_function (addr);
+
+ if (!fs)
+ {
+ i = find_pc_misc_function (addr);
+
+ if (i < 0) return; /* If nothing comes through, don't
+ print anything symbolic */
+
+ name = misc_function_vector[i].name;
+ name_location = misc_function_vector[i].address;
+ }
+ else
+ {
+ name = fs->name;
+ name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (fs));
+ }
+
+ if (addr - name_location)
+ fprintf (stream, " <%s+%d>",
+ name,
+ addr - name_location);
+ else
+ fprintf (stream, " <%s>", name);
+}
+
+/* Examine data at address ADDR in format FMT.
+ Fetch it from memory and print on stdout. */
+
+static void
+do_examine (fmt, addr)
+ struct format_data fmt;
+ CORE_ADDR addr;
+{
+ register char format = 0;
+ register char size;
+ register int count = 1;
+ struct type *val_type;
+ register int i;
+ register int maxelts;
+
+ format = fmt.format;
+ size = fmt.size;
+ count = fmt.count;
+ next_address = addr;
+
+ /* String or instruction format implies fetch single bytes
+ regardless of the specified size. */
+ if (format == 's' || format == 'i')
+ size = 'b';
+
+ if (size == 'b')
+ val_type = builtin_type_char;
+ else if (size == 'h')
+ val_type = builtin_type_short;
+ else if (size == 'w')
+ val_type = builtin_type_long;
+ else if (size == 'g')
+#ifndef LONG_LONG
+ val_type = builtin_type_double;
+#else
+ val_type = builtin_type_long_long;
+#endif
+
+ maxelts = 8;
+ if (size == 'w')
+ maxelts = 4;
+ if (size == 'g')
+ maxelts = 2;
+ if (format == 's' || format == 'i')
+ maxelts = 1;
+
+ /* Print as many objects as specified in COUNT, at most maxelts per line,
+ with the address of the next one at the start of each line. */
+
+ while (count > 0)
+ {
+ print_address (next_address, stdout);
+ fputc (':', stdout);
+ for (i = maxelts;
+ i > 0 && count > 0;
+ i--, count--)
+ {
+ fputc ('\t', stdout);
+ /* Note that print_formatted sets next_address for the next
+ object. */
+ last_examine_address = next_address;
+ last_examine_value = value_at (val_type, next_address);
+ print_formatted (last_examine_value, format, size);
+ }
+ fputc ('\n', stdout);
+ fflush (stdout);
+ }
+}
+
+static void
+validate_format (fmt, cmdname)
+ struct format_data fmt;
+ char *cmdname;
+{
+ if (fmt.size != 0)
+ error ("Size letters are meaningless in \"%s\" command.", cmdname);
+ if (fmt.count != 1)
+ error ("Item count other than 1 is meaningless in \"%s\" command.",
+ cmdname);
+ if (fmt.format == 'i' || fmt.format == 's')
+ error ("Format letter \"%c\" is meaningless in \"%s\" command.",
+ fmt.format, cmdname);
+}
+
+static void
+print_command (exp)
+ char *exp;
+{
+ struct expression *expr;
+ register struct cleanup *old_chain = 0;
+ register char format = 0;
+ register value val;
+ struct format_data fmt;
+ int histindex;
+ int cleanup = 0;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, last_format, 0);
+ validate_format (fmt, "print");
+ last_format = format = fmt.format;
+ }
+
+ if (exp && *exp)
+ {
+ expr = parse_c_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ cleanup = 1;
+ val = evaluate_expression (expr);
+ }
+ else
+ val = access_value_history (0);
+
+ histindex = record_latest_value (val);
+ if (histindex >= 0) printf ("$%d = ", histindex);
+
+ print_formatted (val, format, fmt.size);
+ printf ("\n");
+
+ if (cleanup)
+ do_cleanups (old_chain);
+}
+
+static void
+output_command (exp)
+ char *exp;
+{
+ struct expression *expr;
+ register struct cleanup *old_chain;
+ register char format = 0;
+ register value val;
+ struct format_data fmt;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, 0, 0);
+ validate_format (fmt, "print");
+ format = fmt.format;
+ }
+
+ expr = parse_c_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+
+ val = evaluate_expression (expr);
+
+ print_formatted (val, format, fmt.size);
+
+ do_cleanups (old_chain);
+}
+
+static void
+set_command (exp)
+ char *exp;
+{
+ struct expression *expr = parse_c_expression (exp);
+ register struct cleanup *old_chain
+ = make_cleanup (free_current_contents, &expr);
+ evaluate_expression (expr);
+ do_cleanups (old_chain);
+}
+
+static void
+address_info (exp)
+ char *exp;
+{
+ register struct symbol *sym;
+ register CORE_ADDR val;
+ int is_a_field_of_this; /* C++: lookup_symbol sets this to nonzero
+ if exp is a field of `this'. */
+
+ if (exp == 0)
+ error ("Argument required.");
+
+ sym = lookup_symbol (exp, get_selected_block (), VAR_NAMESPACE,
+ &is_a_field_of_this);
+ if (sym == 0)
+ {
+ register int i;
+
+ if (is_a_field_of_this)
+ {
+ printf("Symbol \"%s\" is a field of the local class variable `this'\n", exp);
+ return;
+ }
+
+ for (i = 0; i < misc_function_count; i++)
+ if (!strcmp (misc_function_vector[i].name, exp))
+ break;
+
+ if (i < misc_function_count)
+ printf ("Symbol \"%s\" is at 0x%x in a file compiled without -g.\n",
+ exp, misc_function_vector[i].address);
+ else
+ error ("No symbol \"%s\" in current context.", exp);
+ return;
+ }
+
+ printf ("Symbol \"%s\" is ", SYMBOL_NAME (sym));
+ val = SYMBOL_VALUE (sym);
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_CONST:
+ case LOC_CONST_BYTES:
+ printf ("constant");
+ break;
+
+ case LOC_LABEL:
+ printf ("a label at address 0x%x", val);
+ break;
+
+ case LOC_REGISTER:
+ printf ("a variable in register %s", reg_names[val]);
+ break;
+
+ case LOC_STATIC:
+ printf ("static at address 0x%x", val);
+ break;
+
+ case LOC_REGPARM:
+ printf ("an argument in register %s", reg_names[val]);
+ break;
+
+ case LOC_ARG:
+ printf ("an argument at offset %d", val);
+ break;
+
+ case LOC_LOCAL:
+ printf ("a local variable at frame offset %d", val);
+ break;
+
+ case LOC_TYPEDEF:
+ printf ("a typedef");
+ break;
+
+ case LOC_BLOCK:
+ printf ("a function at address 0x%x",
+ BLOCK_START (SYMBOL_BLOCK_VALUE (sym)));
+ break;
+ }
+ printf (".\n");
+}
+
+static void
+x_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct expression *expr;
+ struct format_data fmt;
+ struct cleanup *old_chain;
+
+ fmt.format = last_format;
+ fmt.size = last_size;
+ fmt.count = 1;
+
+ if (exp && *exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, last_format, last_size);
+ last_size = fmt.size;
+ last_format = fmt.format;
+ }
+
+ /* If we have an expression, evaluate it and use it as the address. */
+
+ if (exp != 0 && *exp != 0)
+ {
+ expr = parse_c_expression (exp);
+ /* Cause expression not to be there any more
+ if this command is repeated with Newline.
+ But don't clobber a user-defined command's definition. */
+ if (from_tty)
+ *exp = 0;
+ old_chain = make_cleanup (free_current_contents, &expr);
+ next_address = (CORE_ADDR) value_as_long (evaluate_expression (expr));
+ do_cleanups (old_chain);
+ }
+
+ do_examine (fmt, next_address);
+
+ /* Set a couple of internal variables if appropriate. */
+ if (last_examine_value)
+ {
+ /* Make last address examined available to the user as $_. */
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_long (builtin_type_int,
+ (LONGEST) last_examine_address));
+
+ /* Make contents of last address examined available to the user as $__.*/
+ set_internalvar (lookup_internalvar ("__"), last_examine_value);
+ }
+}
+
+/* Commands for printing types of things. */
+
+static void
+whatis_command (exp)
+ char *exp;
+{
+ struct expression *expr;
+ register value val;
+ register struct cleanup *old_chain;
+
+ if (exp)
+ {
+ expr = parse_c_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ val = evaluate_type (expr);
+ }
+ else
+ val = access_value_history (0);
+
+ printf ("type = ");
+ type_print (VALUE_TYPE (val), "", stdout, 1);
+ printf ("\n");
+
+ if (exp)
+ do_cleanups (old_chain);
+}
+
+static void
+ptype_command (typename)
+ char *typename;
+{
+ register char *p = typename;
+ register int len;
+ extern struct block *get_current_block ();
+ register struct block *b
+ = (have_inferior_p () || have_core_file_p ()) ? get_current_block () : 0;
+ register struct type *type;
+
+ if (typename == 0)
+ error_no_arg ("type name");
+
+ while (*p && *p != ' ' && *p != '\t') p++;
+ len = p - typename;
+ while (*p == ' ' || *p == '\t') p++;
+
+ if (len == 6 && !strncmp (typename, "struct", 6))
+ type = lookup_struct (p, b);
+ else if (len == 5 && !strncmp (typename, "union", 5))
+ type = lookup_union (p, b);
+ else if (len == 4 && !strncmp (typename, "enum", 4))
+ type = lookup_enum (p, b);
+ else
+ {
+ type = lookup_typename (typename, b, 1);
+ if (type == 0)
+ {
+ register struct symbol *sym
+ = lookup_symbol (typename, b, STRUCT_NAMESPACE, 0);
+ if (sym == 0)
+ error ("No type named %s.", typename);
+ printf ("No type named %s, but there is a ",
+ typename);
+ switch (TYPE_CODE (SYMBOL_TYPE (sym)))
+ {
+ case TYPE_CODE_STRUCT:
+ printf ("struct");
+ break;
+
+ case TYPE_CODE_UNION:
+ printf ("union");
+ break;
+
+ case TYPE_CODE_ENUM:
+ printf ("enum");
+ }
+ printf (" %s. Type \"help ptype\".\n", typename);
+ type = SYMBOL_TYPE (sym);
+ }
+ }
+
+ type_print (type, "", stdout, 1);
+ printf ("\n");
+}
+
+enum display_status {disabled, enabled};
+
+struct display
+{
+ /* Chain link to next auto-display item. */
+ struct display *next;
+ /* Expression to be evaluated and displayed. */
+ struct expression *exp;
+ /* Item number of this auto-display item. */
+ int number;
+ /* Display format specified. */
+ struct format_data format;
+ /* Innermost block required by this expression when evaluated */
+ struct block *block;
+ /* Status of this display (enabled or disabled) */
+ enum display_status status;
+};
+
+/* Chain of expressions whose values should be displayed
+ automatically each time the program stops. */
+
+static struct display *display_chain;
+
+static int display_number;
+
+/* Add an expression to the auto-display chain.
+ Specify the expression. */
+
+static void
+display_command (exp, from_tty)
+ char *exp;
+ int from_tty;
+{
+ struct format_data fmt;
+ register struct expression *expr;
+ register struct display *new;
+ extern struct block *innermost_block;
+
+ if (exp == 0)
+ {
+ do_displays ();
+ return;
+ }
+
+ if (*exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, 0, 0);
+ if (fmt.size && fmt.format == 0)
+ fmt.format = 'x';
+ if (fmt.format == 'i' || fmt.format == 's')
+ fmt.size = 'b';
+ }
+ else
+ {
+ fmt.format = 0;
+ fmt.size = 0;
+ fmt.count = 0;
+ }
+
+ innermost_block = 0;
+ expr = parse_c_expression (exp);
+
+ new = (struct display *) xmalloc (sizeof (struct display));
+
+ new->exp = expr;
+ new->block = innermost_block;
+ new->next = display_chain;
+ new->number = ++display_number;
+ new->format = fmt;
+ new->status = enabled;
+ display_chain = new;
+
+ if (from_tty && have_inferior_p ())
+ do_one_display (new);
+
+ dont_repeat ();
+}
+
+static void
+free_display (d)
+ struct display *d;
+{
+ free (d->exp);
+ free (d);
+}
+
+/* Clear out the display_chain.
+ Done when new symtabs are loaded, since this invalidates
+ the types stored in many expressions. */
+
+void
+clear_displays ()
+{
+ register struct display *d;
+
+ while (d = display_chain)
+ {
+ free (d->exp);
+ display_chain = d->next;
+ free (d);
+ }
+}
+
+/* Delete the auto-display number NUM. */
+
+void
+delete_display (num)
+ int num;
+{
+ register struct display *d1, *d;
+
+ if (!display_chain)
+ error ("No display number %d.", num);
+
+ if (display_chain->number == num)
+ {
+ d1 = display_chain;
+ display_chain = d1->next;
+ free_display (d1);
+ }
+ else
+ for (d = display_chain; ; d = d->next)
+ {
+ if (d->next == 0)
+ error ("No display number %d.", num);
+ if (d->next->number == num)
+ {
+ d1 = d->next;
+ d->next = d1->next;
+ free_display (d1);
+ break;
+ }
+ }
+}
+
+/* Delete some values from the auto-display chain.
+ Specify the element numbers. */
+
+static void
+undisplay_command (args)
+ char *args;
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+ register struct display *d, *d1;
+
+ if (args == 0)
+ {
+ if (query ("Delete all auto-display expressions? "))
+ clear_displays ();
+ dont_repeat ();
+ return;
+ }
+
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9') p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ num = atoi (p);
+
+ delete_display (num);
+
+ p = p1;
+ while (*p == ' ' || *p == '\t') p++;
+ }
+ dont_repeat ();
+}
+
+/* Display a single auto-display.
+ Do nothing if the display cannot be printed in the current context,
+ or if the display is disabled. */
+
+static void
+do_one_display (d)
+ struct display *d;
+{
+ int within_current_scope;
+
+ if (d->status == disabled)
+ return;
+
+ if (d->block)
+ within_current_scope = contained_in (get_selected_block (), d->block);
+ else
+ within_current_scope = 1;
+ if (!within_current_scope)
+ return;
+
+ current_display_number = d->number;
+
+ printf ("%d: ", d->number);
+ if (d->format.size)
+ {
+ printf ("x/");
+ if (d->format.count != 1)
+ printf ("%d", d->format.count);
+ printf ("%c", d->format.format);
+ if (d->format.format != 'i' && d->format.format != 's')
+ printf ("%c", d->format.size);
+ printf (" ");
+ print_expression (d->exp, stdout);
+ if (d->format.count != 1)
+ printf ("\n");
+ else
+ printf (" ");
+ do_examine (d->format,
+ (CORE_ADDR) value_as_long (evaluate_expression (d->exp)));
+
+ }
+ else
+ {
+ if (d->format.format)
+ printf ("/%c ", d->format.format);
+ print_expression (d->exp, stdout);
+ printf (" = ");
+ print_formatted (evaluate_expression (d->exp),
+ d->format.format, d->format.size);
+ printf ("\n");
+ }
+
+ fflush (stdout);
+ current_display_number = -1;
+}
+
+/* Display all of the values on the auto-display chain which can be
+ evaluated in the current scope. */
+
+void
+do_displays ()
+{
+ register struct display *d;
+
+ for (d = display_chain; d; d = d->next)
+ do_one_display (d);
+}
+
+/* Delete the auto-display which we were in the process of displaying.
+ This is done when there is an error or a signal. */
+
+void
+delete_current_display ()
+{
+ if (current_display_number >= 0)
+ {
+ delete_display (current_display_number);
+ fprintf (stderr, "Deleting display %d to avoid infinite recursion.\n",
+ current_display_number);
+ }
+ current_display_number = -1;
+}
+
+static void
+display_info ()
+{
+ register struct display *d;
+
+ if (!display_chain)
+ printf ("There are no auto-display expressions now.\n");
+ else
+ printf ("Auto-display expressions now in effect:\n\
+Num Enb Expression\n");
+
+ for (d = display_chain; d; d = d->next)
+ {
+ printf ("%d: %c ", d->number, "ny"[(int)d->status]);
+ if (d->format.size)
+ printf ("/%d%c%c ", d->format.count, d->format.size,
+ d->format.format);
+ else if (d->format.format)
+ printf ("/%c ", d->format.format);
+ print_expression (d->exp, stdout);
+ if (d->block && !contained_in (get_selected_block (), d->block))
+ printf (" (cannot be evaluated in the current context)");
+ printf ("\n");
+ fflush (stdout);
+ }
+}
+
+void
+enable_display (args)
+ char *args;
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+ register struct display *d;
+
+ if (p == 0)
+ {
+ for (d = display_chain; d; d->next)
+ d->status = enabled;
+ }
+ else
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ num = atoi (p);
+
+ for (d = display_chain; d; d = d->next)
+ if (d->number == num)
+ {
+ d->status = enabled;
+ goto win;
+ }
+ printf ("No display number %d.\n", num);
+ win:
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+void
+disable_display (args)
+ char *args;
+{
+ register char *p = args;
+ register char *p1;
+ register int num;
+ register struct display *d;
+
+ if (p == 0)
+ {
+ for (d = display_chain; d; d->next)
+ d->status = disabled;
+ }
+ else
+ while (*p)
+ {
+ p1 = p;
+ while (*p1 >= '0' && *p1 <= '9')
+ p1++;
+ if (*p1 && *p1 != ' ' && *p1 != '\t')
+ error ("Arguments must be display numbers.");
+
+ num = atoi (p);
+
+ for (d = display_chain; d; d = d->next)
+ if (d->number == num)
+ {
+ d->status = disabled;
+ goto win;
+ }
+ printf ("No display number %d.\n", num);
+ win:
+ p = p1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+}
+
+
+/* Print the value in stack frame FRAME of a variable
+ specified by a struct symbol. */
+
+void
+print_variable_value (var, frame, stream)
+ struct symbol *var;
+ CORE_ADDR frame;
+ FILE *stream;
+{
+ value val = read_var_value (var, frame);
+ value_print (val, stream, 0);
+}
+
+/* Print the arguments of a stack frame, given the function FUNC
+ running in that frame (as a symbol), the info on the frame,
+ and the number of args according to the stack frame (or -1 if unknown). */
+
+static void print_frame_nameless_args ();
+
+void
+print_frame_args (func, fi, num, stream)
+ struct symbol *func;
+ struct frame_info *fi;
+ int num;
+ FILE *stream;
+{
+ struct block *b;
+ int nsyms = 0;
+ int first = 1;
+ register int i;
+ register int last_offset = FRAME_ARGS_SKIP;
+ register int last_regparm = 0;
+ register struct symbol *lastsym, *sym, *nextsym;
+ register value val;
+ register CORE_ADDR addr = FRAME_ARGS_ADDRESS (fi);
+
+ if (func)
+ {
+ b = SYMBOL_BLOCK_VALUE (func);
+ nsyms = BLOCK_NSYMS (b);
+ }
+
+ lastsym = 0;
+ while (1)
+ {
+ /* Find first arg that is not before LAST_OFFSET. */
+ nextsym = 0;
+ for (i = 0; i < nsyms; i++)
+ {
+ QUIT;
+ sym = BLOCK_SYM (b, i);
+ if (SYMBOL_CLASS (sym) == LOC_ARG)
+ {
+ if (SYMBOL_VALUE (sym) >= last_offset
+ && (nextsym == 0
+ || SYMBOL_VALUE (sym) < SYMBOL_VALUE (nextsym)))
+ nextsym = sym;
+ }
+ else if (SYMBOL_CLASS (sym) == LOC_REGPARM)
+ {
+ /* This shouldn't be sorted by number. Since we can't
+ find nameless args with register parameters, print
+ this out in order by .stabs. */
+ if (sym > lastsym && nextsym == 0)
+ nextsym = sym;
+ }
+ }
+ if (nextsym == 0)
+ break;
+ sym = nextsym;
+ /* Print any nameless args between the last arg printed
+ and the next arg. */
+ if (SYMBOL_CLASS (sym) == LOC_ARG
+ && last_offset != (SYMBOL_VALUE (sym) / sizeof (int)) * sizeof (int))
+ {
+ print_frame_nameless_args (addr, last_offset, SYMBOL_VALUE (sym),
+ stream);
+ first = 0;
+ }
+ /* Print the next arg. */
+ if (SYMBOL_CLASS (sym) == LOC_REGPARM)
+ val = value_from_register (SYMBOL_TYPE (sym),
+ SYMBOL_VALUE (sym),
+ FRAME_INFO_ID (fi));
+ else
+ val = value_at (SYMBOL_TYPE (sym), addr + SYMBOL_VALUE (sym));
+
+ if (! first)
+ fprintf (stream, ", ");
+ fprintf (stream, "%s=", SYMBOL_NAME (sym));
+ value_print (val, stream, 0);
+ first = 0;
+ if (SYMBOL_CLASS (sym) == LOC_ARG)
+ last_offset = SYMBOL_VALUE (sym) + TYPE_LENGTH (SYMBOL_TYPE (sym));
+ else
+ {
+ last_regparm = SYMBOL_VALUE (sym) + 1;
+ last_offset += TYPE_LENGTH (SYMBOL_TYPE (sym));
+ }
+
+ /* Round up address of next arg to multiple of size of int. */
+ last_offset
+ = ((last_offset + sizeof (int) - 1) / sizeof (int)) * sizeof (int);
+ lastsym = sym;
+ }
+ if (num >= 0 && num * sizeof (int) + FRAME_ARGS_SKIP > last_offset)
+ print_frame_nameless_args (addr, last_offset,
+ num * sizeof (int) + FRAME_ARGS_SKIP, stream);
+}
+
+static void
+print_frame_nameless_args (argsaddr, start, end, stream)
+ CORE_ADDR argsaddr;
+ int start;
+ int end;
+ FILE *stream;
+{
+ while (start < end)
+ {
+ QUIT;
+ if (start != FRAME_ARGS_SKIP)
+ fprintf (stream, ", ");
+ fprintf (stream, "%d",
+ read_memory_integer (argsaddr + start, sizeof (int)));
+ start += sizeof (int);
+ }
+}
+
+static void
+printf_command (arg)
+ char *arg;
+{
+ register char *f;
+ register char *s = arg;
+ char *string;
+ value *val_args;
+ int nargs = 0;
+ int allocated_args = 20;
+ char *arg_bytes;
+ char *argclass;
+ int i;
+ int argindex;
+ int nargs_wanted;
+
+ val_args = (value *) xmalloc (allocated_args * sizeof (value));
+
+ if (s == 0)
+ error_no_arg ("format-control string and values to print");
+
+ /* Skip white space before format string */
+ while (*s == ' ' || *s == '\t') s++;
+
+ /* A format string should follow, enveloped in double quotes */
+ if (*s++ != '"')
+ error ("Bad format string, missing '\"'.");
+
+ /* Parse the format-control string and copy it into the string STRING,
+ processing some kinds of escape sequence. */
+
+ f = string = (char *) alloca (strlen (s) + 1);
+ while (*s != '"')
+ {
+ int c = *s++;
+ switch (c)
+ {
+ case '\0':
+ error ("Bad format string, non-terminated '\"'.");
+ /* doesn't return */
+
+ case '\\':
+ switch (c = *s++)
+ {
+ case '\\':
+ *f++ = '\\';
+ break;
+ case 'n':
+ *f++ = '\n';
+ break;
+ case 't':
+ *f++ = '\t';
+ break;
+ case 'r':
+ *f++ = '\r';
+ break;
+ case '"':
+ *f++ = '"';
+ break;
+ default:
+ /* ??? TODO: handle other escape sequences */
+ error ("Unrecognized \\ escape character in format string.");
+ }
+ break;
+
+ default:
+ *f++ = c;
+ }
+ }
+
+ /* Skip over " and following space and comma. */
+ s++;
+ *f++ = '\0';
+ while (*s == ' ' || *s == '\t') s++;
+
+ if (*s != ',' && *s != 0)
+ error ("Invalid argument syntax");
+
+ if (*s == ',') s++;
+ while (*s == ' ' || *s == '\t') s++;
+
+ /* Now scan the string for %-specs and see what kinds of args they want.
+ argclass[I] is set to 1 if the Ith arg should be a string.
+ It's set to 2 if the Ith arg should be floating point. */
+
+ argclass = (char *) alloca (strlen (s));
+ nargs_wanted = 0;
+ f = string;
+ while (*f)
+ if (*f++ == '%')
+ {
+ while (index ("0123456789.hlL-+ #", *f)) f++;
+ if (*f == 's')
+ argclass[nargs_wanted++] = 1;
+ else if (*f == 'e' || *f == 'f' || *f == 'g')
+ argclass[nargs_wanted++] = 2;
+ else if (*f != '%')
+ argclass[nargs_wanted++] = 0;
+ f++;
+ }
+
+ /* Now, parse all arguments and evaluate them.
+ Store the VALUEs in VAL_ARGS. */
+
+ while (*s != '\0')
+ {
+ char *s1;
+ if (nargs == allocated_args)
+ val_args = (value *) xrealloc (val_args,
+ (allocated_args *= 2)
+ * sizeof (value));
+ s1 = s;
+ val_args[nargs] = parse_to_comma_and_eval (&s1);
+
+ /* If format string wants a float, unchecked-convert the value to
+ floating point of the same size */
+
+ if (argclass[nargs] == 2)
+ {
+ argclass[nargs] = 0;
+ if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (float))
+ VALUE_TYPE (val_args[nargs]) = builtin_type_float;
+ if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (double))
+ VALUE_TYPE (val_args[nargs]) = builtin_type_double;
+ }
+ nargs++;
+ s = s1;
+ if (*s == ',')
+ s++;
+ }
+
+ if (nargs != nargs_wanted)
+ error ("Wrong number of arguments for specified format-string");
+
+ /* Now lay out an argument-list containing the arguments
+ as doubles, integers and C pointers. */
+
+ arg_bytes = (char *) alloca (sizeof (double) * nargs);
+ argindex = 0;
+ for (i = 0; i < nargs; i++)
+ {
+ if (argclass[i])
+ {
+ char *str;
+ int tem, j;
+ tem = value_as_long (val_args[i]);
+
+ /* This is a %s argument. Find the length of the string. */
+ for (j = 0; ; j++)
+ {
+ char c;
+ QUIT;
+ read_memory (tem + j, &c, 1);
+ if (c == 0)
+ break;
+ }
+
+ /* Copy the string contents into a string inside GDB. */
+ str = (char *) alloca (j + 1);
+ read_memory (tem, str, j);
+ str[j] = 0;
+
+ /* Pass address of internal copy as the arg to vprintf. */
+ *((int *) &arg_bytes[argindex]) = (int) str;
+ argindex += sizeof (int);
+ }
+ else if (VALUE_TYPE (val_args[i])->code == TYPE_CODE_FLT)
+ {
+ *((double *) &arg_bytes[argindex]) = value_as_double (val_args[i]);
+ argindex += sizeof (double);
+ }
+ else
+#ifdef LONG_LONG
+ if (TYPE_LENGTH (VALUE_TYPE (val_args[i])) == sizeof (long long))
+ {
+ *(long long *) &arg_bytes[argindex] = value_as_long (val_args[i]);
+ argindex += sizeof (long long);
+ }
+ else
+#endif
+ {
+ *((int *) &arg_bytes[argindex]) = value_as_long (val_args[i]);
+ argindex += sizeof (int);
+ }
+ }
+
+ vprintf (string, arg_bytes);
+}
+
+extern struct cmd_list_element *enablelist, *disablelist, *deletelist;
+extern struct cmd_list_element *cmdlist, *setlist;
+
+void
+_initialize_printcmd ()
+{
+ current_display_number = -1;
+
+ add_info ("address", address_info,
+ "Describe where variable VAR is stored.");
+
+ add_com ("x", class_vars, x_command,
+ "Examine memory: x/FMT ADDRESS.\n\
+ADDRESS is an expression for the memory address to examine.\n\
+FMT is a repeat count followed by a format letter and a size letter.\n\
+Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\
+ f(float), a(address), i(instruction), c(char) and s(string).\n\
+Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\
+ g is meaningful only with f, for type double.\n\
+The specified number of objects of the specified size are printed\n\
+according to the format.\n\n\
+Defaults for format and size letters are those previously used.\n\
+Default count is 1. Default address is following last thing printed\n\
+with this command or \"print\".");
+
+ add_com ("ptype", class_vars, ptype_command,
+ "Print definition of type TYPE.\n\
+Argument may be a type name defined by typedef, or \"struct STRUCTNAME\"\n\
+or \"union UNIONNAME\" or \"enum ENUMNAME\".\n\
+The selected stack frame's lexical context is used to look up the name.");
+
+ add_com ("whatis", class_vars, whatis_command,
+ "Print data type of expression EXP.");
+
+ add_info ("display", display_info,
+ "Expressions to display when program stops, with code numbers.");
+
+ add_abbrev_cmd ("undisplay", class_vars, undisplay_command,
+ "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+\"delete display\" has the same effect as this command.\n\
+Do \"info display\" to see current list of code numbers.",
+ &cmdlist);
+
+ add_com ("display", class_vars, display_command,
+ "Print value of expression EXP each time the program stops.\n\
+/FMT may be used before EXP as in the \"print\" command.\n\
+/FMT \"i\" or \"s\" or including a size-letter is allowed,\n\
+as in the \"x\" command, and then EXP is used to get the address to examine\n\
+and examining is done as in the \"x\" command.\n\n\
+With no argument, display all currently requested auto-display expressions.\n\
+Use \"undisplay\" to cancel display requests previously made.");
+
+ add_cmd ("display", class_vars, enable_display,
+ "Enable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to resume displaying.\n\
+No argument means enable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &enablelist);
+
+ add_cmd ("display", class_vars, disable_display,
+ "Disable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means disable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &disablelist);
+
+ add_cmd ("display", class_vars, undisplay_command,
+ "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &deletelist);
+
+ add_com ("printf", class_vars, printf_command,
+ "printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\
+This is useful for formatted output in user-defined commands.");
+ add_com ("output", class_vars, output_command,
+ "Like \"print\" but don't put in value history and don't print newline.\n\
+This is useful in user-defined commands.");
+
+ add_prefix_cmd ("set", class_vars, set_command,
+"Perform an assignment VAR = EXP.\n\
+You must type the \"=\". VAR may be a debugger \"convenience\" variable\n\
+(names starting with $), a register (a few standard names starting with $),\n\
+or an actual variable in the program being debugged. EXP is any expression.\n\
+Use \"set variable\" for variables with names identical to set subcommands.\n\
+\nWith a subcommand, this command modifies parts of the gdb environment",
+ &setlist, "set ", 1, &cmdlist);
+
+ add_cmd ("variable", class_vars, set_command,
+ "Perform an assignment VAR = EXP.\n\
+You must type the \"=\". VAR may be a debugger \"convenience\" variable\n\
+(names starting with $), a register (a few standard names starting with $),\n\
+or an actual variable in the program being debugged. EXP is any expression.\n\
+This may usually be abbreviated to simply \"set\".",
+ &setlist);
+
+ add_com ("print", class_vars, print_command,
+ concat ("Print value of expression EXP.\n\
+Variables accessible are those of the lexical environment of the selected\n\
+stack frame, plus all those whose scope is global or an entire file.\n\
+\n\
+$NUM gets previous value number NUM. $ and $$ are the last two values.\n\
+$$NUM refers to NUM'th value back from the last one.\n\
+Names starting with $ refer to registers (with the values they would have\n\
+if the program were to return to the stack frame now selected, restoring\n\
+all registers saved by frames farther in) or else to debugger\n\
+\"convenience\" variables (any such name not a known register).\n\
+Use assignment expressions to give values to convenience variables.\n",
+ "\n\
+\{TYPE}ADREXP refers to a datum of data type TYPE, located at address ADREXP.\n\
+@@ is a binary operator for treating consecutive data objects\n\
+anywhere in memory as an array. FOO@@NUM gives an array whose first\n\
+element is FOO, whose second element is stored in the space following\n\
+where FOO is stored, etc. FOO must be an expression whose value\n\
+resides in memory.\n",
+ "\n\
+EXP may be preceded with /FMT, where FMT is a format letter\n\
+but no count or size letter (see \"x\" command)."));
+ add_com_alias ("p", "print", class_vars, 1);
+}
+
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@a191 1
+ int bigendian = 0;
+d196 7
+a202 5
+ {
+ union {
+ char a, b, c, d;
+ long i;
+ } x;
+a203 10
+ x.i = 1;
+ if (x.a)
+ {
+ /* Little endian */
+ tmp = v1;
+ v1 = v2;
+ v2 = tmp;
+ }
+ }
+
+d207 1
+a207 1
+ printf ("0x%08x%08x", v1, v2);
+d238 1
+a238 1
+ printf ("0x%02llx", val_long);
+d241 1
+a241 1
+ printf ("0x%04llx", val_long);
+d245 1
+a245 1
+ printf ("0x%08llx", val_long);
+d248 1
+a248 1
+ printf ("0x%16llx", val_long);
+d257 1
+a257 1
+ printf ("0x%02x", val_long);
+d260 1
+a260 1
+ printf ("0x%04x", val_long);
+d264 1
+a264 1
+ printf ("0x%08x", val_long);
+d267 1
+a267 1
+ printf ("0x%16x", val_long);
+d277 1
+a277 1
+ printf ("%lld", val_long);
+d279 1
+a279 1
+ printf ("%d", val_long);
+d285 1
+a285 1
+ printf ("%llu", val_long);
+d287 1
+a287 1
+ printf ("%u", val_long);
+d294 1
+a294 1
+ printf ("0%llo", val_long);
+d296 1
+a296 1
+ printf ("0%o", val_long);
+d299 1
+a299 1
+ printf ("0");
+d313 1
+a313 1
+ if (len == sizeof (double))
+d315 2
+d318 1
+a318 1
+ if (is_nan (unpack_double (type, valaddr)))
+d320 1
+a320 1
+ printf ("Nan");
+d324 10
+a333 4
+ if (len > 4)
+ printf ("%.16g", unpack_double (type, valaddr));
+ else
+ printf ("%.6g", unpack_double (type, valaddr));
+d515 1
+a515 1
+ printf ("$%d = ", histindex);
+@