| /* Parse expressions for GDB. | |
| Copyright (C) 1986-2021 Free Software Foundation, Inc. | |
| Modified from expread.y by the Department of Computer Science at the | |
| State University of New York at Buffalo, 1991. | |
| This file is part of GDB. | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 3 of the License, or | |
| (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
| /* Parse an expression from text in a string, | |
| and return the result as a struct expression pointer. | |
| That structure contains arithmetic operations in reverse polish, | |
| with constants represented by operations that are followed by special data. | |
| See expression.h for the details of the format. | |
| What is important here is that it can be built up sequentially | |
| during the process of parsing; the lower levels of the tree always | |
| come first in the result. */ | |
| #include "defs.h" | |
| #include <ctype.h> | |
| #include "arch-utils.h" | |
| #include "symtab.h" | |
| #include "gdbtypes.h" | |
| #include "frame.h" | |
| #include "expression.h" | |
| #include "value.h" | |
| #include "command.h" | |
| #include "language.h" | |
| #include "parser-defs.h" | |
| #include "gdbcmd.h" | |
| #include "symfile.h" /* for overlay functions */ | |
| #include "inferior.h" | |
| #include "target-float.h" | |
| #include "block.h" | |
| #include "source.h" | |
| #include "objfiles.h" | |
| #include "user-regs.h" | |
| #include <algorithm> | |
| #include "gdbsupport/gdb_optional.h" | |
| #include "c-exp.h" | |
| static unsigned int expressiondebug = 0; | |
| static void | |
| 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); | |
| } | |
| /* True if an expression parser should set yydebug. */ | |
| 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); | |
| } | |
| 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 | |
| innermost_block_tracker::update (const struct block *b, | |
| innermost_block_tracker_types t) | |
| { | |
| if ((m_types & t) != 0 | |
| && (m_innermost_block == NULL | |
| || contained_in (b, m_innermost_block))) | |
| m_innermost_block = b; | |
| } | |
| /* 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) | |
| { | |
| 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; | |
| } | |
| } | |
| /* 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; | |
| } | |
| /* Indicate that the current parser invocation is completing a tag. | |
| TAG is the type code of the tag, and PTR and LENGTH represent the | |
| start of the tag name. */ | |
| void | |
| 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 (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); | |
| } | |
| /* See parser-defs.h. */ | |
| void | |
| parser_state::push_c_string (int kind, struct stoken_vector *vec) | |
| { | |
| std::vector<std::string> data (vec->len); | |
| for (int i = 0; i < vec->len; ++i) | |
| data[i] = std::string (vec->tokens[i].ptr, vec->tokens[i].length); | |
| push_new<expr::c_string_operation> ((enum c_string_type_values) kind, | |
| std::move (data)); | |
| } | |
| /* See parser-defs.h. */ | |
| void | |
| parser_state::push_symbol (const char *name, block_symbol sym) | |
| { | |
| if (sym.symbol != nullptr) | |
| { | |
| if (symbol_read_needs_frame (sym.symbol)) | |
| block_tracker->update (sym); | |
| push_new<expr::var_value_operation> (sym); | |
| } | |
| else | |
| { | |
| struct bound_minimal_symbol msymbol = lookup_bound_minimal_symbol (name); | |
| if (msymbol.minsym != NULL) | |
| push_new<expr::var_msym_value_operation> (msymbol); | |
| else if (!have_full_symbols () && !have_partial_symbols ()) | |
| error (_("No symbol table is loaded. Use the \"file\" command.")); | |
| else | |
| error (_("No symbol \"%s\" in current context."), name); | |
| } | |
| } | |
| /* See parser-defs.h. */ | |
| void | |
| parser_state::push_dollar (struct stoken str) | |
| { | |
| struct block_symbol sym; | |
| struct bound_minimal_symbol msym; | |
| struct internalvar *isym = NULL; | |
| std::string copy; | |
| /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) | |
| and $$digits (equivalent to $<-digits> if you could type that). */ | |
| int negate = 0; | |
| int i = 1; | |
| /* Double dollar means negate the number and add -1 as well. | |
| Thus $$ alone means -1. */ | |
| if (str.length >= 2 && str.ptr[1] == '$') | |
| { | |
| negate = 1; | |
| i = 2; | |
| } | |
| if (i == str.length) | |
| { | |
| /* Just dollars (one or two). */ | |
| i = -negate; | |
| goto handle_last; | |
| } | |
| /* Is the rest of the token digits? */ | |
| for (; i < str.length; i++) | |
| if (!(str.ptr[i] >= '0' && str.ptr[i] <= '9')) | |
| break; | |
| if (i == str.length) | |
| { | |
| i = atoi (str.ptr + 1 + negate); | |
| if (negate) | |
| i = -i; | |
| goto handle_last; | |
| } | |
| /* Handle tokens that refer to machine registers: | |
| $ followed by a register name. */ | |
| i = user_reg_map_name_to_regnum (gdbarch (), | |
| str.ptr + 1, str.length - 1); | |
| if (i >= 0) | |
| goto handle_register; | |
| /* Any names starting with $ are probably debugger internal variables. */ | |
| copy = copy_name (str); | |
| isym = lookup_only_internalvar (copy.c_str () + 1); | |
| if (isym) | |
| { | |
| push_new<expr::internalvar_operation> (isym); | |
| return; | |
| } | |
| /* On some systems, such as HP-UX and hppa-linux, certain system routines | |
| have names beginning with $ or $$. Check for those, first. */ | |
| sym = lookup_symbol (copy.c_str (), NULL, VAR_DOMAIN, NULL); | |
| if (sym.symbol) | |
| { | |
| push_new<expr::var_value_operation> (sym); | |
| return; | |
| } | |
| msym = lookup_bound_minimal_symbol (copy.c_str ()); | |
| if (msym.minsym) | |
| { | |
| push_new<expr::var_msym_value_operation> (msym); | |
| return; | |
| } | |
| /* Any other names are assumed to be 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; | |
| } | |
| const char * | |
| find_template_name_end (const char *p) | |
| { | |
| int depth = 1; | |
| int just_seen_right = 0; | |
| int just_seen_colon = 0; | |
| int just_seen_space = 0; | |
| if (!p || (*p != '<')) | |
| return 0; | |
| while (*++p) | |
| { | |
| switch (*p) | |
| { | |
| case '\'': | |
| case '\"': | |
| case '{': | |
| case '}': | |
| /* In future, may want to allow these?? */ | |
| return 0; | |
| case '<': | |
| depth++; /* start nested template */ | |
| if (just_seen_colon || just_seen_right || just_seen_space) | |
| return 0; /* but not after : or :: or > or space */ | |
| break; | |
| case '>': | |
| if (just_seen_colon || just_seen_right) | |
| return 0; /* end a (nested?) template */ | |
| just_seen_right = 1; /* but not after : or :: */ | |
| if (--depth == 0) /* also disallow >>, insist on > > */ | |
| return ++p; /* if outermost ended, return */ | |
| break; | |
| case ':': | |
| if (just_seen_space || (just_seen_colon > 1)) | |
| return 0; /* nested class spec coming up */ | |
| just_seen_colon++; /* we allow :: but not :::: */ | |
| break; | |
| case ' ': | |
| break; | |
| default: | |
| if (!((*p >= 'a' && *p <= 'z') || /* allow token chars */ | |
| (*p >= 'A' && *p <= 'Z') || | |
| (*p >= '0' && *p <= '9') || | |
| (*p == '_') || (*p == ',') || /* commas for template args */ | |
| (*p == '&') || (*p == '*') || /* pointer and ref types */ | |
| (*p == '(') || (*p == ')') || /* function types */ | |
| (*p == '[') || (*p == ']'))) /* array types */ | |
| return 0; | |
| } | |
| if (*p != ' ') | |
| just_seen_space = 0; | |
| if (*p != ':') | |
| just_seen_colon = 0; | |
| if (*p != '>') | |
| just_seen_right = 0; | |
| } | |
| return 0; | |
| } | |
| /* Return a null-terminated temporary copy of the name of a string token. | |
| Tokens that refer to names do so with explicit pointer and length, | |
| so they can share the storage that lexptr is parsing. | |
| When it is necessary to pass a name to a function that expects | |
| a null-terminated string, the substring is copied out | |
| into a separate block of storage. */ | |
| std::string | |
| copy_name (struct stoken token) | |
| { | |
| return std::string (token.ptr, token.length); | |
| } | |
| /* 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, | |
| innermost_block_tracker *tracker, | |
| expr_completion_state *cstate) | |
| { | |
| const struct language_defn *lang = NULL; | |
| if (*stringptr == 0 || **stringptr == 0) | |
| error_no_arg (_("expression to compute")); | |
| const struct block *expression_context_block = block; | |
| CORE_ADDR expression_context_pc = 0; | |
| innermost_block_tracker local_tracker; | |
| 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) | |
| { | |
| struct symtab_and_line cursal = get_current_source_symtab_and_line (); | |
| if (cursal.symtab) | |
| expression_context_block | |
| = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (cursal.symtab), | |
| STATIC_BLOCK); | |
| if (expression_context_block) | |
| expression_context_pc = BLOCK_ENTRY_PC (expression_context_block); | |
| } | |
| if (language_mode == language_mode_auto && block != NULL) | |
| { | |
| /* Find the language associated to the given context block. | |
| Default to the current language if it can not be determined. | |
| Note that using the language corresponding to the current frame | |
| can sometimes give unexpected results. For instance, this | |
| routine is often called several times during the inferior | |
| startup phase to re-parse breakpoint expressions after | |
| a new shared library has been loaded. The language associated | |
| to the current frame at this moment is not relevant for | |
| the breakpoint. Using it would therefore be silly, so it seems | |
| better to rely on the current language rather than relying on | |
| 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); | |
| if (func != NULL) | |
| lang = language_def (func->language ()); | |
| if (lang == NULL || lang->la_language == language_unknown) | |
| lang = current_language; | |
| } | |
| else | |
| lang = current_language; | |
| /* get_current_arch may reset CURRENT_LANGUAGE via select_frame. | |
| While we need CURRENT_LANGUAGE to be set to LANG (for lookup_symbol | |
| and others called from *.y) ensure CURRENT_LANGUAGE gets restored | |
| 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); | |
| scoped_restore_current_language lang_saver; | |
| set_language (lang->la_language); | |
| try | |
| { | |
| lang->parser (&ps); | |
| } | |
| catch (const gdb_exception &except) | |
| { | |
| /* If parsing for completion, allow this to succeed; but if no | |
| expression elements have been written, then there's nothing | |
| to do, so fail. */ | |
| if (! ps.parse_completion || ps.expout->op == nullptr) | |
| throw; | |
| } | |
| expression_up result = ps.release (); | |
| result->op->set_outermost (); | |
| if (expressiondebug) | |
| dump_prefix_expression (result.get (), gdb_stdlog); | |
| if (cstate != nullptr) | |
| *cstate = std::move (ps.m_completion_state); | |
| *stringptr = ps.lexptr; | |
| return result; | |
| } | |
| /* 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. */ | |
| expression_up | |
| parse_expression (const char *string, innermost_block_tracker *tracker, | |
| bool void_context_p) | |
| { | |
| expression_up exp = parse_exp_in_context (&string, 0, nullptr, 0, | |
| void_context_p, | |
| tracker, nullptr); | |
| if (*string) | |
| error (_("Junk after end of expression.")); | |
| return exp; | |
| } | |
| /* Same as parse_expression, but using the given language (LANG) | |
| to parse the expression. */ | |
| expression_up | |
| parse_expression_with_language (const char *string, enum language lang) | |
| { | |
| gdb::optional<scoped_restore_current_language> lang_saver; | |
| if (current_language->la_language != lang) | |
| { | |
| lang_saver.emplace (); | |
| set_language (lang); | |
| } | |
| 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) | |
| { | |
| expression_up exp; | |
| expr_completion_state cstate; | |
| try | |
| { | |
| exp = parse_exp_in_context (&string, 0, 0, 0, false, nullptr, &cstate); | |
| } | |
| 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) | |
| 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 ())); | |
| } | |
| /* Parse floating point value P of length LEN. | |
| Return false if invalid, true if valid. | |
| The successfully parsed number is stored in DATA in | |
| target format for floating-point type TYPE. | |
| NOTE: This accepts the floating point syntax that sscanf accepts. */ | |
| bool | |
| parse_float (const char *p, int len, | |
| const struct type *type, gdb_byte *data) | |
| { | |
| return target_float_from_string (data, type, std::string (p, len)); | |
| } | |
| /* This function avoids direct calls to fprintf | |
| in the parser generated debug code. */ | |
| void | |
| parser_fprintf (FILE *x, const char *y, ...) | |
| { | |
| va_list args; | |
| va_start (args, y); | |
| if (x == stderr) | |
| vfprintf_unfiltered (gdb_stderr, y, args); | |
| else | |
| { | |
| fprintf_unfiltered (gdb_stderr, " Unknown FILE used.\n"); | |
| vfprintf_unfiltered (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 () | |
| { | |
| add_setshow_zuinteger_cmd ("expression", class_maintenance, | |
| &expressiondebug, | |
| _("Set expression debugging."), | |
| _("Show expression debugging."), | |
| _("When non-zero, the internal representation " | |
| "of expressions will be printed."), | |
| NULL, | |
| show_expressiondebug, | |
| &setdebuglist, &showdebuglist); | |
| add_setshow_boolean_cmd ("parser", class_maintenance, | |
| &parser_debug, | |
| _("Set parser debugging."), | |
| _("Show parser debugging."), | |
| _("When non-zero, expression parser " | |
| "tracing will be enabled."), | |
| NULL, | |
| show_parserdebug, | |
| &setdebuglist, &showdebuglist); | |
| } |