#include "dfp.h"
#include "python/python.h"
#include "ada-lang.h"
+#include "gdb_obstack.h"
+#include "charset.h"
+#include <ctype.h>
#include <errno.h>
static int
valprint_check_validity (struct ui_file *stream,
struct type *type,
- int offset,
+ int embedded_offset,
const struct value *val)
{
CHECK_TYPEDEF (type);
&& TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_ARRAY)
{
- if (! value_bits_valid (val, TARGET_CHAR_BIT * offset,
- TARGET_CHAR_BIT * TYPE_LENGTH (type)))
+ if (!value_bits_valid (val, TARGET_CHAR_BIT * embedded_offset,
+ TARGET_CHAR_BIT * TYPE_LENGTH (type)))
{
val_print_optimized_out (stream);
return 0;
}
- if (value_bits_synthetic_pointer (val, TARGET_CHAR_BIT * offset,
+ if (value_bits_synthetic_pointer (val, TARGET_CHAR_BIT * embedded_offset,
TARGET_CHAR_BIT * TYPE_LENGTH (type)))
{
fputs_filtered (_("<synthetic pointer>"), stream);
return 0;
}
+
+ if (!value_bytes_available (val, embedded_offset, TYPE_LENGTH (type)))
+ {
+ val_print_unavailable (stream);
+ return 0;
+ }
}
return 1;
fprintf_filtered (stream, _("<optimized out>"));
}
-/* Print using the given LANGUAGE the data of type TYPE located at VALADDR
- (within GDB), which came from the inferior at address ADDRESS, onto
- stdio stream STREAM according to OPTIONS.
-
- If the data are a string pointer, returns the number of string characters
- printed.
+void
+val_print_unavailable (struct ui_file *stream)
+{
+ fprintf_filtered (stream, _("<unavailable>"));
+}
- FIXME: The data at VALADDR is in target byte order. If gdb is ever
- enhanced to be able to debug more than the single target it was compiled
- for (specific CPU type and thus specific target byte ordering), then
- either the print routines are going to have to take this into account,
- or the data is going to have to be passed into here already converted
- to the host byte ordering, whichever is more convenient. */
+void
+val_print_invalid_address (struct ui_file *stream)
+{
+ fprintf_filtered (stream, _("<invalid address>"));
+}
+/* Print using the given LANGUAGE the data of type TYPE located at
+ VALADDR + EMBEDDED_OFFSET (within GDB), which came from the
+ inferior at address ADDRESS + EMBEDDED_OFFSET, onto stdio stream
+ STREAM according to OPTIONS. VAL is the whole object that came
+ from ADDRESS. VALADDR must point to the head of VAL's contents
+ buffer.
+
+ The language printers will pass down an adjusted EMBEDDED_OFFSET to
+ further helper subroutines as subfields of TYPE are printed. In
+ such cases, VALADDR is passed down unadjusted, as well as VAL, so
+ that VAL can be queried for metadata about the contents data being
+ printed, using EMBEDDED_OFFSET as an offset into VAL's contents
+ buffer. For example: "has this field been optimized out", or "I'm
+ printing an object while inspecting a traceframe; has this
+ particular piece of data been collected?".
+
+ RECURSE indicates the amount of indentation to supply before
+ continuation lines; this amount is roughly twice the value of
+ RECURSE.
+
+ If the data is printed as a string, returns the number of string
+ characters printed. */
int
val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
}
}
fputs_filtered ("]", stream);
+
+/* Print a scalar of data of type TYPE, pointed to in GDB by VALADDR,
+ according to OPTIONS and SIZE on STREAM. Format i is not supported
+ at this level.
+
+ This is how the elements of an array or structure are printed
+ with a format. */
+}
+
+void
+val_print_scalar_formatted (struct type *type,
+ const gdb_byte *valaddr, int embedded_offset,
+ const struct value *val,
+ const struct value_print_options *options,
+ int size,
+ struct ui_file *stream)
+{
+ gdb_assert (val != NULL);
+ gdb_assert (valaddr == value_contents_for_printing_const (val));
+
+ /* If we get here with a string format, try again without it. Go
+ all the way back to the language printers, which may call us
+ again. */
+ if (options->format == 's')
+ {
+ struct value_print_options opts = *options;
+ opts.format = 0;
+ opts.deref_ref = 0;
+ val_print (type, valaddr, embedded_offset, 0, stream, 0, val, &opts,
+ current_language);
+ return;
+ }
+
+ /* A scalar object that does not have all bits available can't be
+ printed, because all bits contribute to its representation. */
+ if (!value_bits_valid (val, TARGET_CHAR_BIT * embedded_offset,
+ TARGET_CHAR_BIT * TYPE_LENGTH (type)))
+ val_print_optimized_out (stream);
+ else if (!value_bytes_available (val, embedded_offset, TYPE_LENGTH (type)))
+ val_print_unavailable (stream);
+ else
+ print_scalar_formatted (valaddr + embedded_offset, type,
+ options, size, stream);
}
/* Print a number according to FORMAT which is one of d,u,x,o,b,h,w,g.
rep1 = i + 1;
reps = 1;
- while (rep1 < len
- && memcmp (valaddr + embedded_offset + i * eltlen,
- valaddr + embedded_offset + rep1 * eltlen,
- eltlen) == 0)
+ /* Only check for reps if repeat_count_threshold is not set to
+ UINT_MAX (unlimited). */
+ if (options->repeat_count_threshold < UINT_MAX)
{
- ++reps;
- ++rep1;
+ while (rep1 < len
+ && value_available_contents_eq (val,
+ embedded_offset + i * eltlen,
+ val,
+ (embedded_offset
+ + rep1 * eltlen),
+ eltlen))
+ {
+ ++reps;
+ ++rep1;
+ }
}
if (reps > options->repeat_count_threshold)
return errcode;
}
+/* Return true if print_wchar can display W without resorting to a
+ numeric escape, false otherwise. */
+
+static int
+wchar_printable (gdb_wchar_t w)
+{
+ return (gdb_iswprint (w)
+ || w == LCST ('\a') || w == LCST ('\b')
+ || w == LCST ('\f') || w == LCST ('\n')
+ || w == LCST ('\r') || w == LCST ('\t')
+ || w == LCST ('\v'));
+}
+
+/* A helper function that converts the contents of STRING to wide
+ characters and then appends them to OUTPUT. */
+
+static void
+append_string_as_wide (const char *string,
+ struct obstack *output)
+{
+ for (; *string; ++string)
+ {
+ gdb_wchar_t w = gdb_btowc (*string);
+ obstack_grow (output, &w, sizeof (gdb_wchar_t));
+ }
+}
+
+/* Print a wide character W to OUTPUT. ORIG is a pointer to the
+ original (target) bytes representing the character, ORIG_LEN is the
+ number of valid bytes. WIDTH is the number of bytes in a base
+ characters of the type. OUTPUT is an obstack to which wide
+ characters are emitted. QUOTER is a (narrow) character indicating
+ the style of quotes surrounding the character to be printed.
+ NEED_ESCAPE is an in/out flag which is used to track numeric
+ escapes across calls. */
+
+static void
+print_wchar (gdb_wint_t w, const gdb_byte *orig,
+ int orig_len, int width,
+ enum bfd_endian byte_order,
+ struct obstack *output,
+ int quoter, int *need_escapep)
+{
+ int need_escape = *need_escapep;
+
+ *need_escapep = 0;
+ if (gdb_iswprint (w) && (!need_escape || (!gdb_iswdigit (w)
+ && w != LCST ('8')
+ && w != LCST ('9'))))
+ {
+ gdb_wchar_t wchar = w;
+
+ if (w == gdb_btowc (quoter) || w == LCST ('\\'))
+ obstack_grow_wstr (output, LCST ("\\"));
+ obstack_grow (output, &wchar, sizeof (gdb_wchar_t));
+ }
+ else
+ {
+ switch (w)
+ {
+ case LCST ('\a'):
+ obstack_grow_wstr (output, LCST ("\\a"));
+ break;
+ case LCST ('\b'):
+ obstack_grow_wstr (output, LCST ("\\b"));
+ break;
+ case LCST ('\f'):
+ obstack_grow_wstr (output, LCST ("\\f"));
+ break;
+ case LCST ('\n'):
+ obstack_grow_wstr (output, LCST ("\\n"));
+ break;
+ case LCST ('\r'):
+ obstack_grow_wstr (output, LCST ("\\r"));
+ break;
+ case LCST ('\t'):
+ obstack_grow_wstr (output, LCST ("\\t"));
+ break;
+ case LCST ('\v'):
+ obstack_grow_wstr (output, LCST ("\\v"));
+ break;
+ default:
+ {
+ int i;
+
+ for (i = 0; i + width <= orig_len; i += width)
+ {
+ char octal[30];
+ ULONGEST value;
+
+ value = extract_unsigned_integer (&orig[i], width,
+ byte_order);
+ /* If the value fits in 3 octal digits, print it that
+ way. Otherwise, print it as a hex escape. */
+ if (value <= 0777)
+ sprintf (octal, "\\%.3o", (int) (value & 0777));
+ else
+ sprintf (octal, "\\x%lx", (long) value);
+ append_string_as_wide (octal, output);
+ }
+ /* If we somehow have extra bytes, print them now. */
+ while (i < orig_len)
+ {
+ char octal[5];
+
+ sprintf (octal, "\\%.3o", orig[i] & 0xff);
+ append_string_as_wide (octal, output);
+ ++i;
+ }
+
+ *need_escapep = 1;
+ }
+ break;
+ }
+ }
+}
+
+/* Print the character C on STREAM as part of the contents of a
+ literal string whose delimiter is QUOTER. ENCODING names the
+ encoding of C. */
+
+void
+generic_emit_char (int c, struct type *type, struct ui_file *stream,
+ int quoter, const char *encoding)
+{
+ enum bfd_endian byte_order
+ = gdbarch_byte_order (get_type_arch (type));
+ struct obstack wchar_buf, output;
+ struct cleanup *cleanups;
+ gdb_byte *buf;
+ struct wchar_iterator *iter;
+ int need_escape = 0;
+
+ buf = alloca (TYPE_LENGTH (type));
+ pack_long (buf, type, c);
+
+ iter = make_wchar_iterator (buf, TYPE_LENGTH (type),
+ encoding, TYPE_LENGTH (type));
+ cleanups = make_cleanup_wchar_iterator (iter);
+
+ /* This holds the printable form of the wchar_t data. */
+ obstack_init (&wchar_buf);
+ make_cleanup_obstack_free (&wchar_buf);
+
+ while (1)
+ {
+ int num_chars;
+ gdb_wchar_t *chars;
+ const gdb_byte *buf;
+ size_t buflen;
+ int print_escape = 1;
+ enum wchar_iterate_result result;
+
+ num_chars = wchar_iterate (iter, &result, &chars, &buf, &buflen);
+ if (num_chars < 0)
+ break;
+ if (num_chars > 0)
+ {
+ /* If all characters are printable, print them. Otherwise,
+ we're going to have to print an escape sequence. We
+ check all characters because we want to print the target
+ bytes in the escape sequence, and we don't know character
+ boundaries there. */
+ int i;
+
+ print_escape = 0;
+ for (i = 0; i < num_chars; ++i)
+ if (!wchar_printable (chars[i]))
+ {
+ print_escape = 1;
+ break;
+ }
+
+ if (!print_escape)
+ {
+ for (i = 0; i < num_chars; ++i)
+ print_wchar (chars[i], buf, buflen,
+ TYPE_LENGTH (type), byte_order,
+ &wchar_buf, quoter, &need_escape);
+ }
+ }
+
+ /* This handles the NUM_CHARS == 0 case as well. */
+ if (print_escape)
+ print_wchar (gdb_WEOF, buf, buflen, TYPE_LENGTH (type),
+ byte_order, &wchar_buf, quoter, &need_escape);
+ }
+
+ /* The output in the host encoding. */
+ obstack_init (&output);
+ make_cleanup_obstack_free (&output);
+
+ convert_between_encodings (INTERMEDIATE_ENCODING, host_charset (),
+ obstack_base (&wchar_buf),
+ obstack_object_size (&wchar_buf),
+ 1, &output, translit_char);
+ obstack_1grow (&output, '\0');
+
+ fputs_filtered (obstack_base (&output), stream);
+
+ do_cleanups (cleanups);
+}
+
+/* Print the character string STRING, printing at most LENGTH
+ characters. LENGTH is -1 if the string is nul terminated. TYPE is
+ the type of each character. OPTIONS holds the printing options;
+ printing stops early if the number hits print_max; repeat counts
+ are printed as appropriate. Print ellipses at the end if we had to
+ stop before printing LENGTH characters, or if FORCE_ELLIPSES.
+ QUOTE_CHAR is the character to print at each end of the string. If
+ C_STYLE_TERMINATOR is true, and the last character is 0, then it is
+ omitted. */
+
+void
+generic_printstr (struct ui_file *stream, struct type *type,
+ const gdb_byte *string, unsigned int length,
+ const char *encoding, int force_ellipses,
+ int quote_char, int c_style_terminator,
+ const struct value_print_options *options)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+ unsigned int i;
+ unsigned int things_printed = 0;
+ int in_quotes = 0;
+ int need_comma = 0;
+ int width = TYPE_LENGTH (type);
+ struct obstack wchar_buf, output;
+ struct cleanup *cleanup;
+ struct wchar_iterator *iter;
+ int finished = 0;
+ int need_escape = 0;
+ gdb_wchar_t wide_quote_char = gdb_btowc (quote_char);
+
+ if (length == -1)
+ {
+ unsigned long current_char = 1;
+
+ for (i = 0; current_char; ++i)
+ {
+ QUIT;
+ current_char = extract_unsigned_integer (string + i * width,
+ width, byte_order);
+ }
+ length = i;
+ }
+
+ /* If the string was not truncated due to `set print elements', and
+ the last byte of it is a null, we don't print that, in
+ traditional C style. */
+ if (c_style_terminator
+ && !force_ellipses
+ && length > 0
+ && (extract_unsigned_integer (string + (length - 1) * width,
+ width, byte_order) == 0))
+ length--;
+
+ if (length == 0)
+ {
+ fputs_filtered ("\"\"", stream);
+ return;
+ }
+
+ /* Arrange to iterate over the characters, in wchar_t form. */
+ iter = make_wchar_iterator (string, length * width, encoding, width);
+ cleanup = make_cleanup_wchar_iterator (iter);
+
+ /* WCHAR_BUF is the obstack we use to represent the string in
+ wchar_t form. */
+ obstack_init (&wchar_buf);
+ make_cleanup_obstack_free (&wchar_buf);
+
+ while (!finished && things_printed < options->print_max)
+ {
+ int num_chars;
+ enum wchar_iterate_result result;
+ gdb_wchar_t *chars;
+ const gdb_byte *buf;
+ size_t buflen;
+
+ QUIT;
+
+ if (need_comma)
+ {
+ obstack_grow_wstr (&wchar_buf, LCST (", "));
+ need_comma = 0;
+ }
+
+ num_chars = wchar_iterate (iter, &result, &chars, &buf, &buflen);
+ /* We only look at repetitions when we were able to convert a
+ single character in isolation. This makes the code simpler
+ and probably does the sensible thing in the majority of
+ cases. */
+ while (num_chars == 1 && things_printed < options->print_max)
+ {
+ /* Count the number of repetitions. */
+ unsigned int reps = 0;
+ gdb_wchar_t current_char = chars[0];
+ const gdb_byte *orig_buf = buf;
+ int orig_len = buflen;
+
+ if (need_comma)
+ {
+ obstack_grow_wstr (&wchar_buf, LCST (", "));
+ need_comma = 0;
+ }
+
+ while (num_chars == 1 && current_char == chars[0])
+ {
+ num_chars = wchar_iterate (iter, &result, &chars,
+ &buf, &buflen);
+ ++reps;
+ }
+
+ /* Emit CURRENT_CHAR according to the repetition count and
+ options. */
+ if (reps > options->repeat_count_threshold)
+ {
+ if (in_quotes)
+ {
+ if (options->inspect_it)
+ obstack_grow_wstr (&wchar_buf, LCST ("\\"));
+ obstack_grow (&wchar_buf, &wide_quote_char,
+ sizeof (gdb_wchar_t));
+ obstack_grow_wstr (&wchar_buf, LCST (", "));
+ in_quotes = 0;
+ }
+ obstack_grow_wstr (&wchar_buf, LCST ("'"));
+ need_escape = 0;
+ print_wchar (current_char, orig_buf, orig_len, width,
+ byte_order, &wchar_buf, '\'', &need_escape);
+ obstack_grow_wstr (&wchar_buf, LCST ("'"));
+ {
+ /* Painful gyrations. */
+ int j;
+ char *s = xstrprintf (_(" <repeats %u times>"), reps);
+
+ for (j = 0; s[j]; ++j)
+ {
+ gdb_wchar_t w = gdb_btowc (s[j]);
+ obstack_grow (&wchar_buf, &w, sizeof (gdb_wchar_t));
+ }
+ xfree (s);
+ }
+ things_printed += options->repeat_count_threshold;
+ need_comma = 1;
+ }
+ else
+ {
+ /* Saw the character one or more times, but fewer than
+ the repetition threshold. */
+ if (!in_quotes)
+ {
+ if (options->inspect_it)
+ obstack_grow_wstr (&wchar_buf, LCST ("\\"));
+ obstack_grow (&wchar_buf, &wide_quote_char,
+ sizeof (gdb_wchar_t));
+ in_quotes = 1;
+ need_escape = 0;
+ }
+
+ while (reps-- > 0)
+ {
+ print_wchar (current_char, orig_buf,
+ orig_len, width,
+ byte_order, &wchar_buf,
+ quote_char, &need_escape);
+ ++things_printed;
+ }
+ }
+ }
+
+ /* NUM_CHARS and the other outputs from wchar_iterate are valid
+ here regardless of which branch was taken above. */
+ if (num_chars < 0)
+ {
+ /* Hit EOF. */
+ finished = 1;
+ break;
+ }
+
+ switch (result)
+ {
+ case wchar_iterate_invalid:
+ if (!in_quotes)
+ {
+ if (options->inspect_it)
+ obstack_grow_wstr (&wchar_buf, LCST ("\\"));
+ obstack_grow (&wchar_buf, &wide_quote_char,
+ sizeof (gdb_wchar_t));
+ in_quotes = 1;
+ }
+ need_escape = 0;
+ print_wchar (gdb_WEOF, buf, buflen, width, byte_order,
+ &wchar_buf, quote_char, &need_escape);
+ break;
+
+ case wchar_iterate_incomplete:
+ if (in_quotes)
+ {
+ if (options->inspect_it)
+ obstack_grow_wstr (&wchar_buf, LCST ("\\"));
+ obstack_grow (&wchar_buf, &wide_quote_char,
+ sizeof (gdb_wchar_t));
+ obstack_grow_wstr (&wchar_buf, LCST (","));
+ in_quotes = 0;
+ }
+ obstack_grow_wstr (&wchar_buf,
+ LCST (" <incomplete sequence "));
+ print_wchar (gdb_WEOF, buf, buflen, width,
+ byte_order, &wchar_buf,
+ 0, &need_escape);
+ obstack_grow_wstr (&wchar_buf, LCST (">"));
+ finished = 1;
+ break;
+ }
+ }
+
+ /* Terminate the quotes if necessary. */
+ if (in_quotes)
+ {
+ if (options->inspect_it)
+ obstack_grow_wstr (&wchar_buf, LCST ("\\"));
+ obstack_grow (&wchar_buf, &wide_quote_char,
+ sizeof (gdb_wchar_t));
+ }
+
+ if (force_ellipses || !finished)
+ obstack_grow_wstr (&wchar_buf, LCST ("..."));
+
+ /* OUTPUT is where we collect `char's for printing. */
+ obstack_init (&output);
+ make_cleanup_obstack_free (&output);
+
+ convert_between_encodings (INTERMEDIATE_ENCODING, host_charset (),
+ obstack_base (&wchar_buf),
+ obstack_object_size (&wchar_buf),
+ 1, &output, translit_char);
+ obstack_1grow (&output, '\0');
+
+ fputs_filtered (obstack_base (&output), stream);
+
+ do_cleanups (cleanup);
+}
+
/* Print a string from the inferior, starting at ADDR and printing up to LEN
characters, of WIDTH bytes a piece, to STREAM. If LEN is -1, printing
stops at the first null byte, otherwise printing proceeds (including null