/* Parse expressions for GDB.
- Copyright (C) 1986-2021 Free Software Foundation, Inc.
+ Copyright (C) 1986-2023 Free Software Foundation, Inc.
Modified from expread.y by the Department of Computer Science at the
State University of New York at Buffalo, 1991.
#include "language.h"
#include "parser-defs.h"
#include "gdbcmd.h"
-#include "symfile.h" /* for overlay functions */
+#include "symfile.h"
#include "inferior.h"
#include "target-float.h"
#include "block.h"
#include "objfiles.h"
#include "user-regs.h"
#include <algorithm>
-#include "gdbsupport/gdb_optional.h"
+#include <optional>
#include "c-exp.h"
static unsigned int expressiondebug = 0;
show_expressiondebug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Expression debugging is %s.\n"), value);
+ gdb_printf (file, _("Expression debugging is %s.\n"), value);
}
/* True if an expression parser should set yydebug. */
-bool parser_debug;
+static bool parser_debug;
static void
show_parserdebug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Parser debugging is %s.\n"), value);
+ gdb_printf (file, _("Parser debugging is %s.\n"), value);
}
-static expression_up parse_exp_in_context (const char **, CORE_ADDR,
- const struct block *, int,
- bool, innermost_block_tracker *,
- expr_completion_state *);
-
/* Documented at it's declaration. */
void
{
if ((m_types & t) != 0
&& (m_innermost_block == NULL
- || contained_in (b, m_innermost_block)))
+ || m_innermost_block->contains (b)))
m_innermost_block = b;
}
\f
-/* Return the type of MSYMBOL, a minimal symbol of OBJFILE. If
- ADDRESS_P is not NULL, set it to the MSYMBOL's resolved
- address. */
-
-type *
-find_minsym_type_and_address (minimal_symbol *msymbol,
- struct objfile *objfile,
- CORE_ADDR *address_p)
+bool
+expr_complete_tag::complete (struct expression *exp,
+ completion_tracker &tracker)
{
- bound_minimal_symbol bound_msym = {msymbol, objfile};
- struct obj_section *section = msymbol->obj_section (objfile);
- enum minimal_symbol_type type = MSYMBOL_TYPE (msymbol);
-
- bool is_tls = (section != NULL
- && section->the_bfd_section->flags & SEC_THREAD_LOCAL);
-
- /* The minimal symbol might point to a function descriptor;
- resolve it to the actual code address instead. */
- CORE_ADDR addr;
- if (is_tls)
- {
- /* Addresses of TLS symbols are really offsets into a
- per-objfile/per-thread storage block. */
- addr = MSYMBOL_VALUE_RAW_ADDRESS (bound_msym.minsym);
- }
- else if (msymbol_is_function (objfile, msymbol, &addr))
- {
- if (addr != BMSYMBOL_VALUE_ADDRESS (bound_msym))
- {
- /* This means we resolved a function descriptor, and we now
- have an address for a code/text symbol instead of a data
- symbol. */
- if (MSYMBOL_TYPE (msymbol) == mst_data_gnu_ifunc)
- type = mst_text_gnu_ifunc;
- else
- type = mst_text;
- section = NULL;
- }
- }
- else
- addr = BMSYMBOL_VALUE_ADDRESS (bound_msym);
-
- if (overlay_debugging)
- addr = symbol_overlayed_address (addr, section);
-
- if (is_tls)
- {
- /* Skip translation if caller does not need the address. */
- if (address_p != NULL)
- *address_p = target_translate_tls_address (objfile, addr);
- return objfile_type (objfile)->nodebug_tls_symbol;
- }
-
- if (address_p != NULL)
- *address_p = addr;
-
- switch (type)
- {
- case mst_text:
- case mst_file_text:
- case mst_solib_trampoline:
- return objfile_type (objfile)->nodebug_text_symbol;
-
- case mst_text_gnu_ifunc:
- return objfile_type (objfile)->nodebug_text_gnu_ifunc_symbol;
-
- case mst_data:
- case mst_file_data:
- case mst_bss:
- case mst_file_bss:
- return objfile_type (objfile)->nodebug_data_symbol;
-
- case mst_slot_got_plt:
- return objfile_type (objfile)->nodebug_got_plt_symbol;
-
- default:
- return objfile_type (objfile)->nodebug_unknown_symbol;
- }
+ collect_symbol_completion_matches_type (tracker, m_name.get (),
+ m_name.get (), m_code);
+ return true;
}
/* See parser-defs.h. */
void
parser_state::mark_struct_expression (expr::structop_base_operation *op)
{
- gdb_assert (parse_completion
- && (m_completion_state.expout_tag_completion_type
- == TYPE_CODE_UNDEF));
- m_completion_state.expout_last_op = op;
+ gdb_assert (parse_completion && m_completion_state == nullptr);
+ m_completion_state.reset (new expr_complete_structop (op));
}
/* Indicate that the current parser invocation is completing a tag.
parser_state::mark_completion_tag (enum type_code tag, const char *ptr,
int length)
{
- gdb_assert (parse_completion
- && (m_completion_state.expout_tag_completion_type
- == TYPE_CODE_UNDEF)
- && m_completion_state.expout_completion_name == NULL
- && m_completion_state.expout_last_op == nullptr);
+ gdb_assert (parse_completion && m_completion_state == nullptr);
gdb_assert (tag == TYPE_CODE_UNION
|| tag == TYPE_CODE_STRUCT
|| tag == TYPE_CODE_ENUM);
- m_completion_state.expout_tag_completion_type = tag;
- m_completion_state.expout_completion_name
- = make_unique_xstrndup (ptr, length);
+ m_completion_state.reset
+ (new expr_complete_tag (tag, make_unique_xstrndup (ptr, length)));
}
/* See parser-defs.h. */
{
/* Just dollars (one or two). */
i = -negate;
- goto handle_last;
+ push_new<expr::last_operation> (i);
+ return;
}
/* Is the rest of the token digits? */
for (; i < str.length; i++)
i = atoi (str.ptr + 1 + negate);
if (negate)
i = -i;
- goto handle_last;
+ push_new<expr::last_operation> (i);
+ return;
}
/* Handle tokens that refer to machine registers:
i = user_reg_map_name_to_regnum (gdbarch (),
str.ptr + 1, str.length - 1);
if (i >= 0)
- goto handle_register;
+ {
+ str.length--;
+ str.ptr++;
+ push_new<expr::register_operation> (copy_name (str));
+ block_tracker->update (expression_context_block,
+ INNERMOST_BLOCK_FOR_REGISTERS);
+ return;
+ }
/* Any names starting with $ are probably debugger internal variables. */
push_new<expr::internalvar_operation>
(create_internalvar (copy.c_str () + 1));
- return;
-handle_last:
- push_new<expr::last_operation> (i);
- return;
-handle_register:
- str.length--;
- str.ptr++;
- push_new<expr::register_operation> (copy_name (str));
- block_tracker->update (expression_context_block,
- INNERMOST_BLOCK_FOR_REGISTERS);
- return;
}
\f
}
\f
-/* Read an expression from the string *STRINGPTR points to,
- parse it, and return a pointer to a struct expression that we malloc.
- Use block BLOCK as the lexical context for variable names;
- if BLOCK is zero, use the block of the selected stack frame.
- Meanwhile, advance *STRINGPTR to point after the expression,
- at the first nonwhite character that is not part of the expression
- (possibly a null character).
-
- If COMMA is nonzero, stop if a comma is reached. */
-
-expression_up
-parse_exp_1 (const char **stringptr, CORE_ADDR pc, const struct block *block,
- int comma, innermost_block_tracker *tracker)
-{
- return parse_exp_in_context (stringptr, pc, block, comma, false,
- tracker, nullptr);
-}
-
/* As for parse_exp_1, except that if VOID_CONTEXT_P, then
no value is expected from the expression. */
static expression_up
parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
const struct block *block,
- int comma, bool void_context_p,
+ parser_flags flags,
innermost_block_tracker *tracker,
- expr_completion_state *cstate)
+ std::unique_ptr<expr_completion_base> *completer)
{
const struct language_defn *lang = NULL;
if (tracker == nullptr)
tracker = &local_tracker;
- /* If no context specified, try using the current frame, if any. */
- if (!expression_context_block)
- expression_context_block = get_selected_block (&expression_context_pc);
- else if (pc == 0)
- expression_context_pc = BLOCK_ENTRY_PC (expression_context_block);
- else
- expression_context_pc = pc;
-
- /* Fall back to using the current source static context, if any. */
-
- if (!expression_context_block)
+ if ((flags & PARSER_LEAVE_BLOCK_ALONE) == 0)
{
- struct symtab_and_line cursal = get_current_source_symtab_and_line ();
- if (cursal.symtab)
+ /* If no context specified, try using the current frame, if any. */
+ if (!expression_context_block)
expression_context_block
- = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (cursal.symtab),
- STATIC_BLOCK);
- if (expression_context_block)
- expression_context_pc = BLOCK_ENTRY_PC (expression_context_block);
+ = get_selected_block (&expression_context_pc);
+ else if (pc == 0)
+ expression_context_pc = expression_context_block->entry_pc ();
+ else
+ expression_context_pc = pc;
+
+ /* Fall back to using the current source static context, if any. */
+
+ if (!expression_context_block)
+ {
+ struct symtab_and_line cursal
+ = get_current_source_symtab_and_line ();
+
+ if (cursal.symtab)
+ expression_context_block
+ = cursal.symtab->compunit ()->blockvector ()->static_block ();
+
+ if (expression_context_block)
+ expression_context_pc = expression_context_block->entry_pc ();
+ }
}
if (language_mode == language_mode_auto && block != NULL)
the current frame language to parse the expression. That's why
we do the following language detection only if the context block
has been specifically provided. */
- struct symbol *func = block_linkage_function (block);
+ struct symbol *func = block->linkage_function ();
if (func != NULL)
lang = language_def (func->language ());
to the value matching SELECTED_FRAME as set by get_current_arch. */
parser_state ps (lang, get_current_arch (), expression_context_block,
- expression_context_pc, comma, *stringptr,
- cstate != nullptr, tracker, void_context_p);
+ expression_context_pc, flags, *stringptr,
+ completer != nullptr, tracker);
scoped_restore_current_language lang_saver;
set_language (lang->la_language);
{
lang->parser (&ps);
}
- catch (const gdb_exception &except)
+ catch (const gdb_exception_error &except)
{
/* If parsing for completion, allow this to succeed; but if no
expression elements have been written, then there's nothing
result->op->set_outermost ();
if (expressiondebug)
- dump_prefix_expression (result.get (), gdb_stdlog);
+ result->dump (gdb_stdlog);
- if (cstate != nullptr)
- *cstate = std::move (ps.m_completion_state);
+ if (completer != nullptr)
+ *completer = std::move (ps.m_completion_state);
*stringptr = ps.lexptr;
return result;
}
+/* Read an expression from the string *STRINGPTR points to,
+ parse it, and return a pointer to a struct expression that we malloc.
+ Use block BLOCK as the lexical context for variable names;
+ if BLOCK is zero, use the block of the selected stack frame.
+ Meanwhile, advance *STRINGPTR to point after the expression,
+ at the first nonwhite character that is not part of the expression
+ (possibly a null character). FLAGS are passed to the parser. */
+
+expression_up
+parse_exp_1 (const char **stringptr, CORE_ADDR pc, const struct block *block,
+ parser_flags flags, innermost_block_tracker *tracker)
+{
+ return parse_exp_in_context (stringptr, pc, block, flags,
+ tracker, nullptr);
+}
+
/* Parse STRING as an expression, and complain if this fails to use up
all of the contents of STRING. TRACKER, if non-null, will be
- updated by the parser. VOID_CONTEXT_P should be true to indicate
- that the expression may be expected to return a value with void
- type. Parsers are free to ignore this, or to use it to help with
- overload resolution decisions. */
+ updated by the parser. FLAGS are passed to the parser. */
expression_up
parse_expression (const char *string, innermost_block_tracker *tracker,
- bool void_context_p)
+ parser_flags flags)
{
- expression_up exp = parse_exp_in_context (&string, 0, nullptr, 0,
- void_context_p,
+ expression_up exp = parse_exp_in_context (&string, 0, nullptr, flags,
tracker, nullptr);
if (*string)
error (_("Junk after end of expression."));
expression_up
parse_expression_with_language (const char *string, enum language lang)
{
- gdb::optional<scoped_restore_current_language> lang_saver;
+ std::optional<scoped_restore_current_language> lang_saver;
if (current_language->la_language != lang)
{
lang_saver.emplace ();
return parse_expression (string);
}
-/* Parse STRING as an expression. If parsing ends in the middle of a
- field reference, return the type of the left-hand-side of the
- reference; furthermore, if the parsing ends in the field name,
- return the field name in *NAME. If the parsing ends in the middle
- of a field reference, but the reference is somehow invalid, throw
- an exception. In all other cases, return NULL. */
-
-struct type *
-parse_expression_for_completion (const char *string,
- gdb::unique_xmalloc_ptr<char> *name,
- enum type_code *code)
+/* Parse STRING as an expression. If the parse is marked for
+ completion, set COMPLETER and return the expression. In all other
+ cases, return NULL. */
+
+expression_up
+parse_expression_for_completion
+ (const char *string,
+ std::unique_ptr<expr_completion_base> *completer)
{
expression_up exp;
- expr_completion_state cstate;
try
{
- exp = parse_exp_in_context (&string, 0, 0, 0, false, nullptr, &cstate);
+ exp = parse_exp_in_context (&string, 0, 0, 0, nullptr, completer);
}
catch (const gdb_exception_error &except)
{
/* Nothing, EXP remains NULL. */
}
- if (exp == NULL)
- return NULL;
-
- if (cstate.expout_tag_completion_type != TYPE_CODE_UNDEF)
- {
- *code = cstate.expout_tag_completion_type;
- *name = std::move (cstate.expout_completion_name);
- return NULL;
- }
-
- if (cstate.expout_last_op == nullptr)
+ /* If we didn't get a completion result, be sure to also not return
+ an expression to our caller. */
+ if (*completer == nullptr)
return nullptr;
- expr::structop_base_operation *op = cstate.expout_last_op;
- const std::string &fld = op->get_string ();
- *name = make_unique_xstrdup (fld.c_str ());
- return value_type (op->evaluate_lhs (exp.get ()));
+ return exp;
}
/* Parse floating point value P of length LEN.
{
return target_float_from_string (data, type, std::string (p, len));
}
+
+/* Return true if the number N_SIGN * N fits in a type with TYPE_BITS and
+ TYPE_SIGNED_P. N_SIGNED is either 1 or -1. */
+
+bool
+fits_in_type (int n_sign, ULONGEST n, int type_bits, bool type_signed_p)
+{
+ /* Normalize -0. */
+ if (n == 0 && n_sign == -1)
+ n_sign = 1;
+
+ if (n_sign == -1 && !type_signed_p)
+ /* Can't fit a negative number in an unsigned type. */
+ return false;
+
+ if (type_bits > sizeof (ULONGEST) * 8)
+ return true;
+
+ ULONGEST smax = (ULONGEST)1 << (type_bits - 1);
+ if (n_sign == -1)
+ {
+ /* Negative number, signed type. */
+ return (n <= smax);
+ }
+ else if (n_sign == 1 && type_signed_p)
+ {
+ /* Positive number, signed type. */
+ return (n < smax);
+ }
+ else if (n_sign == 1 && !type_signed_p)
+ {
+ /* Positive number, unsigned type. */
+ return ((n >> 1) >> (type_bits - 1)) == 0;
+ }
+ else
+ gdb_assert_not_reached ("");
+}
+
+/* Return true if the number N_SIGN * N fits in a type with TYPE_BITS and
+ TYPE_SIGNED_P. N_SIGNED is either 1 or -1. */
+
+bool
+fits_in_type (int n_sign, const gdb_mpz &n, int type_bits, bool type_signed_p)
+{
+ /* N must be nonnegative. */
+ gdb_assert (n.sgn () >= 0);
+
+ /* Zero always fits. */
+ /* Normalize -0. */
+ if (n.sgn () == 0)
+ return true;
+
+ if (n_sign == -1 && !type_signed_p)
+ /* Can't fit a negative number in an unsigned type. */
+ return false;
+
+ gdb_mpz max = gdb_mpz::pow (2, (type_signed_p
+ ? type_bits - 1
+ : type_bits));
+ if (n_sign == -1)
+ return n <= max;
+ return n < max;
+}
\f
/* This function avoids direct calls to fprintf
in the parser generated debug code. */
va_start (args, y);
if (x == stderr)
- vfprintf_unfiltered (gdb_stderr, y, args);
+ gdb_vprintf (gdb_stderr, y, args);
else
{
- fprintf_unfiltered (gdb_stderr, " Unknown FILE used.\n");
- vfprintf_unfiltered (gdb_stderr, y, args);
+ gdb_printf (gdb_stderr, " Unknown FILE used.\n");
+ gdb_vprintf (gdb_stderr, y, args);
}
va_end (args);
}
-/* Return rue if EXP uses OBJFILE (and will become dangling when
- OBJFILE is unloaded), otherwise return false. OBJFILE must not be
- a separate debug info file. */
-
-bool
-exp_uses_objfile (struct expression *exp, struct objfile *objfile)
-{
- gdb_assert (objfile->separate_debug_objfile_backlink == NULL);
-
- return exp->op->uses_objfile (objfile);
-}
-
void _initialize_parse ();
void
_initialize_parse ()