/* Print values for GNU debugger GDB.
- Copyright (C) 1986-2020 Free Software Foundation, Inc.
+ Copyright (C) 1986-2021 Free Software Foundation, Inc.
This file is part of GDB.
#include "source.h"
#include "gdbsupport/byte-vector.h"
#include "gdbsupport/gdb_optional.h"
+#include "safe-ctype.h"
/* Last specified output format. */
/* We often wrap here if there are long symbolic names. */
wrap_here (" ");
next_address = (value_address (val)
- + gdb_print_insn (get_type_arch (type),
+ + gdb_print_insn (type->arch (),
value_address (val), stream,
&branch_delay_insns));
return;
}
if (options->format == 0 || options->format == 's'
+ || type->code () == TYPE_CODE_VOID
|| type->code () == TYPE_CODE_REF
|| type->code () == TYPE_CODE_ARRAY
|| type->code () == TYPE_CODE_STRING
static struct type *
float_type_from_length (struct type *type)
{
- struct gdbarch *gdbarch = get_type_arch (type);
+ struct gdbarch *gdbarch = type->arch ();
const struct builtin_type *builtin = builtin_type (gdbarch);
if (TYPE_LENGTH (type) == TYPE_LENGTH (builtin->builtin_float))
const struct value_print_options *options,
int size, struct ui_file *stream)
{
- struct gdbarch *gdbarch = get_type_arch (type);
+ struct gdbarch *gdbarch = type->arch ();
unsigned int len = TYPE_LENGTH (type);
enum bfd_endian byte_order = type_byte_order (type);
a negative signed value (e.g. "print/u (short)-1" should print 65535
(if shorts are 16 bits) instead of 4294967295). */
if (options->format != 'c'
- && (options->format != 'd' || TYPE_UNSIGNED (type)))
+ && (options->format != 'd' || type->is_unsigned ()))
{
if (len < TYPE_LENGTH (type) && byte_order == BFD_ENDIAN_BIG)
valaddr += TYPE_LENGTH (type) - len;
}
+ /* Allow LEN == 0, and in this case, don't assume that VALADDR is
+ valid. */
+ const gdb_byte zero = 0;
+ if (len == 0)
+ {
+ len = 1;
+ valaddr = &zero;
+ }
+
if (size != 0 && (options->format == 'x' || options->format == 't'))
{
/* Truncate to fit. */
long, and then printing the long. PR cli/16242 suggests changing
this to using C-style hex float format.
- Biased range types must also be unbiased here; the unbiasing is
- done by unpack_long. */
+ Biased range types and sub-word scalar types must also be handled
+ here; the value is correctly computed by unpack_long. */
gdb::byte_vector converted_bytes;
/* Some cases below will unpack the value again. In the biased
range case, we want to avoid this, so we store the unpacked value
here for possible use later. */
gdb::optional<LONGEST> val_long;
- if ((type->code () == TYPE_CODE_FLT
+ if (((type->code () == TYPE_CODE_FLT
+ || is_fixed_point_type (type))
&& (options->format == 'o'
|| options->format == 'x'
|| options->format == 't'
|| options->format == 'z'
|| options->format == 'd'
|| options->format == 'u'))
- || (type->code () == TYPE_CODE_RANGE
- && TYPE_RANGE_DATA (type)->bias != 0))
+ || (type->code () == TYPE_CODE_RANGE && type->bounds ()->bias != 0)
+ || type->bit_size_differs_p ())
{
val_long.emplace (unpack_long (type, valaddr));
converted_bytes.resize (TYPE_LENGTH (type));
{
type = float_type_from_length (type);
if (type->code () != TYPE_CODE_FLT)
- format = 0;
+ format = 0;
}
switch (format)
case 0:
if (type->code () != TYPE_CODE_FLT)
{
- print_decimal_chars (stream, valaddr, len, !TYPE_UNSIGNED (type),
+ print_decimal_chars (stream, valaddr, len, !type->is_unsigned (),
byte_order);
break;
}
val_long.emplace (unpack_long (type, valaddr));
opts.format = 0;
- if (TYPE_UNSIGNED (type))
+ if (type->is_unsigned ())
type = builtin_type (gdbarch)->builtin_true_unsigned_char;
else
type = builtin_type (gdbarch)->builtin_true_char;
int line = 0;
if (build_address_symbolic (gdbarch, addr, do_demangle, false, &name,
- &offset, &filename, &line, &unmapped))
+ &offset, &filename, &line, &unmapped))
return 0;
fputs_filtered (leadin, stream);
3) The symbol address is not identical to that of the address
under consideration. */
if (symbol == NULL ||
- (!prefer_sym_over_minsym
+ (!prefer_sym_over_minsym
&& BMSYMBOL_VALUE_ADDRESS (msymbol) == addr
&& name_location != addr))
{
static CORE_ADDR
find_instruction_backward (struct gdbarch *gdbarch, CORE_ADDR addr,
- int inst_count, int *inst_read)
+ int inst_count, int *inst_read)
{
/* The vector PCS is used to store instruction addresses within
a pc range. */
pcs.clear ();
sal = find_pc_sect_line (loop_start, NULL, 1);
if (sal.line <= 0)
- {
- /* We reach here when line info is not available. In this case,
- we print a message and just exit the loop. The return value
- is calculated after the loop. */
- printf_filtered (_("No line number information available "
- "for address "));
- wrap_here (" ");
- print_address (gdbarch, loop_start - 1, gdb_stdout);
- printf_filtered ("\n");
- break;
- }
+ {
+ /* We reach here when line info is not available. In this case,
+ we print a message and just exit the loop. The return value
+ is calculated after the loop. */
+ printf_filtered (_("No line number information available "
+ "for address "));
+ wrap_here (" ");
+ print_address (gdbarch, loop_start - 1, gdb_stdout);
+ printf_filtered ("\n");
+ break;
+ }
loop_end = loop_start;
loop_start = sal.pc;
/* This loop pushes instruction addresses in the range from
- LOOP_START to LOOP_END. */
+ LOOP_START to LOOP_END. */
for (p = loop_start; p < loop_end;)
- {
+ {
pcs.push_back (p);
- p += gdb_insn_length (gdbarch, p);
- }
+ p += gdb_insn_length (gdbarch, p);
+ }
inst_count -= pcs.size ();
*inst_read += pcs.size ();
the reason below.
Let's assume the following instruction addresses and run 'x/-4i 0x400e'.
Line X of File
- 0x4000
- 0x4001
- 0x4005
+ 0x4000
+ 0x4001
+ 0x4005
Line Y of File
- 0x4009
- 0x400c
+ 0x4009
+ 0x400c
=> 0x400e
- 0x4011
+ 0x4011
find_instruction_backward is called with INST_COUNT = 4 and expected to
return 0x4001. When we reach here, INST_COUNT is set to -1 because
it was subtracted by 2 (from Line Y) and 3 (from Line X). The value
static int
read_memory_backward (struct gdbarch *gdbarch,
- CORE_ADDR memaddr, gdb_byte *myaddr, int len)
+ CORE_ADDR memaddr, gdb_byte *myaddr, int len)
{
int errcode;
int nread; /* Number of bytes actually read. */
memaddr += len;
myaddr += len;
for (nread = 0; nread < len; ++nread)
- {
- errcode = target_read_memory (--memaddr, --myaddr, 1);
- if (errcode != 0)
- {
- /* The read was unsuccessful, so exit the loop. */
- printf_filtered (_("Cannot access memory at address %s\n"),
- paddress (gdbarch, memaddr));
- break;
- }
- }
+ {
+ errcode = target_read_memory (--memaddr, --myaddr, 1);
+ if (errcode != 0)
+ {
+ /* The read was unsuccessful, so exit the loop. */
+ printf_filtered (_("Cannot access memory at address %s\n"),
+ paddress (gdbarch, memaddr));
+ break;
+ }
+ }
}
return nread;
}
static CORE_ADDR
find_string_backward (struct gdbarch *gdbarch,
- CORE_ADDR addr, int count, int char_size,
- const struct value_print_options *options,
- int *strings_counted)
+ CORE_ADDR addr, int count, int char_size,
+ const struct value_print_options *options,
+ int *strings_counted)
{
const int chunk_size = 0x20;
int read_error = 0;
addr -= chars_to_read * char_size;
chars_read = read_memory_backward (gdbarch, addr, buffer.data (),
- chars_to_read * char_size);
+ chars_to_read * char_size);
chars_read /= char_size;
read_error = (chars_read == chars_to_read) ? 0 : 1;
/* Searching for '\0' from the end of buffer in backward direction. */
for (i = 0; i < chars_read && count > 0 ; ++i, ++chars_counted)
- {
- int offset = (chars_to_read - i - 1) * char_size;
-
- if (integer_is_zero (&buffer[offset], char_size)
- || chars_counted == options->print_max)
- {
- /* Found '\0' or reached print_max. As OFFSET is the offset to
- '\0', we add CHAR_SIZE to return the start address of
- a string. */
- --count;
- string_start_addr = addr + offset + char_size;
- chars_counted = 0;
- }
- }
+ {
+ int offset = (chars_to_read - i - 1) * char_size;
+
+ if (integer_is_zero (&buffer[offset], char_size)
+ || chars_counted == options->print_max)
+ {
+ /* Found '\0' or reached print_max. As OFFSET is the offset to
+ '\0', we add CHAR_SIZE to return the start address of
+ a string. */
+ --count;
+ string_start_addr = addr + offset + char_size;
+ chars_counted = 0;
+ }
+ }
}
/* Update STRINGS_COUNTED with the actual number of loaded strings. */
if (read_error != 0)
{
/* In error case, STRING_START_ADDR is pointing to the string that
- was last successfully loaded. Rewind the partially loaded string. */
+ was last successfully loaded. Rewind the partially loaded string. */
string_start_addr -= chars_counted * char_size;
}
else if (size == 'w')
char_type = builtin_type (next_gdbarch)->builtin_char32;
if (char_type)
- val_type = char_type;
+ val_type = char_type;
else
- {
+ {
if (size != '\0' && size != 'b')
warning (_("Unable to display strings with "
"size '%c', using 'b' instead."), size);
size = 'b';
val_type = builtin_type (next_gdbarch)->builtin_int8;
- }
+ }
}
maxelts = 8;
if (count < 0)
{
/* This is the negative repeat count case.
- We rewind the address based on the given repeat count and format,
- then examine memory from there in forward direction. */
+ We rewind the address based on the given repeat count and format,
+ then examine memory from there in forward direction. */
count = -count;
if (format == 'i')
- {
- next_address = find_instruction_backward (gdbarch, addr, count,
- &count);
- }
+ {
+ next_address = find_instruction_backward (gdbarch, addr, count,
+ &count);
+ }
else if (format == 's')
- {
- next_address = find_string_backward (gdbarch, addr, count,
- TYPE_LENGTH (val_type),
- &opts, &count);
- }
+ {
+ next_address = find_string_backward (gdbarch, addr, count,
+ TYPE_LENGTH (val_type),
+ &opts, &count);
+ }
else
- {
- next_address = addr - count * TYPE_LENGTH (val_type);
- }
+ {
+ next_address = addr - count * TYPE_LENGTH (val_type);
+ }
/* The following call to print_formatted updates next_address in every
- iteration. In backward case, we store the start address here
- and update next_address with it before exiting the function. */
+ iteration. In backward case, we store the start address here
+ and update next_address with it before exiting the function. */
addr_rewound = (format == 's'
- ? next_address - TYPE_LENGTH (val_type)
- : next_address);
+ ? next_address - TYPE_LENGTH (val_type)
+ : next_address);
need_to_update_next_address = 1;
}
/* Implementation of the "print" and "call" commands. */
static void
-print_command_1 (const char *args, int voidprint)
+print_command_1 (const char *args, bool voidprint)
{
struct value *val;
value_print_options print_opts;
if (exp != nullptr && *exp)
{
- expression_up expr = parse_expression (exp);
+ /* VOIDPRINT is true to indicate that we do want to print a void
+ value, so invert it for parse_expression. */
+ expression_up expr = parse_expression (exp, nullptr, !voidprint);
val = evaluate_expression (expr.get ());
}
else
print_value (val, print_opts);
}
+/* Called from command completion function to skip over /FMT
+ specifications, allowing the rest of the line to be completed. Returns
+ true if the /FMT is at the end of the current line and there is nothing
+ left to complete, otherwise false is returned.
+
+ In either case *ARGS can be updated to point after any part of /FMT that
+ is present.
+
+ This function is designed so that trying to complete '/' will offer no
+ completions, the user needs to insert the format specification
+ themselves. Trying to complete '/FMT' (where FMT is any non-empty set
+ of alpha-numeric characters) will cause readline to insert a single
+ space, setting the user up to enter the expression. */
+
+static bool
+skip_over_slash_fmt (completion_tracker &tracker, const char **args)
+{
+ const char *text = *args;
+
+ if (text[0] == '/')
+ {
+ bool in_fmt;
+ tracker.set_use_custom_word_point (true);
+
+ if (text[1] == '\0')
+ {
+ /* The user tried to complete after typing just the '/' character
+ of the /FMT string. Step the completer past the '/', but we
+ don't offer any completions. */
+ in_fmt = true;
+ ++text;
+ }
+ else
+ {
+ /* The user has typed some characters after the '/', we assume
+ this is a complete /FMT string, first skip over it. */
+ text = skip_to_space (text);
+
+ if (*text == '\0')
+ {
+ /* We're at the end of the input string. The user has typed
+ '/FMT' and asked for a completion. Push an empty
+ completion string, this will cause readline to insert a
+ space so the user now has '/FMT '. */
+ in_fmt = true;
+ tracker.add_completion (make_unique_xstrdup (text));
+ }
+ else
+ {
+ /* The user has already typed things after the /FMT, skip the
+ whitespace and return false. Whoever called this function
+ should then try to complete what comes next. */
+ in_fmt = false;
+ text = skip_spaces (text);
+ }
+ }
+
+ tracker.advance_custom_word_point_by (text - *args);
+ *args = text;
+ return in_fmt;
+ }
+
+ return false;
+}
+
/* See valprint.h. */
void
(tracker, &text, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER, group))
return;
+ if (skip_over_slash_fmt (tracker, &text))
+ return;
+
const char *word = advance_to_expression_complete_word_point (tracker, text);
expression_completer (ignore, tracker, text, word);
}
static void
print_command (const char *exp, int from_tty)
{
- print_command_1 (exp, 1);
+ print_command_1 (exp, true);
}
/* Same as print, except it doesn't print void results. */
static void
call_command (const char *exp, int from_tty)
{
- print_command_1 (exp, 0);
+ print_command_1 (exp, false);
}
/* Implementation of the "output" command. */
fputs_styled (paddress (gdbarch, load_addr), address_style.style (),
gdb_stdout);
printf_filtered (" in a file compiled without debugging");
- section = MSYMBOL_OBJ_SECTION (objfile, msymbol.minsym);
+ section = msymbol.minsym->obj_section (objfile);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
printf_filtered ("\" is ");
val = SYMBOL_VALUE (sym);
if (SYMBOL_OBJFILE_OWNED (sym))
- section = SYMBOL_OBJ_SECTION (symbol_objfile (sym), sym);
+ section = sym->obj_section (symbol_objfile (sym));
else
section = NULL;
gdbarch = symbol_arch (sym);
printf_filtered ("unresolved");
else
{
- section = MSYMBOL_OBJ_SECTION (msym.objfile, msym.minsym);
+ section = msym.obj_section ();
if (section
&& (section->the_bfd_section->flags & SEC_THREAD_LOCAL) != 0)
{
expression_up expr = parse_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. */
+ repeated with Newline. But don't clobber a user-defined
+ command's definition. */
if (from_tty)
set_repeat_arguments ("");
val = evaluate_expression (expr.get ());
if (TYPE_IS_REFERENCE (value_type (val)))
val = coerce_ref (val);
/* In rvalue contexts, such as this, functions are coerced into
- pointers to functions. This makes "x/i main" work. */
+ pointers to functions. This makes "x/i main" work. */
if (value_type (val)->code () == TYPE_CODE_FUNC
&& VALUE_LVAL (val) == lval_memory)
next_address = value_address (val);
if (last_examine_value != nullptr)
{
/* Make last address examined available to the user as $_. Use
- the correct pointer type. */
+ the correct pointer type. */
struct type *pointer_type
= lookup_pointer_type (value_type (last_examine_value.get ()));
set_internalvar (lookup_internalvar ("_"),
set_internalvar (lookup_internalvar ("__"), last_examine_value.get ());
}
}
+
+/* Command completion for the 'display' and 'x' commands. */
+
+static void
+display_and_x_command_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char * /*word*/)
+{
+ if (skip_over_slash_fmt (tracker, &text))
+ return;
+
+ const char *word = advance_to_expression_complete_word_point (tracker, text);
+ expression_completer (ignore, tracker, text, word);
+}
+
\f
/* Add an expression to the auto-display chain.
annotate_display_value ();
try
- {
+ {
struct value *val;
CORE_ADDR addr;
opts.raw = d->format.raw;
try
- {
+ {
struct value *val;
val = evaluate_expression (d->exp.get ());
if (d->pspace != pspace)
continue;
- if (lookup_objfile_from_block (d->block) == objfile
+ struct objfile *bl_objf = nullptr;
+ if (d->block != nullptr)
+ {
+ bl_objf = block_objfile (d->block);
+ if (bl_objf->separate_debug_objfile_backlink != nullptr)
+ bl_objf = bl_objf->separate_debug_objfile_backlink;
+ }
+
+ if (bl_objf == objfile
|| (d->exp != NULL && exp_uses_objfile (d->exp.get (), objfile)))
- {
- d->exp.reset ();
- d->block = NULL;
- }
+ {
+ d->exp.reset ();
+ d->block = NULL;
+ }
}
}
\f
if (!name)
name = var->print_name ();
- fprintf_filtered (stream, "%s%ps = ", n_spaces (2 * indent),
+ fprintf_filtered (stream, "%*s%ps = ", 2 * indent, "",
styled_string (variable_name_style.style (), name));
try
{
const gdb_byte *str;
size_t len;
- struct gdbarch *gdbarch = get_type_arch (value_type (value));
+ struct gdbarch *gdbarch = value_type (value)->arch ();
struct type *wctype = lookup_typename (current_language,
"wchar_t", NULL, 0);
int wcwidth = TYPE_LENGTH (wctype);
{
/* Parameter data. */
struct type *param_type = value_type (value);
- struct gdbarch *gdbarch = get_type_arch (param_type);
+ struct gdbarch *gdbarch = param_type->arch ();
/* Determine target type corresponding to the format string. */
struct type *fmt_type;
break;
case wide_char_arg:
{
- struct gdbarch *gdbarch
- = get_type_arch (value_type (val_args[i]));
+ struct gdbarch *gdbarch = value_type (val_args[i])->arch ();
struct type *wctype = lookup_typename (current_language,
"wchar_t", NULL, 0);
struct type *valtype;
DIAGNOSTIC_PUSH
DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
fprintf_filtered (stream, current_substring,
- obstack_base (&output));
+ obstack_base (&output));
DIAGNOSTIC_POP
}
break;
DIAGNOSTIC_PUSH
DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
- fprintf_filtered (stream, current_substring, val);
+ fprintf_filtered (stream, current_substring, val);
DIAGNOSTIC_POP
break;
}
DIAGNOSTIC_PUSH
DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
- fprintf_filtered (stream, current_substring, val);
+ fprintf_filtered (stream, current_substring, val);
DIAGNOSTIC_POP
break;
}
DIAGNOSTIC_PUSH
DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
- fprintf_filtered (stream, current_substring, val);
+ fprintf_filtered (stream, current_substring, val);
DIAGNOSTIC_POP
break;
}
DIAGNOSTIC_PUSH
DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
- fprintf_filtered (stream, current_substring, val);
+ fprintf_filtered (stream, current_substring, val);
DIAGNOSTIC_POP
break;
}
Usage: info symbol ADDR\n\
Only for symbols with fixed locations (global or static scope)."));
- add_com ("x", class_vars, x_command, _("\
+ c = 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\
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\"."));
+ set_cmd_completer_handle_brkchars (c, display_and_x_command_completer);
add_info ("display", info_display_command, _("\
Expressions to display when program stops, with code numbers.\n\
Do \"info display\" to see current list of code numbers."),
&cmdlist);
- add_com ("display", class_vars, display_command, _("\
+ c = add_com ("display", class_vars, display_command, _("\
Print value of expression EXP each time the program stops.\n\
Usage: display[/FMT] EXP\n\
/FMT may be used before EXP as in the \"print\" command.\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."));
+ set_cmd_completer_handle_brkchars (c, display_and_x_command_completer);
add_cmd ("display", class_vars, enable_display_command, _("\
Enable some expressions to be displayed when program stops.\n\