1999-04-16 09:35:26 +08:00
|
|
|
|
/* Evaluate expressions for GDB.
|
2003-01-13 Andrew Cagney <ac131313@redhat.com>
* ax-gdb.c, c-valprint.c, charset.c, corefile.c: Update copyright.
* demangle.c, disasm.c, dwarf2cfi.c, dwarfread.c: Update copyright.
* elfread.c, eval.c, expprint.c, expression.h: Update copyright.
* f-typeprint.c, findvar.c, gcore.c, gdb_mbuild.sh: Update copyright.
* gdbtypes.h, gnu-v2-abi.c, inferior.h, inftarg.c: Update copyright.
* language.c, language.h, m32r-tdep.c: Update copyright.
* mn10200-tdep.c, scm-lang.c, scm-lang.h: Update copyright.
* somsolib.c, somsolib.h, symfile.c, symtab.h: Update copyright.
* thread-db.c, typeprint.c, utils.c, valarith.c: Update copyright.
* values.c, win32-nat.c, x86-64-linux-nat.c: Update copyright.
* x86-64-linux-tdep.c, z8k-tdep.c: Update copyright.
* cli/cli-decode.h, config/h8500/tm-h8500.h: Update copyright.
Index: mi/ChangeLog
2003-01-13 Andrew Cagney <ac131313@redhat.com>
* mi-cmd-env.c: Update copyright.
2003-01-14 08:49:06 +08:00
|
|
|
|
|
2024-01-12 23:30:44 +08:00
|
|
|
|
Copyright (C) 1986-2024 Free Software Foundation, Inc.
|
1999-04-16 09:35:26 +08:00
|
|
|
|
|
1999-07-08 04:19:36 +08:00
|
|
|
|
This file is part of GDB.
|
1999-04-16 09:35:26 +08:00
|
|
|
|
|
1999-07-08 04:19:36 +08:00
|
|
|
|
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
|
2007-08-24 02:08:50 +08:00
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
1999-07-08 04:19:36 +08:00
|
|
|
|
(at your option) any later version.
|
1999-04-16 09:35:26 +08:00
|
|
|
|
|
1999-07-08 04:19:36 +08:00
|
|
|
|
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.
|
1999-04-16 09:35:26 +08:00
|
|
|
|
|
1999-07-08 04:19:36 +08:00
|
|
|
|
You should have received a copy of the GNU General Public License
|
2007-08-24 02:08:50 +08:00
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
1999-04-16 09:35:26 +08:00
|
|
|
|
|
2019-04-07 03:38:10 +08:00
|
|
|
|
#include "symtab.h"
|
|
|
|
|
#include "gdbtypes.h"
|
|
|
|
|
#include "value.h"
|
1999-04-16 09:35:26 +08:00
|
|
|
|
#include "expression.h"
|
2019-04-07 03:38:10 +08:00
|
|
|
|
#include "target.h"
|
1999-04-16 09:35:26 +08:00
|
|
|
|
#include "frame.h"
|
2014-11-11 21:43:03 +08:00
|
|
|
|
#include "gdbthread.h"
|
2023-09-20 10:34:23 +08:00
|
|
|
|
#include "language.h"
|
2019-04-07 03:38:10 +08:00
|
|
|
|
#include "cp-abi.h"
|
2003-04-21 Andrew Cagney <cagney@redhat.com>
* infcall.c: New file.
* infcall.h: New file.
* valarith.c: Include "infcall.h".
* scm-lang.c, objc-lang.cm, hppa-tdep.c, gcore.c: Ditto.
* eval.c, ada-valprint.c, ada-lang.c: Ditto.
* Makefile.in (valarith.o, scm-lang.o): Update dependencies.
(objc-lang.o, hppa-tdep.o, gcore.o): Update dependencies.
(eval.o, ada-valprint.o, ada-lang.o): Update dependencies.
(SFILES): Add "infcall.c"
(COMMON_OBS): Add "infcall.o".
(infcall.o): Specify dependencies.
* value.h (call_function_by_hand): Delete declaration.
* inferior.h (run_stack_dummy): Delete declaration.
* infcmd.c (breakpoint_auto_delete_contents): Move to "infcall.c".
(run_stack_dummy): Move to "infcall.c", merged into
call_function_by_hand.
* valops.c (call_function_by_hand): Moved to "infcall.c".
(find_function_addr, value_arg_coerce): Ditto.
(unwindonsignal_p, coerce_float_to_double): Ditto.
(_initialize_valops): Move "set/show coerce-float-to-double", and
"set/show unwindonsignal" commands to "infcall.c".
* v850-tdep.c, target.h: Update comments.
* sparc-tdep.c (sparc_fix_call_dummy): Update comments.
* sh-tdep.c (sh_init_extra_frame_info): Update comments.
(sh64_init_extra_frame_info): Update comments.
* mn10300-tdep.c: Update comments.
* mcore-tdep.c (mcore_init_extra_frame_info): Update comments.
* config/sparc/tm-sparc.h: Update comments.
* breakpoint.h: Update comments.
* avr-tdep.c (avr_init_extra_frame_info): Update comments.
* arm-tdep.c: Update comment.
2003-04-22 00:48:41 +08:00
|
|
|
|
#include "infcall.h"
|
2003-04-30 09:27:53 +08:00
|
|
|
|
#include "objc-lang.h"
|
2019-04-07 03:38:10 +08:00
|
|
|
|
#include "block.h"
|
* parser-defs.h (struct exp_descriptor): New definition, containing
language-specific info for printing, prefixifying, dumping, and
evaluating expressions.
(exp_descriptor_standard): Declare new variable.
(print_subexp): Make global and declare here (from expprint.c).
(dump_subexp): Ditto.
(dump_subexp_body_standard): Declare.
(operator_length_standard): Declare.
(op_name_standard): Declare.
(print_subexp): Declare.
(print_subexp_standard): Declare.
* language.h (struct language_defn): Add la_exp_desc field to hold
pointer to table for language-specific operators.
Remove evaluate_exp field, which is now in struct exp_descriptor.
* parse.c (operator_length): Move most code to new
operator_length_standard function. Use language-specific information.
(operator_length_standard): New function taking most code from
operator_length.
(exp_descriptor_standard): New constant.
* expression.h (enum exp_opcode): Add definitions of OP_EXTENDED0
and OP_EXTENDED_LAST.
* expprint.c (print_subexp): Use language-specific print_subexp.
Make global; remove static declaration.
Move most code to print_subexp_standard.
(print_subexp_standard): New function, containing code formerly in
print_subexp.
(op_name): Add expression to argument signature.
Use langauge-specific op_name.
Move most code to op_name_standard.
(op_name_standard): New function, containing code formerly in op_name.
(dump_subexp): Use new version of op_name function.
Use language-specific dump_subexp_body, and move most existing code to
dump_subexp_body_standard.
(dump_raw_expression): Use new op_name interface.
(dump_subexp_body): Move most code to dump_subexp_body_standard.
(dump_subexp_body_standard): New function, containing code formerly
in dump_subexp_body.
* language.c (unknown_language): Add default la_exp_desc field and
remove evaluate_exp field.
(auto_language): Ditto.
(local_language): Ditto.
* f-lang.c (f_language_defn): Ditto.
* c-lang.c (c_language_defn): Ditto.
(cplus_language_defn): Ditto.
(asm_language_defn): Ditto.
(minimal_language_defn): Ditto.
* p-lang.c (pascal_language_defn): Ditto.
* m2-lang.c (m2_language_defn): Ditto.
* objc-lang.c (objc_language_defn): Ditto.
* jv-lang.c (exp_descriptor_java): New variable, containing
Java-specific expression evaluator.
(java_language_defn): Add la_exp_desc field and remove evaluate_exp
field.
* scm-lang.c (exp_descriptor_scm): New variable, containing
Scheme-specific expression evaluator.
(scm_language_defn): Add la_exp_desc field and remove evaluate_exp
field.
* objc-lang.c (print_object_command): Take evaluate_exp from the
la_exp_desc field.
* Makefile.in (eval.o): Add dependency on parser-defs.h.
* eval.c: Include parser-defs.h for the full declaration of
la_exp_desc's type.
(evaluate_subexp): Get evaluate_exp out of la_exp_desc field.
2003-09-25 16:40:45 +08:00
|
|
|
|
#include "parser-defs.h"
|
2019-04-07 03:38:10 +08:00
|
|
|
|
#include "cp-support.h"
|
2019-04-03 10:04:24 +08:00
|
|
|
|
#include "ui-out.h"
|
2019-04-07 03:38:10 +08:00
|
|
|
|
#include "regcache.h"
|
2008-08-22 04:13:08 +08:00
|
|
|
|
#include "user-regs.h"
|
gdb
* varobj.c (value_get_print_value): Include valprint.h.
(value_get_print_value): Use get_formatted_print_options.
* value.h (struct value_print_options): Declare.
(value_print, val_print, common_val_print, val_print_string):
Update.
* value.c: Include valprint.h.
(show_values): Use get_user_print_options.
(show_convenience): Likewise.
* valprint.h (prettyprint_arrays, prettyprint_structs): Don't
declare.
(struct value_print_options): New type.
(vtblprint, unionprint, addressprint, objectprint, print_max,
inspect_it, repeat_count_threshold, output_format,
stop_print_at_null): Don't declare.
(user_print_options, get_user_print_options,
get_raw_print_options, get_formatted_print_options): Declare.
(print_array_indexes_p): Don't declare.
(maybe_print_array_index, val_print_array_elements): Update.
* valprint.c (print_max): Remove.
(user_print_options): New global.
(get_user_print_options, get_raw_print_options,
get_formatted_print_options): New functions.
(print_array_indexes, repeat_count_threshold, stop_print_at_null,
prettyprint_structs, prettyprint_arrays, unionprint,
addressprint): Remove.
(val_print): Remove format, deref_ref, pretty arguments; add
options. Update.
(common_val_print): Likewise.
(print_array_indexes_p): Remove.
(maybe_print_array_index): Remove format, pretty arguments; add
options. Update.
(val_print_array_elements): Remove format, deref_ref, pretty
arguments; add options. Update.
(val_print_string): Add options argument. Update.
(_initialize_valprint): Use user_print_options.
(output_format): Remove.
(set_output_radix_1): Use user_print_options.
* typeprint.c: Include valprint.h.
(objectprint): Don't declare.
(whatis_exp): Use get_user_print_options.
* tui/tui-regs.c: Include valprint.h.
(tui_register_format): Use get_formatted_print_options.
* tracepoint.c: Include valprint.h.
(addressprint): Don't declare.
(trace_mention): Use get_user_print_options.
(tracepoints_info): Likewise.
* stack.c (print_frame_args): Use get_raw_print_options.
(print_frame_info): Use get_user_print_options.
(print_frame): Likewise.
* sh64-tdep.c: Include valprint.h
(sh64_do_register): Use get_formatted_print_options.
* scm-valprint.c (scm_inferior_print): Remove format, deref_ref,
pretty arguments; add options.
(scm_scmlist_print): Likewise. Update.
(scm_scmval_print): Likewise.
(scm_val_print): Likewise.
(scm_value_print): Remove format, pretty arguments; add options.
Update.
* scm-lang.h (scm_value_print, scm_val_print, scm_scmval_print):
Update.
* scm-lang.c (scm_printstr): Add options argument.
* python/python-value.c: Include valprint.h.
(valpy_str): Use get_user_print_options.
* printcmd.c: Include valprint.h.
(addressprint): Don't declare.
(inspect_it): Remove.
(print_formatted): Remove format option; add options. Update.
(print_scalar_formatted): Likewise.
(print_address_demangle): Use get_user_print_options.
(do_examine): Use get_formatted_print_options.
(print_command_1): Likewise.
(output_command): Use get_formatted_print_options.
(do_one_display): Likewise.
(print_variable_value): Use get_user_print_options.
* p-valprint.c (pascal_val_print): Remove format, deref_ref,
pretty arguments; add options. Update.
(pascal_value_print): Remove format, pretty arguments; add
options. Update.
(vtblprint, objectprint): Don't declare.
(pascal_static_field_print): Remove.
(pascal_object_print_value_fields): Remove format, pretty
arguments; add options. Update.
(pascal_object_print_static_field): Likewise.
(_initialize_pascal_valprint): Use user_print_options. Update.
* p-lang.h (pascal_val_print, pascal_value_print,
pascal_printstr, pascal_object_print_value_fields): Update.
(vtblprint, static_field_print): Don't declare.
* p-lang.c (pascal_printstr): Add options argument. Update.
* objc-lang.c (objc_printstr): Add options argument. Update.
* mt-tdep.c: Include valprint.h.
(mt_registers_info): Use get_raw_print_options.
* mips-tdep.c: Include valprint.h.
(mips_print_fp_register): Use get_formatted_print_options.
(mips_print_register): Likewise.
* mi/mi-main.c: Include valprint.h.
(get_register): Use get_user_print_options.
(mi_cmd_data_evaluate_expression): Likewise.
(mi_cmd_data_read_memory): Use get_formatted_print_options.
* mi/mi-cmd-stack.c: Include valprint.h.
(list_args_or_locals): Use get_raw_print_options.
* m2-valprint.c (print_function_pointer_address): Add addressprint
argument.
(m2_print_long_set): Remove format, pretty arguments.
(m2_print_unbounded_array): Remove format, deref_ref, pretty
arguments; add options. Update.
(print_unpacked_pointer): Remove format argument; add options.
Now static. Update.
(print_variable_at_address): Remove format, deref_ref, pretty
arguments; add options. Update.
(m2_print_array_contents): Likewise.
(m2_val_print): Likewise.
* m2-lang.h (m2_val_print): Update.
* m2-lang.c (m2_printstr): Add options argument. Update.
* language.h (struct value_print_options): Declare.
(struct language_defn) <la_printstr>: Add options argument.
<la_val_print>: Remove format, deref_ref, pretty argument; add
options.
<la_value_print>: Remove format, pretty arguments; add options.
<la_print_array_index>: Likewise.
(LA_VAL_PRINT, LA_VALUE_PRINT, LA_PRINT_STRING,
LA_PRINT_ARRAY_INDEX): Update.
(default_print_array_index): Update.
* language.c (default_print_array_index): Remove format, pretty
arguments; add options. Update.
(unk_lang_printstr): Add options argument.
(unk_lang_val_print): Remove format, deref_ref, pretty arguments;
add options.
(unk_lang_value_print): Remove format, pretty arguments; add
options.
* jv-valprint.c (java_value_print): Remove format, pretty
arguments; add options. Update.
(java_print_value_fields): Likewise.
(java_val_print): Remove format, deref_ref, pretty arguments; add
options. Update.
* jv-lang.h (java_val_print, java_value_print): Declare.
* infcmd.c: Include valprint.h.
(print_return_value): Use get_raw_print_options.
(default_print_registers_info): Use get_user_print_options,
get_formatted_print_options.
(registers_info): Use get_formatted_print_options.
* gdbtypes.h (struct value_print_options): Declare.
(print_scalar_formatted): Update.
* f-valprint.c (f77_print_array_1): Remove format, deref_ref,
pretty arguments; add options. Update.
(f77_print_array): Likewise.
(f_val_print): Likewise.
* f-lang.h (f_val_print): Update.
* f-lang.c (f_printstr): Add options argument. Update.
(c_value_print): Update declaration.
* expprint.c: Include valprint.h.
(print_subexp_standard): Use get_raw_print_options,
get_user_print_options.
* eval.c: Include valprint.h.
(objectprint): Don't declare.
(evaluate_subexp_standard): Use get_user_print_options.
* cp-valprint.c (vtblprint, objectprint, static_field_print):
Remove.
(cp_print_value_fields): Remove format, pretty arguments; add
options. Update.
(cp_print_value): Likewise.
(cp_print_static_field): Likewise.
(_initialize_cp_valprint): Use user_print_options. Update.
* c-valprint.c (print_function_pointer_address): Add addressprint
argument.
(c_val_print): Remove format, deref_ref, pretty arguments; add
options. Update.
(c_value_print): Add options argument. Update.
* c-lang.h (c_val_print, c_value_print, c_printstr): Update.
(vtblprint, static_field_print): Don't declare.
(cp_print_value_fields): Update.
* c-lang.c (c_printstr): Add options argument. Update.
* breakpoint.c: Include valprint.h.
(addressprint): Don't declare.
(watchpoint_value_print): Use get_user_print_options.
(print_one_breakpoint_location): Likewise.
(breakpoint_1, print_it_catch_fork, print_it_catch_vfork, mention,
print_exception_catchpoint): Likewise.
* auxv.c (fprint_target_auxv): Don't declare addressprint. Use
get_user_print_options.
* ada-valprint.c (struct ada_val_print_args): Remove format,
deref_ref, and pretty; add options.
(print_optional_low_bound): Add options argument.
(val_print_packed_array_elements): Remove format and pretty
arguments; add options. Update.
(printstr): Add options argument. Update.
(ada_printstr): Likewise.
(ada_val_print): Remove format, deref_ref, pretty arguments; add
options argument. Update.
(ada_val_print_stub): Update.
(ada_val_print_array): Remove format, deref_ref, pretty arguments;
add options. Update.
(ada_val_print_1): Likewise.
(print_variant_part): Likewise.
(ada_value_print): Remove format, pretty arguments; add options.
Update.
(print_record): Likewise.
(print_field_values): Likewise.
* ada-lang.h (ada_val_print, ada_value_print, ada_printstr):
Update.
* ada-lang.c (ada_print_array_index): Add options argument; remove
format and pretty arguments.
(print_one_exception): Use get_user_print_options.
gdb/testsuite
* gdb.base/exprs.exp (test_expr): Add enum formatting tests.
2008-10-29 01:19:58 +08:00
|
|
|
|
#include "valprint.h"
|
2021-12-22 07:38:32 +08:00
|
|
|
|
#include "gdbsupport/gdb_obstack.h"
|
2019-04-07 03:38:10 +08:00
|
|
|
|
#include "objfiles.h"
|
|
|
|
|
#include "typeprint.h"
|
|
|
|
|
#include <ctype.h>
|
Introduce class operation
This patch introduces class operation, the new base class for all
expression operations.
In the new approach, an operation is simply a class that presents a
certain interface. Operations own their operands, and management is
done via unique_ptr.
The operation interface is largely ad hoc, based on the evolution of
expression handling in GDB. Parts (for example,
evaluate_with_coercion) are probably redundant; however I took this
approach to try to avoid mixing different kinds of refactorings.
In some specific situations, rather than add a generic method across
the entire operation class hierarchy, I chose instead to use
dynamic_cast and specialized methods on certain concrete subclasses.
This will appear in some subsequent patches.
One goal of this work is to avoid the kinds of easy-to-make errors
that affected the old implementation. To this end, some helper
subclasses are also added here. These helpers automate the
implementation of the 'dump', 'uses_objfile', and 'constant_p'
methods. Nearly every concrete operation that is subsequently added
will use these facilities. (Note that the 'dump' implementation is
only outlined here, the body appears in the next patch.)
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* expression.h (expr::operation): New class.
(expr::make_operation): New function.
(expr::operation_up): New typedef.
* expop.h: New file.
* eval.c (operation::evaluate_for_cast)
(operation::evaluate_for_address, operation::evaluate_for_sizeof):
New methods.
* ax-gdb.c (operation::generate_ax): New method.
2021-03-08 22:27:57 +08:00
|
|
|
|
#include "expop.h"
|
2021-03-08 22:27:57 +08:00
|
|
|
|
#include "c-exp.h"
|
2021-03-25 06:08:12 +08:00
|
|
|
|
#include "inferior.h"
|
gdb/
2009-03-05 Tom Tromey <tromey@redhat.com>
Add support for convenience functions in Python.
* Makefile.in (SUBDIR_PYTHON_OBS): Add python-function.o.
(SUBDIR_PYTHON_SRCS): Add python-function.c.
(python-function.o): New target.
* eval.c: Include "python/python.h" and <ctype.h>.
(evaluate_subexp_standard): Handle values of type
TYPE_CODE_INTERNAL_FUNCTION.
* gdbtypes.h (type_code): Add TYPE_CODE_INTERNAL_FUNCTION.
* parse.c (write_exp_string): Remove duplicate word in comment.
* python/python-function.c: New file.
* python/python-internal.h (gdbpy_initialize_functions): Add
prototype.
* python/python.c (_initialize_python): Call
gdbpy_initialize_functions.
* valprint.c (value_check_printable): Handle values of type
TYPE_CODE_INTERNAL_FUNCTION.
* value.c: Include "cli/cli-decode.h".
(internal_function): New struct.
(functionlist, internal_fn_type): New static variables.
(lookup_only_internalvar,
lookup_internalvar): Add const qualifier to name argument.
(create_internalvar): Likewise. Initialize new field.
(set_internal_var): Fix typo in comment. Don't allow assignment
to canonical variable.
(value_create_internal_function, value_internal_function_name,
call_internal_function, function_command, function_destroyer,
add_internal_function): New functions.
(_initialize_values): Create `function' placeholder command.
Initialize internal_fn_type.
* value.h (lookup_only_internalvar, create_internalvar,
lookup_internalvar): Add const qualifier to name argument.
(internal_function_fn, add_internal_function, call_internal_function,
value_internal_function_name): Add prototypes.
(struct internalvar) <canonical>: New field.
gdb/doc/
2008-03-05 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Convenience Vars): Document convenience functions.
(Functions In Python): New node.
(Python API): Update.
gdb/testsuite/
2009-03-05 Thiago Jung Bauermann <bauerman@br.ibm.com>
* gdb.python/python-function.exp: New file.
2009-03-21 11:03:56 +08:00
|
|
|
|
|
1999-04-16 09:35:26 +08:00
|
|
|
|
|
|
|
|
|
/* Parse the string EXP as a C expression, evaluate it,
|
|
|
|
|
and return the result as a number. */
|
|
|
|
|
|
|
|
|
|
CORE_ADDR
|
2013-03-13 01:39:45 +08:00
|
|
|
|
parse_and_eval_address (const char *exp)
|
1999-04-16 09:35:26 +08:00
|
|
|
|
{
|
'struct expression *' -> gdb::unique_xmalloc_ptr<expression>
This patch makes parse_expression and friends return a unique_ptr
instead of raw pointer [1]:
typedef gdb::unique_malloc_ptr<expression> expression_up;
and then adjusts the codebase throughout to stop using cleanups to
manage lifetime of expression pointers.
Whenever I found a structure owning an expression pointer, I made it
store a unique_ptr instead of a raw pointer, which then requires using
new/delete of the holding structure, instead of XNEW/xfree.
[1] - I'd like to set the rule that types named with an "_up" suffix
are unique_ptr typedefs.
Note I used gdb::unique_xmalloc_ptr instead of gdb::unique_ptr, simply
because we still use xmalloc instead of new to allocate expression
objects. Once that's changed, all we need to do is change the
expression_up typedef and the smart pointer will then call delete
instead of xfree.
gdb/ChangeLog:
2016-11-08 Pedro Alves <palves@redhat.com>
* ada-lang.c (ada_read_renaming_var_value): Use expression_up.
(struct ada_catchpoint_location) <excep_cond_expr>: Now an
expression_up.
(ada_catchpoint_location_dtor): Reset excep_cond_expr instead of
using xfree.
(create_excep_cond_exprs): Use expression_up and gdb::move.
(allocate_location_exception): Use new instead of XNEW.
(should_stop_exception): Likewise. Adjust to use expression_up.
(create_ada_exception_catchpoint): Use new instead of XNEW.
* ax-gdb.c (agent_eval_command_one): Use expression_up instead of
cleanups.
(maint_agent_printf_command): Use expression_up.
* break-catch-sig.c (create_signal_catchpoint): Use new instead of
XNEW.
* break-catch-syscall.c (create_syscall_event_catchpoint):
Likewise.
* break-catch-throw.c (handle_gnu_v3_exceptions): Use new instead
of XCNEW. Use gdb::unique_ptr instead of cleanups.
* breakpoint.c (set_breakpoint_condition, update_watchpoint)
(parse_cmd_to_aexpr, watchpoint_check)
(bpstat_check_breakpoint_conditions, watchpoint_locations_match):
Adjust to use expression_up.
(init_bp_location): Adjust.
(free_bp_location): Use delete instead of xfree.
(set_raw_breakpoint_without_location, set_raw_breakpoint)
(add_solib_catchpoint, create_fork_vfork_event_catchpoint)
(new_single_step_breakpoint, create_breakpoint_sal): Use new
instead of XNEW.
(find_condition_and_thread): Adjust to use expression_up.
(create_breakpoint): Use new instead of XNEW.
(dtor_watchpoint): Don't xfree expression pointers, they're
unique_ptr's now.
(insert_watchpoint, remove_watchpoint): Adjust.
(watch_command_1): Use expression_up. Use new instead of XCNEW.
(catch_exec_command_1): Use new instead of XNEW.
(bp_location_dtor): Don't xfree expression pointers, they're
unique_ptr's now.
(base_breakpoint_allocate_location)
(strace_marker_create_breakpoints_sal): Use new instead of XNEW.
(delete_breakpoint): Use delete instead of xfree.
* breakpoint.h (struct bp_location) <cond>: Now an
unique_ptr<expression> instead of a raw pointer.
(struct watchpoint) <exp, cond_exp>: Likewise.
* cli/cli-script.c (execute_control_command): Use expression_up
instead of cleanups.
* dtrace-probe.c (dtrace_process_dof_probe): Use expression_up.
* eval.c (parse_and_eval_address, parse_and_eval_long)
(parse_and_eval, parse_to_comma_and_eval, parse_and_eval_type):
Use expression_up instead of cleanups.
* expression.h (expression_up): New typedef.
(parse_expression, parse_expression_with_language, parse_exp_1):
Change return type to expression_up.
* mi/mi-main.c (mi_cmd_data_evaluate_expression)
(print_variable_or_computed): Use expression_up.
* objc-lang.c (print_object_command): Use expression_up instead of
cleanups.
* parse.c (parse_exp_1, parse_exp_in_context)
(parse_exp_in_context_1, parse_expression)
(parse_expression_with_language): Return an expression_up instead
of a raw pointer.
(parse_expression_for_completion): Use expression_up.
* printcmd.c (struct display) <exp>: Now an expression_up instead
of a raw pointer.
(print_command_1, output_command_const, set_command, x_command):
Use expression_up instead of cleanups.
(display_command): Likewise. Use new instead of XNEW.
(free_display): Use delete instead of xfree.
(do_one_display): Adjust to use expression_up.
* remote.c (remote_download_tracepoint): Likewise.
* stack.c (return_command): Likewise.
* tracepoint.c (validate_actionline, encode_actions_1): Use
expression_up instead of cleanups.
* typeprint.c (whatis_exp, maintenance_print_type): Likewise.
* value.c (init_if_undefined_command): Likewise.
* varobj.c (struct varobj_root) <exp>: Now an expression_up
instead of a raw pointer.
(varobj_create): Adjust.
(varobj_set_value): Use an expression_up instead of cleanups.
(new_root_variable): Use new instead of XNEW.
(free_variable): Use delete instead of xfree.
(value_of_root_1): Use std::swap.
2016-11-08 23:26:43 +08:00
|
|
|
|
expression_up expr = parse_expression (exp);
|
|
|
|
|
|
2023-04-28 21:24:59 +08:00
|
|
|
|
return value_as_address (expr->evaluate ());
|
1999-04-16 09:35:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-30 23:32:51 +08:00
|
|
|
|
/* Like parse_and_eval_address, but treats the value of the expression
|
2011-01-08 03:36:19 +08:00
|
|
|
|
as an integer, not an address, returns a LONGEST, not a CORE_ADDR. */
|
2000-10-30 23:32:51 +08:00
|
|
|
|
LONGEST
|
2013-05-15 04:37:57 +08:00
|
|
|
|
parse_and_eval_long (const char *exp)
|
2000-10-30 23:32:51 +08:00
|
|
|
|
{
|
'struct expression *' -> gdb::unique_xmalloc_ptr<expression>
This patch makes parse_expression and friends return a unique_ptr
instead of raw pointer [1]:
typedef gdb::unique_malloc_ptr<expression> expression_up;
and then adjusts the codebase throughout to stop using cleanups to
manage lifetime of expression pointers.
Whenever I found a structure owning an expression pointer, I made it
store a unique_ptr instead of a raw pointer, which then requires using
new/delete of the holding structure, instead of XNEW/xfree.
[1] - I'd like to set the rule that types named with an "_up" suffix
are unique_ptr typedefs.
Note I used gdb::unique_xmalloc_ptr instead of gdb::unique_ptr, simply
because we still use xmalloc instead of new to allocate expression
objects. Once that's changed, all we need to do is change the
expression_up typedef and the smart pointer will then call delete
instead of xfree.
gdb/ChangeLog:
2016-11-08 Pedro Alves <palves@redhat.com>
* ada-lang.c (ada_read_renaming_var_value): Use expression_up.
(struct ada_catchpoint_location) <excep_cond_expr>: Now an
expression_up.
(ada_catchpoint_location_dtor): Reset excep_cond_expr instead of
using xfree.
(create_excep_cond_exprs): Use expression_up and gdb::move.
(allocate_location_exception): Use new instead of XNEW.
(should_stop_exception): Likewise. Adjust to use expression_up.
(create_ada_exception_catchpoint): Use new instead of XNEW.
* ax-gdb.c (agent_eval_command_one): Use expression_up instead of
cleanups.
(maint_agent_printf_command): Use expression_up.
* break-catch-sig.c (create_signal_catchpoint): Use new instead of
XNEW.
* break-catch-syscall.c (create_syscall_event_catchpoint):
Likewise.
* break-catch-throw.c (handle_gnu_v3_exceptions): Use new instead
of XCNEW. Use gdb::unique_ptr instead of cleanups.
* breakpoint.c (set_breakpoint_condition, update_watchpoint)
(parse_cmd_to_aexpr, watchpoint_check)
(bpstat_check_breakpoint_conditions, watchpoint_locations_match):
Adjust to use expression_up.
(init_bp_location): Adjust.
(free_bp_location): Use delete instead of xfree.
(set_raw_breakpoint_without_location, set_raw_breakpoint)
(add_solib_catchpoint, create_fork_vfork_event_catchpoint)
(new_single_step_breakpoint, create_breakpoint_sal): Use new
instead of XNEW.
(find_condition_and_thread): Adjust to use expression_up.
(create_breakpoint): Use new instead of XNEW.
(dtor_watchpoint): Don't xfree expression pointers, they're
unique_ptr's now.
(insert_watchpoint, remove_watchpoint): Adjust.
(watch_command_1): Use expression_up. Use new instead of XCNEW.
(catch_exec_command_1): Use new instead of XNEW.
(bp_location_dtor): Don't xfree expression pointers, they're
unique_ptr's now.
(base_breakpoint_allocate_location)
(strace_marker_create_breakpoints_sal): Use new instead of XNEW.
(delete_breakpoint): Use delete instead of xfree.
* breakpoint.h (struct bp_location) <cond>: Now an
unique_ptr<expression> instead of a raw pointer.
(struct watchpoint) <exp, cond_exp>: Likewise.
* cli/cli-script.c (execute_control_command): Use expression_up
instead of cleanups.
* dtrace-probe.c (dtrace_process_dof_probe): Use expression_up.
* eval.c (parse_and_eval_address, parse_and_eval_long)
(parse_and_eval, parse_to_comma_and_eval, parse_and_eval_type):
Use expression_up instead of cleanups.
* expression.h (expression_up): New typedef.
(parse_expression, parse_expression_with_language, parse_exp_1):
Change return type to expression_up.
* mi/mi-main.c (mi_cmd_data_evaluate_expression)
(print_variable_or_computed): Use expression_up.
* objc-lang.c (print_object_command): Use expression_up instead of
cleanups.
* parse.c (parse_exp_1, parse_exp_in_context)
(parse_exp_in_context_1, parse_expression)
(parse_expression_with_language): Return an expression_up instead
of a raw pointer.
(parse_expression_for_completion): Use expression_up.
* printcmd.c (struct display) <exp>: Now an expression_up instead
of a raw pointer.
(print_command_1, output_command_const, set_command, x_command):
Use expression_up instead of cleanups.
(display_command): Likewise. Use new instead of XNEW.
(free_display): Use delete instead of xfree.
(do_one_display): Adjust to use expression_up.
* remote.c (remote_download_tracepoint): Likewise.
* stack.c (return_command): Likewise.
* tracepoint.c (validate_actionline, encode_actions_1): Use
expression_up instead of cleanups.
* typeprint.c (whatis_exp, maintenance_print_type): Likewise.
* value.c (init_if_undefined_command): Likewise.
* varobj.c (struct varobj_root) <exp>: Now an expression_up
instead of a raw pointer.
(varobj_create): Adjust.
(varobj_set_value): Use an expression_up instead of cleanups.
(new_root_variable): Use new instead of XNEW.
(free_variable): Use delete instead of xfree.
(value_of_root_1): Use std::swap.
2016-11-08 23:26:43 +08:00
|
|
|
|
expression_up expr = parse_expression (exp);
|
|
|
|
|
|
2023-04-28 21:24:59 +08:00
|
|
|
|
return value_as_long (expr->evaluate ());
|
2000-10-30 23:32:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-11 04:15:13 +08:00
|
|
|
|
struct value *
|
2023-04-28 22:45:48 +08:00
|
|
|
|
parse_and_eval (const char *exp, parser_flags flags)
|
1999-04-16 09:35:26 +08:00
|
|
|
|
{
|
2023-04-28 22:45:48 +08:00
|
|
|
|
expression_up expr = parse_expression (exp, nullptr, flags);
|
1999-04-16 09:35:26 +08:00
|
|
|
|
|
2023-04-28 21:24:59 +08:00
|
|
|
|
return expr->evaluate ();
|
1999-04-16 09:35:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse up to a comma (or to a closeparen)
|
|
|
|
|
in the string EXPP as an expression, evaluate it, and return the value.
|
|
|
|
|
EXPP is advanced to point to the comma. */
|
|
|
|
|
|
2001-11-11 04:15:13 +08:00
|
|
|
|
struct value *
|
2013-03-13 01:39:45 +08:00
|
|
|
|
parse_to_comma_and_eval (const char **expp)
|
1999-04-16 09:35:26 +08:00
|
|
|
|
{
|
2023-04-28 22:08:49 +08:00
|
|
|
|
expression_up expr = parse_exp_1 (expp, 0, nullptr,
|
|
|
|
|
PARSER_COMMA_TERMINATES);
|
1999-04-16 09:35:26 +08:00
|
|
|
|
|
2023-04-28 21:24:59 +08:00
|
|
|
|
return expr->evaluate ();
|
1999-04-16 09:35:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-02-19 02:23:33 +08:00
|
|
|
|
/* See expression.h. */
|
|
|
|
|
|
2022-12-20 02:14:02 +08:00
|
|
|
|
bool
|
|
|
|
|
expression::uses_objfile (struct objfile *objfile) const
|
|
|
|
|
{
|
|
|
|
|
gdb_assert (objfile->separate_debug_objfile_backlink == nullptr);
|
|
|
|
|
return op->uses_objfile (objfile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See expression.h. */
|
|
|
|
|
|
2021-02-19 02:23:33 +08:00
|
|
|
|
struct value *
|
|
|
|
|
expression::evaluate (struct type *expect_type, enum noside noside)
|
|
|
|
|
{
|
2023-10-13 17:27:48 +08:00
|
|
|
|
std::optional<enable_thread_stack_temporaries> stack_temporaries;
|
2021-06-04 04:20:30 +08:00
|
|
|
|
if (target_has_execution () && inferior_ptid != null_ptid
|
2021-02-19 02:23:33 +08:00
|
|
|
|
&& language_defn->la_language == language_cplus
|
|
|
|
|
&& !thread_stack_temporaries_enabled_p (inferior_thread ()))
|
|
|
|
|
stack_temporaries.emplace (inferior_thread ());
|
|
|
|
|
|
Remove union exp_element
This removes union exp_element functions that either create such
elements or walk them. struct expression no longer holds
exp_elements. A couple of language_defn methods are also removed, as
they are obsolete.
Note that this patch also removes the print_expression code. The only
in-tree caller of this was from dump_prefix_expression, which is only
called when expression debugging is enabled. Implementing this would
involve a fair amount of code, and it seems to me that prefix dumping
is preferable anyway, as it is unambiguous. So, I have not
reimplemented this feature.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (evaluate_subexp_with_coercion): Don't declare.
* parse.c (exp_descriptor_standard): Remove.
(expr_builder::expr_builder, expr_builder::release): Update.
(expression::expression): Remove size_t parameter.
(expression::~expression): Simplify.
(expression::resize): Remove.
(write_exp_elt, write_exp_elt_opcode, write_exp_elt_sym)
(write_exp_elt_msym, write_exp_elt_block, write_exp_elt_objfile)
(write_exp_elt_longcst, write_exp_elt_floatcst)
(write_exp_elt_type, write_exp_elt_intern, write_exp_string)
(write_exp_string_vector, write_exp_bitstring): Remove.
* p-lang.h (class pascal_language) <opcode_print_table,
op_print_tab>: Remove.
* p-lang.c (pascal_language::op_print_tab): Remove.
* opencl-lang.c (class opencl_language) <opcode_print_table>:
Remove.
* objc-lang.c (objc_op_print_tab): Remove.
(class objc_language) <opcode_print_table>: Remove.
* m2-lang.h (class m2_language) <opcode_print_table,
op_print_tab>: Remove.
* m2-lang.c (m2_language::op_print_tab): Remove.
* language.h (struct language_defn) <post_parser, expression_ops,
opcode_print_table>: Remove.
* language.c (language_defn::expression_ops)
(auto_or_unknown_language::opcode_print_table): Remove.
* go-lang.h (class go_language) <opcode_print_table,
op_print_tab>: Remove.
* go-lang.c (go_language::op_print_tab): Remove.
* f-lang.h (class f_language) <opcode_print_table>: Remove
<op_print_tab>: Remove.
* f-lang.c (f_language::op_print_tab): Remove.
* expression.h (union exp_element): Remove.
(struct expression): Remove size_t parameter from constructor.
<resize>: Remove.
<first_opcode>: Update.
<nelts, elts>: Remove.
(EXP_ELEM_TO_BYTES, BYTES_TO_EXP_ELEM): Remove.
(evaluate_subexp_standard, print_expression, op_string)
(dump_raw_expression): Don't declare.
* expprint.c (print_expression, print_subexp)
(print_subexp_funcall, print_subexp_standard, op_string)
(dump_raw_expression, dump_subexp, dump_subexp_body)
(dump_subexp_body_funcall, dump_subexp_body_standard): Remove.
(dump_prefix_expression): Update.
* eval.c (evaluate_subexp): Remove.
(evaluate_expression, evaluate_type): Update.
(evaluate_subexpression_type): Remove.
(fetch_subexp_value): Remove "pc" parameter. Update.
(extract_field_op, evaluate_struct_tuple, evaluate_funcall)
(evaluate_subexp_standard, evaluate_subexp_for_address)
(evaluate_subexp_with_coercion, evaluate_subexp_for_sizeof)
(evaluate_subexp_for_cast): Remove.
(parse_and_eval_type): Update.
* dtrace-probe.c (dtrace_probe::compile_to_ax): Update.
* d-lang.c (d_op_print_tab): Remove.
(class d_language) <opcode_print_table>: Remove.
* c-lang.h (c_op_print_tab): Don't declare.
* c-lang.c (c_op_print_tab): Remove.
(class c_language, class cplus_language, class asm_language, class
minimal_language) <opcode_print_table>: Remove.
* breakpoint.c (update_watchpoint, watchpoint_check)
(watchpoint_exp_is_const, watch_command_1): Update.
* ax-gdb.h (union exp_element): Don't declare.
* ax-gdb.c (const_var_ref, const_expr, maybe_const_expr)
(gen_repeat, gen_sizeof, gen_expr_for_cast, gen_expr)
(gen_expr_binop_rest): Remove.
(gen_trace_for_expr, gen_eval_for_expr, gen_printf): Update.
* ada-lang.c (ada_op_print_tab): Remove.
(class ada_language) <post_parser, opcode_print_table>: Remove.
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *retval = op->evaluate (expect_type, this, noside);
|
2021-02-19 02:23:33 +08:00
|
|
|
|
|
|
|
|
|
if (stack_temporaries.has_value ()
|
|
|
|
|
&& value_in_thread_stack_temporaries (retval, inferior_thread ()))
|
2023-02-01 07:23:22 +08:00
|
|
|
|
retval = retval->non_lval ();
|
2021-02-19 02:23:33 +08:00
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-08 00:15:18 +08:00
|
|
|
|
/* Find the current value of a watchpoint on EXP. Return the value in
|
|
|
|
|
*VALP and *RESULTP and the chain of intermediate and final values
|
|
|
|
|
in *VAL_CHAIN. RESULTP and VAL_CHAIN may be NULL if the caller does
|
|
|
|
|
not need them.
|
|
|
|
|
|
2013-08-03 00:41:08 +08:00
|
|
|
|
If PRESERVE_ERRORS is true, then exceptions are passed through.
|
|
|
|
|
Otherwise, if PRESERVE_ERRORS is false, then if a memory error
|
|
|
|
|
occurs while evaluating the expression, *RESULTP will be set to
|
|
|
|
|
NULL. *RESULTP may be a lazy value, if the result could not be
|
|
|
|
|
read from memory. It is used to determine whether a value is
|
|
|
|
|
user-specified (we should watch the whole value) or intermediate
|
2010-07-08 00:15:18 +08:00
|
|
|
|
(we should watch only the bit used to locate the final value).
|
|
|
|
|
|
|
|
|
|
If the final value, or any intermediate value, could not be read
|
|
|
|
|
from memory, *VALP will be set to NULL. *VAL_CHAIN will still be
|
|
|
|
|
set to any referenced values. *VALP will never be a lazy value.
|
|
|
|
|
This is the value which we store in struct breakpoint.
|
|
|
|
|
|
2018-04-04 10:20:01 +08:00
|
|
|
|
If VAL_CHAIN is non-NULL, the values put into *VAL_CHAIN will be
|
|
|
|
|
released from the value chain. If VAL_CHAIN is NULL, all generated
|
|
|
|
|
values will be left on the value chain. */
|
2010-07-08 00:15:18 +08:00
|
|
|
|
|
|
|
|
|
void
|
Remove union exp_element
This removes union exp_element functions that either create such
elements or walk them. struct expression no longer holds
exp_elements. A couple of language_defn methods are also removed, as
they are obsolete.
Note that this patch also removes the print_expression code. The only
in-tree caller of this was from dump_prefix_expression, which is only
called when expression debugging is enabled. Implementing this would
involve a fair amount of code, and it seems to me that prefix dumping
is preferable anyway, as it is unambiguous. So, I have not
reimplemented this feature.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (evaluate_subexp_with_coercion): Don't declare.
* parse.c (exp_descriptor_standard): Remove.
(expr_builder::expr_builder, expr_builder::release): Update.
(expression::expression): Remove size_t parameter.
(expression::~expression): Simplify.
(expression::resize): Remove.
(write_exp_elt, write_exp_elt_opcode, write_exp_elt_sym)
(write_exp_elt_msym, write_exp_elt_block, write_exp_elt_objfile)
(write_exp_elt_longcst, write_exp_elt_floatcst)
(write_exp_elt_type, write_exp_elt_intern, write_exp_string)
(write_exp_string_vector, write_exp_bitstring): Remove.
* p-lang.h (class pascal_language) <opcode_print_table,
op_print_tab>: Remove.
* p-lang.c (pascal_language::op_print_tab): Remove.
* opencl-lang.c (class opencl_language) <opcode_print_table>:
Remove.
* objc-lang.c (objc_op_print_tab): Remove.
(class objc_language) <opcode_print_table>: Remove.
* m2-lang.h (class m2_language) <opcode_print_table,
op_print_tab>: Remove.
* m2-lang.c (m2_language::op_print_tab): Remove.
* language.h (struct language_defn) <post_parser, expression_ops,
opcode_print_table>: Remove.
* language.c (language_defn::expression_ops)
(auto_or_unknown_language::opcode_print_table): Remove.
* go-lang.h (class go_language) <opcode_print_table,
op_print_tab>: Remove.
* go-lang.c (go_language::op_print_tab): Remove.
* f-lang.h (class f_language) <opcode_print_table>: Remove
<op_print_tab>: Remove.
* f-lang.c (f_language::op_print_tab): Remove.
* expression.h (union exp_element): Remove.
(struct expression): Remove size_t parameter from constructor.
<resize>: Remove.
<first_opcode>: Update.
<nelts, elts>: Remove.
(EXP_ELEM_TO_BYTES, BYTES_TO_EXP_ELEM): Remove.
(evaluate_subexp_standard, print_expression, op_string)
(dump_raw_expression): Don't declare.
* expprint.c (print_expression, print_subexp)
(print_subexp_funcall, print_subexp_standard, op_string)
(dump_raw_expression, dump_subexp, dump_subexp_body)
(dump_subexp_body_funcall, dump_subexp_body_standard): Remove.
(dump_prefix_expression): Update.
* eval.c (evaluate_subexp): Remove.
(evaluate_expression, evaluate_type): Update.
(evaluate_subexpression_type): Remove.
(fetch_subexp_value): Remove "pc" parameter. Update.
(extract_field_op, evaluate_struct_tuple, evaluate_funcall)
(evaluate_subexp_standard, evaluate_subexp_for_address)
(evaluate_subexp_with_coercion, evaluate_subexp_for_sizeof)
(evaluate_subexp_for_cast): Remove.
(parse_and_eval_type): Update.
* dtrace-probe.c (dtrace_probe::compile_to_ax): Update.
* d-lang.c (d_op_print_tab): Remove.
(class d_language) <opcode_print_table>: Remove.
* c-lang.h (c_op_print_tab): Don't declare.
* c-lang.c (c_op_print_tab): Remove.
(class c_language, class cplus_language, class asm_language, class
minimal_language) <opcode_print_table>: Remove.
* breakpoint.c (update_watchpoint, watchpoint_check)
(watchpoint_exp_is_const, watch_command_1): Update.
* ax-gdb.h (union exp_element): Don't declare.
* ax-gdb.c (const_var_ref, const_expr, maybe_const_expr)
(gen_repeat, gen_sizeof, gen_expr_for_cast, gen_expr)
(gen_expr_binop_rest): Remove.
(gen_trace_for_expr, gen_eval_for_expr, gen_printf): Update.
* ada-lang.c (ada_op_print_tab): Remove.
(class ada_language) <post_parser, opcode_print_table>: Remove.
2021-03-08 22:27:57 +08:00
|
|
|
|
fetch_subexp_value (struct expression *exp,
|
Add an expr::operation_up to struct expression
This adds an expr::operation_up to struct expression, and then
modifies various parts of GDB to use this member when it is non-null.
The list of such spots was a bit surprising to me, and found only
after writing most of the code and then noticing what no longer
compiled.
In a few spots, new accessor methods are added to operation
subclasses, so that code that dissects an expression will work with
the new scheme.
After this change, code that constructs an expression can be switched
to the new form without breaking.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* ada-exp.h (class ada_var_value_operation) <get_symbol>: Remove;
now in superclass.
* value.h (fetch_subexp_value): Add "op" parameter.
* value.c (init_if_undefined_command): Update.
* tracepoint.c (validate_actionline, encode_actions_1): Update.
* stap-probe.c (stap_probe::compile_to_ax): Update.
* printcmd.c (set_command): Update.
* ppc-linux-nat.c (ppc_linux_nat_target::check_condition):
Update.
* parser-defs.h (struct expr_builder) <set_operation>: New
method.
* parse.c (parse_exp_in_context, exp_uses_objfile): Update.
* expression.h (struct expression) <first_opcode>: Update.
<op>: New member.
* expprint.c (dump_raw_expression, dump_prefix_expression):
Update.
* expop.h (class var_value_operation) <get_symbol>: New method.
(class register_operation) <get_name>: New method.
(class equal_operation): No longer a typedef, now a subclass.
(class unop_memval_operation) <get_type>: New method.
(class assign_operation) <get_lhs>: New method.
(class unop_cast_operation) <get_type>: New method.
* eval.c (evaluate_expression, evaluate_type)
(evaluate_subexpression_type): Update.
(fetch_subexp_value): Add "op" parameter.
(parse_and_eval_type): Update.
* dtrace-probe.c (dtrace_probe::compile_to_ax): Update.
* breakpoint.c (update_watchpoint, watchpoint_check)
(watchpoint_exp_is_const, watch_command_1): Update.
* ax-gdb.c (gen_trace_for_expr, gen_eval_for_expr, gen_printf):
Update.
2021-03-08 22:27:57 +08:00
|
|
|
|
expr::operation *op,
|
|
|
|
|
struct value **valp, struct value **resultp,
|
2018-04-04 10:20:01 +08:00
|
|
|
|
std::vector<value_ref_ptr> *val_chain,
|
2020-11-17 00:12:44 +08:00
|
|
|
|
bool preserve_errors)
|
2010-07-08 00:15:18 +08:00
|
|
|
|
{
|
|
|
|
|
struct value *mark, *new_mark, *result;
|
|
|
|
|
|
|
|
|
|
*valp = NULL;
|
|
|
|
|
if (resultp)
|
|
|
|
|
*resultp = NULL;
|
|
|
|
|
if (val_chain)
|
2018-04-04 10:20:01 +08:00
|
|
|
|
val_chain->clear ();
|
2010-07-08 00:15:18 +08:00
|
|
|
|
|
|
|
|
|
/* Evaluate the expression. */
|
|
|
|
|
mark = value_mark ();
|
|
|
|
|
result = NULL;
|
|
|
|
|
|
2019-04-04 06:02:42 +08:00
|
|
|
|
try
|
2010-07-08 00:15:18 +08:00
|
|
|
|
{
|
Remove union exp_element
This removes union exp_element functions that either create such
elements or walk them. struct expression no longer holds
exp_elements. A couple of language_defn methods are also removed, as
they are obsolete.
Note that this patch also removes the print_expression code. The only
in-tree caller of this was from dump_prefix_expression, which is only
called when expression debugging is enabled. Implementing this would
involve a fair amount of code, and it seems to me that prefix dumping
is preferable anyway, as it is unambiguous. So, I have not
reimplemented this feature.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (evaluate_subexp_with_coercion): Don't declare.
* parse.c (exp_descriptor_standard): Remove.
(expr_builder::expr_builder, expr_builder::release): Update.
(expression::expression): Remove size_t parameter.
(expression::~expression): Simplify.
(expression::resize): Remove.
(write_exp_elt, write_exp_elt_opcode, write_exp_elt_sym)
(write_exp_elt_msym, write_exp_elt_block, write_exp_elt_objfile)
(write_exp_elt_longcst, write_exp_elt_floatcst)
(write_exp_elt_type, write_exp_elt_intern, write_exp_string)
(write_exp_string_vector, write_exp_bitstring): Remove.
* p-lang.h (class pascal_language) <opcode_print_table,
op_print_tab>: Remove.
* p-lang.c (pascal_language::op_print_tab): Remove.
* opencl-lang.c (class opencl_language) <opcode_print_table>:
Remove.
* objc-lang.c (objc_op_print_tab): Remove.
(class objc_language) <opcode_print_table>: Remove.
* m2-lang.h (class m2_language) <opcode_print_table,
op_print_tab>: Remove.
* m2-lang.c (m2_language::op_print_tab): Remove.
* language.h (struct language_defn) <post_parser, expression_ops,
opcode_print_table>: Remove.
* language.c (language_defn::expression_ops)
(auto_or_unknown_language::opcode_print_table): Remove.
* go-lang.h (class go_language) <opcode_print_table,
op_print_tab>: Remove.
* go-lang.c (go_language::op_print_tab): Remove.
* f-lang.h (class f_language) <opcode_print_table>: Remove
<op_print_tab>: Remove.
* f-lang.c (f_language::op_print_tab): Remove.
* expression.h (union exp_element): Remove.
(struct expression): Remove size_t parameter from constructor.
<resize>: Remove.
<first_opcode>: Update.
<nelts, elts>: Remove.
(EXP_ELEM_TO_BYTES, BYTES_TO_EXP_ELEM): Remove.
(evaluate_subexp_standard, print_expression, op_string)
(dump_raw_expression): Don't declare.
* expprint.c (print_expression, print_subexp)
(print_subexp_funcall, print_subexp_standard, op_string)
(dump_raw_expression, dump_subexp, dump_subexp_body)
(dump_subexp_body_funcall, dump_subexp_body_standard): Remove.
(dump_prefix_expression): Update.
* eval.c (evaluate_subexp): Remove.
(evaluate_expression, evaluate_type): Update.
(evaluate_subexpression_type): Remove.
(fetch_subexp_value): Remove "pc" parameter. Update.
(extract_field_op, evaluate_struct_tuple, evaluate_funcall)
(evaluate_subexp_standard, evaluate_subexp_for_address)
(evaluate_subexp_with_coercion, evaluate_subexp_for_sizeof)
(evaluate_subexp_for_cast): Remove.
(parse_and_eval_type): Update.
* dtrace-probe.c (dtrace_probe::compile_to_ax): Update.
* d-lang.c (d_op_print_tab): Remove.
(class d_language) <opcode_print_table>: Remove.
* c-lang.h (c_op_print_tab): Don't declare.
* c-lang.c (c_op_print_tab): Remove.
(class c_language, class cplus_language, class asm_language, class
minimal_language) <opcode_print_table>: Remove.
* breakpoint.c (update_watchpoint, watchpoint_check)
(watchpoint_exp_is_const, watch_command_1): Update.
* ax-gdb.h (union exp_element): Don't declare.
* ax-gdb.c (const_var_ref, const_expr, maybe_const_expr)
(gen_repeat, gen_sizeof, gen_expr_for_cast, gen_expr)
(gen_expr_binop_rest): Remove.
(gen_trace_for_expr, gen_eval_for_expr, gen_printf): Update.
* ada-lang.c (ada_op_print_tab): Remove.
(class ada_language) <post_parser, opcode_print_table>: Remove.
2021-03-08 22:27:57 +08:00
|
|
|
|
result = op->evaluate (nullptr, exp, EVAL_NORMAL);
|
2010-07-08 00:15:18 +08:00
|
|
|
|
}
|
2019-04-04 05:59:07 +08:00
|
|
|
|
catch (const gdb_exception &ex)
|
2010-07-08 00:15:18 +08:00
|
|
|
|
{
|
2013-08-03 00:41:08 +08:00
|
|
|
|
/* Ignore memory errors if we want watchpoints pointing at
|
2010-07-08 00:15:18 +08:00
|
|
|
|
inaccessible memory to still be created; otherwise, throw the
|
|
|
|
|
error to some higher catcher. */
|
|
|
|
|
switch (ex.error)
|
|
|
|
|
{
|
|
|
|
|
case MEMORY_ERROR:
|
2013-08-03 00:41:08 +08:00
|
|
|
|
if (!preserve_errors)
|
|
|
|
|
break;
|
2023-10-16 01:09:07 +08:00
|
|
|
|
[[fallthrough]];
|
2010-07-08 00:15:18 +08:00
|
|
|
|
default:
|
Replace throw_exception with throw in some cases
This replaces throw_exception with "throw;" when possible. This was
written by script. The rule that is followed is that uses of the
form:
catch (... &name)
{
...
throw_exception (name);
}
... can be rewritten. This should always be safe, because exceptions
are caught by const reference, and therefore can't be modified in the
body of the catch.
gdb/ChangeLog
2019-04-08 Tom Tromey <tom@tromey.com>
* valops.c (value_rtti_indirect_type): Replace throw_exception
with throw.
* tracefile-tfile.c (tfile_target_open): Replace throw_exception
with throw.
* thread.c (thr_try_catch_cmd): Replace throw_exception with
throw.
* target.c (target_translate_tls_address): Replace throw_exception
with throw.
* stack.c (frame_apply_command_count): Replace throw_exception
with throw.
* solib-spu.c (append_ocl_sos): Replace throw_exception with
throw.
* s390-tdep.c (s390_frame_unwind_cache): Replace throw_exception
with throw.
* rs6000-tdep.c (rs6000_frame_cache)
(rs6000_epilogue_frame_cache): Replace throw_exception with throw.
* remote.c: Replace throw_exception with throw.
* record-full.c (record_full_message, record_full_wait_1)
(record_full_restore): Replace throw_exception with throw.
* record-btrace.c:
(get_thread_current_frame_id, record_btrace_start_replaying)
(cmd_record_btrace_bts_start, cmd_record_btrace_pt_start)
(cmd_record_btrace_start): Replace throw_exception with throw.
* parse.c (parse_exp_in_context_1): Replace throw_exception with
throw.
* linux-nat.c (detach_one_lwp, linux_resume_one_lwp)
(resume_stopped_resumed_lwps): Replace throw_exception with throw.
* linespec.c:
(find_linespec_symbols): Replace throw_exception with throw.
* infrun.c (displaced_step_prepare, resume): Replace
throw_exception with throw.
* infcmd.c (post_create_inferior): Replace throw_exception with
throw.
* inf-loop.c (inferior_event_handler): Replace throw_exception
with throw.
* i386-tdep.c (i386_frame_cache, i386_epilogue_frame_cache)
(i386_sigtramp_frame_cache): Replace throw_exception with throw.
* frame.c (frame_unwind_pc, get_prev_frame_if_no_cycle)
(get_prev_frame_always, get_frame_pc_if_available)
(get_frame_address_in_block_if_available, get_frame_language):
Replace throw_exception with throw.
* frame-unwind.c (frame_unwind_try_unwinder): Replace
throw_exception with throw.
* eval.c (fetch_subexp_value, evaluate_var_value)
(evaluate_funcall, evaluate_subexp_standard): Replace
throw_exception with throw.
* dwarf2loc.c (call_site_find_chain)
(dwarf2_evaluate_loc_desc_full, dwarf2_locexpr_baton_eval):
Replace throw_exception with throw.
* dwarf2-frame.c (dwarf2_frame_cache): Replace throw_exception
with throw.
* darwin-nat.c (darwin_attach_pid): Replace throw_exception with
throw.
* cp-abi.c (baseclass_offset): Replace throw_exception with throw.
* completer.c (complete_line_internal): Replace throw_exception
with throw.
* compile/compile-object-run.c (compile_object_run): Replace
throw_exception with throw.
* cli/cli-script.c (process_next_line): Replace throw_exception
with throw.
* btrace.c (btrace_compute_ftrace_pt, btrace_compute_ftrace)
(btrace_enable, btrace_maint_update_pt_packets): Replace
throw_exception with throw.
* breakpoint.c (create_breakpoint, save_breakpoints): Replace
throw_exception with throw.
* break-catch-throw.c (re_set_exception_catchpoint): Replace
throw_exception with throw.
* amd64-tdep.c (amd64_frame_cache, amd64_sigtramp_frame_cache)
(amd64_epilogue_frame_cache): Replace throw_exception with throw.
* aarch64-tdep.c (aarch64_make_prologue_cache)
(aarch64_make_stub_cache): Replace throw_exception with throw.
gdb/gdbserver/ChangeLog
2019-04-08 Tom Tromey <tom@tromey.com>
* linux-low.c (linux_detach_one_lwp): Replace throw_exception with
throw.
(linux_resume_one_lwp): Likewise.
2019-01-29 01:45:45 +08:00
|
|
|
|
throw;
|
2010-07-08 00:15:18 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new_mark = value_mark ();
|
|
|
|
|
if (mark == new_mark)
|
|
|
|
|
return;
|
|
|
|
|
if (resultp)
|
|
|
|
|
*resultp = result;
|
|
|
|
|
|
|
|
|
|
/* Make sure it's not lazy, so that after the target stops again we
|
|
|
|
|
have a non-lazy previous value to compare with. */
|
2012-01-10 04:27:49 +08:00
|
|
|
|
if (result != NULL)
|
|
|
|
|
{
|
2023-02-01 01:52:04 +08:00
|
|
|
|
if (!result->lazy ())
|
2012-01-10 04:27:49 +08:00
|
|
|
|
*valp = result;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
2019-04-04 06:02:42 +08:00
|
|
|
|
try
|
2012-01-10 04:27:49 +08:00
|
|
|
|
{
|
2023-02-01 04:53:55 +08:00
|
|
|
|
result->fetch_lazy ();
|
2012-01-10 04:27:49 +08:00
|
|
|
|
*valp = result;
|
|
|
|
|
}
|
2019-04-04 05:59:07 +08:00
|
|
|
|
catch (const gdb_exception_error &except)
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 23:14:14 +08:00
|
|
|
|
{
|
|
|
|
|
}
|
2012-01-10 04:27:49 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-07-08 00:15:18 +08:00
|
|
|
|
|
|
|
|
|
if (val_chain)
|
|
|
|
|
{
|
|
|
|
|
/* Return the chain of intermediate values. We use this to
|
|
|
|
|
decide which addresses to watch. */
|
2018-04-04 10:20:01 +08:00
|
|
|
|
*val_chain = value_release_to_mark (mark);
|
2010-07-08 00:15:18 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-11 22:14:20 +08:00
|
|
|
|
/* Promote value ARG1 as appropriate before performing a unary operation
|
|
|
|
|
on this argument.
|
|
|
|
|
If the result is not appropriate for any particular language then it
|
|
|
|
|
needs to patch this function. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
unop_promote (const struct language_defn *language, struct gdbarch *gdbarch,
|
|
|
|
|
struct value **arg1)
|
|
|
|
|
{
|
|
|
|
|
struct type *type1;
|
|
|
|
|
|
|
|
|
|
*arg1 = coerce_ref (*arg1);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
type1 = check_typedef ((*arg1)->type ());
|
2008-09-11 22:14:20 +08:00
|
|
|
|
|
|
|
|
|
if (is_integral_type (type1))
|
|
|
|
|
{
|
|
|
|
|
switch (language->la_language)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
/* Perform integral promotion for ANSI C/C++.
|
2019-10-18 08:48:08 +08:00
|
|
|
|
If not appropriate for any particular language
|
2008-09-11 22:14:20 +08:00
|
|
|
|
it needs to modify this function. */
|
|
|
|
|
{
|
|
|
|
|
struct type *builtin_int = builtin_type (gdbarch)->builtin_int;
|
2010-05-15 02:35:11 +08:00
|
|
|
|
|
2022-09-21 23:05:21 +08:00
|
|
|
|
if (type1->length () < builtin_int->length ())
|
2008-09-11 22:14:20 +08:00
|
|
|
|
*arg1 = value_cast (builtin_int, *arg1);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Promote values ARG1 and ARG2 as appropriate before performing a binary
|
|
|
|
|
operation on those two operands.
|
|
|
|
|
If the result is not appropriate for any particular language then it
|
|
|
|
|
needs to patch this function. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
binop_promote (const struct language_defn *language, struct gdbarch *gdbarch,
|
|
|
|
|
struct value **arg1, struct value **arg2)
|
|
|
|
|
{
|
|
|
|
|
struct type *promoted_type = NULL;
|
|
|
|
|
struct type *type1;
|
|
|
|
|
struct type *type2;
|
|
|
|
|
|
|
|
|
|
*arg1 = coerce_ref (*arg1);
|
|
|
|
|
*arg2 = coerce_ref (*arg2);
|
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
type1 = check_typedef ((*arg1)->type ());
|
|
|
|
|
type2 = check_typedef ((*arg2)->type ());
|
2008-09-11 22:14:20 +08:00
|
|
|
|
|
2020-05-15 01:46:38 +08:00
|
|
|
|
if ((type1->code () != TYPE_CODE_FLT
|
|
|
|
|
&& type1->code () != TYPE_CODE_DECFLOAT
|
2008-09-11 22:14:20 +08:00
|
|
|
|
&& !is_integral_type (type1))
|
2020-05-15 01:46:38 +08:00
|
|
|
|
|| (type2->code () != TYPE_CODE_FLT
|
|
|
|
|
&& type2->code () != TYPE_CODE_DECFLOAT
|
2008-09-11 22:14:20 +08:00
|
|
|
|
&& !is_integral_type (type2)))
|
|
|
|
|
return;
|
|
|
|
|
|
2020-11-15 16:17:12 +08:00
|
|
|
|
if (is_fixed_point_type (type1) || is_fixed_point_type (type2))
|
2022-01-03 22:55:20 +08:00
|
|
|
|
return;
|
2020-11-15 16:17:12 +08:00
|
|
|
|
|
2020-05-15 01:46:38 +08:00
|
|
|
|
if (type1->code () == TYPE_CODE_DECFLOAT
|
|
|
|
|
|| type2->code () == TYPE_CODE_DECFLOAT)
|
2008-09-11 22:14:20 +08:00
|
|
|
|
{
|
|
|
|
|
/* No promotion required. */
|
|
|
|
|
}
|
2020-05-15 01:46:38 +08:00
|
|
|
|
else if (type1->code () == TYPE_CODE_FLT
|
|
|
|
|
|| type2->code () == TYPE_CODE_FLT)
|
2008-09-11 22:14:20 +08:00
|
|
|
|
{
|
|
|
|
|
switch (language->la_language)
|
|
|
|
|
{
|
|
|
|
|
case language_c:
|
|
|
|
|
case language_cplus:
|
|
|
|
|
case language_asm:
|
|
|
|
|
case language_objc:
|
2010-11-05 22:31:30 +08:00
|
|
|
|
case language_opencl:
|
2008-09-11 22:14:20 +08:00
|
|
|
|
/* No promotion required. */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* For other languages the result type is unchanged from gdb
|
|
|
|
|
version 6.7 for backward compatibility.
|
|
|
|
|
If either arg was long double, make sure that value is also long
|
|
|
|
|
double. Otherwise use double. */
|
2022-09-21 23:05:21 +08:00
|
|
|
|
if (type1->length () * 8 > gdbarch_double_bit (gdbarch)
|
|
|
|
|
|| type2->length () * 8 > gdbarch_double_bit (gdbarch))
|
2008-09-11 22:14:20 +08:00
|
|
|
|
promoted_type = builtin_type (gdbarch)->builtin_long_double;
|
|
|
|
|
else
|
|
|
|
|
promoted_type = builtin_type (gdbarch)->builtin_double;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-15 01:46:38 +08:00
|
|
|
|
else if (type1->code () == TYPE_CODE_BOOL
|
|
|
|
|
&& type2->code () == TYPE_CODE_BOOL)
|
2008-09-11 22:14:20 +08:00
|
|
|
|
{
|
|
|
|
|
/* No promotion required. */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* Integral operations here. */
|
|
|
|
|
/* FIXME: Also mixed integral/booleans, with result an integer. */
|
|
|
|
|
{
|
|
|
|
|
const struct builtin_type *builtin = builtin_type (gdbarch);
|
2022-09-21 23:05:21 +08:00
|
|
|
|
unsigned int promoted_len1 = type1->length ();
|
|
|
|
|
unsigned int promoted_len2 = type2->length ();
|
2020-09-14 23:07:57 +08:00
|
|
|
|
int is_unsigned1 = type1->is_unsigned ();
|
|
|
|
|
int is_unsigned2 = type2->is_unsigned ();
|
2008-09-11 22:14:20 +08:00
|
|
|
|
unsigned int result_len;
|
|
|
|
|
int unsigned_operation;
|
|
|
|
|
|
|
|
|
|
/* Determine type length and signedness after promotion for
|
gdb, gdbserver, gdbsupport: fix leading space vs tabs issues
Many spots incorrectly use only spaces for indentation (for example,
there are a lot of spots in ada-lang.c). I've always found it awkward
when I needed to edit one of these spots: do I keep the original wrong
indentation, or do I fix it? What if the lines around it are also
wrong, do I fix them too? I probably don't want to fix them in the same
patch, to avoid adding noise to my patch.
So I propose to fix as much as possible once and for all (hopefully).
One typical counter argument for this is that it makes code archeology
more difficult, because git-blame will show this commit as the last
change for these lines. My counter counter argument is: when
git-blaming, you often need to do "blame the file at the parent commit"
anyway, to go past some other refactor that touched the line you are
interested in, but is not the change you are looking for. So you
already need a somewhat efficient way to do this.
Using some interactive tool, rather than plain git-blame, makes this
trivial. For example, I use "tig blame <file>", where going back past
the commit that changed the currently selected line is one keystroke.
It looks like Magit in Emacs does it too (though I've never used it).
Web viewers of Github and Gitlab do it too. My point is that it won't
really make archeology more difficult.
The other typical counter argument is that it will cause conflicts with
existing patches. That's true... but it's a one time cost, and those
are not conflicts that are difficult to resolve. I have also tried "git
rebase --ignore-whitespace", it seems to work well. Although that will
re-introduce the faulty indentation, so one needs to take care of fixing
the indentation in the patch after that (which is easy).
gdb/ChangeLog:
* aarch64-linux-tdep.c: Fix indentation.
* aarch64-ravenscar-thread.c: Fix indentation.
* aarch64-tdep.c: Fix indentation.
* aarch64-tdep.h: Fix indentation.
* ada-lang.c: Fix indentation.
* ada-lang.h: Fix indentation.
* ada-tasks.c: Fix indentation.
* ada-typeprint.c: Fix indentation.
* ada-valprint.c: Fix indentation.
* ada-varobj.c: Fix indentation.
* addrmap.c: Fix indentation.
* addrmap.h: Fix indentation.
* agent.c: Fix indentation.
* aix-thread.c: Fix indentation.
* alpha-bsd-nat.c: Fix indentation.
* alpha-linux-tdep.c: Fix indentation.
* alpha-mdebug-tdep.c: Fix indentation.
* alpha-nbsd-tdep.c: Fix indentation.
* alpha-obsd-tdep.c: Fix indentation.
* alpha-tdep.c: Fix indentation.
* amd64-bsd-nat.c: Fix indentation.
* amd64-darwin-tdep.c: Fix indentation.
* amd64-linux-nat.c: Fix indentation.
* amd64-linux-tdep.c: Fix indentation.
* amd64-nat.c: Fix indentation.
* amd64-obsd-tdep.c: Fix indentation.
* amd64-tdep.c: Fix indentation.
* amd64-windows-tdep.c: Fix indentation.
* annotate.c: Fix indentation.
* arc-tdep.c: Fix indentation.
* arch-utils.c: Fix indentation.
* arch/arm-get-next-pcs.c: Fix indentation.
* arch/arm.c: Fix indentation.
* arm-linux-nat.c: Fix indentation.
* arm-linux-tdep.c: Fix indentation.
* arm-nbsd-tdep.c: Fix indentation.
* arm-pikeos-tdep.c: Fix indentation.
* arm-tdep.c: Fix indentation.
* arm-tdep.h: Fix indentation.
* arm-wince-tdep.c: Fix indentation.
* auto-load.c: Fix indentation.
* auxv.c: Fix indentation.
* avr-tdep.c: Fix indentation.
* ax-gdb.c: Fix indentation.
* ax-general.c: Fix indentation.
* bfin-linux-tdep.c: Fix indentation.
* block.c: Fix indentation.
* block.h: Fix indentation.
* blockframe.c: Fix indentation.
* bpf-tdep.c: Fix indentation.
* break-catch-sig.c: Fix indentation.
* break-catch-syscall.c: Fix indentation.
* break-catch-throw.c: Fix indentation.
* breakpoint.c: Fix indentation.
* breakpoint.h: Fix indentation.
* bsd-uthread.c: Fix indentation.
* btrace.c: Fix indentation.
* build-id.c: Fix indentation.
* buildsym-legacy.h: Fix indentation.
* buildsym.c: Fix indentation.
* c-typeprint.c: Fix indentation.
* c-valprint.c: Fix indentation.
* c-varobj.c: Fix indentation.
* charset.c: Fix indentation.
* cli/cli-cmds.c: Fix indentation.
* cli/cli-decode.c: Fix indentation.
* cli/cli-decode.h: Fix indentation.
* cli/cli-script.c: Fix indentation.
* cli/cli-setshow.c: Fix indentation.
* coff-pe-read.c: Fix indentation.
* coffread.c: Fix indentation.
* compile/compile-cplus-types.c: Fix indentation.
* compile/compile-object-load.c: Fix indentation.
* compile/compile-object-run.c: Fix indentation.
* completer.c: Fix indentation.
* corefile.c: Fix indentation.
* corelow.c: Fix indentation.
* cp-abi.h: Fix indentation.
* cp-namespace.c: Fix indentation.
* cp-support.c: Fix indentation.
* cp-valprint.c: Fix indentation.
* cris-linux-tdep.c: Fix indentation.
* cris-tdep.c: Fix indentation.
* darwin-nat-info.c: Fix indentation.
* darwin-nat.c: Fix indentation.
* darwin-nat.h: Fix indentation.
* dbxread.c: Fix indentation.
* dcache.c: Fix indentation.
* disasm.c: Fix indentation.
* dtrace-probe.c: Fix indentation.
* dwarf2/abbrev.c: Fix indentation.
* dwarf2/attribute.c: Fix indentation.
* dwarf2/expr.c: Fix indentation.
* dwarf2/frame.c: Fix indentation.
* dwarf2/index-cache.c: Fix indentation.
* dwarf2/index-write.c: Fix indentation.
* dwarf2/line-header.c: Fix indentation.
* dwarf2/loc.c: Fix indentation.
* dwarf2/macro.c: Fix indentation.
* dwarf2/read.c: Fix indentation.
* dwarf2/read.h: Fix indentation.
* elfread.c: Fix indentation.
* eval.c: Fix indentation.
* event-top.c: Fix indentation.
* exec.c: Fix indentation.
* exec.h: Fix indentation.
* expprint.c: Fix indentation.
* f-lang.c: Fix indentation.
* f-typeprint.c: Fix indentation.
* f-valprint.c: Fix indentation.
* fbsd-nat.c: Fix indentation.
* fbsd-tdep.c: Fix indentation.
* findvar.c: Fix indentation.
* fork-child.c: Fix indentation.
* frame-unwind.c: Fix indentation.
* frame-unwind.h: Fix indentation.
* frame.c: Fix indentation.
* frv-linux-tdep.c: Fix indentation.
* frv-tdep.c: Fix indentation.
* frv-tdep.h: Fix indentation.
* ft32-tdep.c: Fix indentation.
* gcore.c: Fix indentation.
* gdb_bfd.c: Fix indentation.
* gdbarch.sh: Fix indentation.
* gdbarch.c: Re-generate
* gdbarch.h: Re-generate.
* gdbcore.h: Fix indentation.
* gdbthread.h: Fix indentation.
* gdbtypes.c: Fix indentation.
* gdbtypes.h: Fix indentation.
* glibc-tdep.c: Fix indentation.
* gnu-nat.c: Fix indentation.
* gnu-nat.h: Fix indentation.
* gnu-v2-abi.c: Fix indentation.
* gnu-v3-abi.c: Fix indentation.
* go32-nat.c: Fix indentation.
* guile/guile-internal.h: Fix indentation.
* guile/scm-cmd.c: Fix indentation.
* guile/scm-frame.c: Fix indentation.
* guile/scm-iterator.c: Fix indentation.
* guile/scm-math.c: Fix indentation.
* guile/scm-ports.c: Fix indentation.
* guile/scm-pretty-print.c: Fix indentation.
* guile/scm-value.c: Fix indentation.
* h8300-tdep.c: Fix indentation.
* hppa-linux-nat.c: Fix indentation.
* hppa-linux-tdep.c: Fix indentation.
* hppa-nbsd-nat.c: Fix indentation.
* hppa-nbsd-tdep.c: Fix indentation.
* hppa-obsd-nat.c: Fix indentation.
* hppa-tdep.c: Fix indentation.
* hppa-tdep.h: Fix indentation.
* i386-bsd-nat.c: Fix indentation.
* i386-darwin-nat.c: Fix indentation.
* i386-darwin-tdep.c: Fix indentation.
* i386-dicos-tdep.c: Fix indentation.
* i386-gnu-nat.c: Fix indentation.
* i386-linux-nat.c: Fix indentation.
* i386-linux-tdep.c: Fix indentation.
* i386-nto-tdep.c: Fix indentation.
* i386-obsd-tdep.c: Fix indentation.
* i386-sol2-nat.c: Fix indentation.
* i386-tdep.c: Fix indentation.
* i386-tdep.h: Fix indentation.
* i386-windows-tdep.c: Fix indentation.
* i387-tdep.c: Fix indentation.
* i387-tdep.h: Fix indentation.
* ia64-libunwind-tdep.c: Fix indentation.
* ia64-libunwind-tdep.h: Fix indentation.
* ia64-linux-nat.c: Fix indentation.
* ia64-linux-tdep.c: Fix indentation.
* ia64-tdep.c: Fix indentation.
* ia64-tdep.h: Fix indentation.
* ia64-vms-tdep.c: Fix indentation.
* infcall.c: Fix indentation.
* infcmd.c: Fix indentation.
* inferior.c: Fix indentation.
* infrun.c: Fix indentation.
* iq2000-tdep.c: Fix indentation.
* language.c: Fix indentation.
* linespec.c: Fix indentation.
* linux-fork.c: Fix indentation.
* linux-nat.c: Fix indentation.
* linux-tdep.c: Fix indentation.
* linux-thread-db.c: Fix indentation.
* lm32-tdep.c: Fix indentation.
* m2-lang.c: Fix indentation.
* m2-typeprint.c: Fix indentation.
* m2-valprint.c: Fix indentation.
* m32c-tdep.c: Fix indentation.
* m32r-linux-tdep.c: Fix indentation.
* m32r-tdep.c: Fix indentation.
* m68hc11-tdep.c: Fix indentation.
* m68k-bsd-nat.c: Fix indentation.
* m68k-linux-nat.c: Fix indentation.
* m68k-linux-tdep.c: Fix indentation.
* m68k-tdep.c: Fix indentation.
* machoread.c: Fix indentation.
* macrocmd.c: Fix indentation.
* macroexp.c: Fix indentation.
* macroscope.c: Fix indentation.
* macrotab.c: Fix indentation.
* macrotab.h: Fix indentation.
* main.c: Fix indentation.
* mdebugread.c: Fix indentation.
* mep-tdep.c: Fix indentation.
* mi/mi-cmd-catch.c: Fix indentation.
* mi/mi-cmd-disas.c: Fix indentation.
* mi/mi-cmd-env.c: Fix indentation.
* mi/mi-cmd-stack.c: Fix indentation.
* mi/mi-cmd-var.c: Fix indentation.
* mi/mi-cmds.c: Fix indentation.
* mi/mi-main.c: Fix indentation.
* mi/mi-parse.c: Fix indentation.
* microblaze-tdep.c: Fix indentation.
* minidebug.c: Fix indentation.
* minsyms.c: Fix indentation.
* mips-linux-nat.c: Fix indentation.
* mips-linux-tdep.c: Fix indentation.
* mips-nbsd-tdep.c: Fix indentation.
* mips-tdep.c: Fix indentation.
* mn10300-linux-tdep.c: Fix indentation.
* mn10300-tdep.c: Fix indentation.
* moxie-tdep.c: Fix indentation.
* msp430-tdep.c: Fix indentation.
* namespace.h: Fix indentation.
* nat/fork-inferior.c: Fix indentation.
* nat/gdb_ptrace.h: Fix indentation.
* nat/linux-namespaces.c: Fix indentation.
* nat/linux-osdata.c: Fix indentation.
* nat/netbsd-nat.c: Fix indentation.
* nat/x86-dregs.c: Fix indentation.
* nbsd-nat.c: Fix indentation.
* nbsd-tdep.c: Fix indentation.
* nios2-linux-tdep.c: Fix indentation.
* nios2-tdep.c: Fix indentation.
* nto-procfs.c: Fix indentation.
* nto-tdep.c: Fix indentation.
* objfiles.c: Fix indentation.
* objfiles.h: Fix indentation.
* opencl-lang.c: Fix indentation.
* or1k-tdep.c: Fix indentation.
* osabi.c: Fix indentation.
* osabi.h: Fix indentation.
* osdata.c: Fix indentation.
* p-lang.c: Fix indentation.
* p-typeprint.c: Fix indentation.
* p-valprint.c: Fix indentation.
* parse.c: Fix indentation.
* ppc-linux-nat.c: Fix indentation.
* ppc-linux-tdep.c: Fix indentation.
* ppc-nbsd-nat.c: Fix indentation.
* ppc-nbsd-tdep.c: Fix indentation.
* ppc-obsd-nat.c: Fix indentation.
* ppc-ravenscar-thread.c: Fix indentation.
* ppc-sysv-tdep.c: Fix indentation.
* ppc64-tdep.c: Fix indentation.
* printcmd.c: Fix indentation.
* proc-api.c: Fix indentation.
* producer.c: Fix indentation.
* producer.h: Fix indentation.
* prologue-value.c: Fix indentation.
* prologue-value.h: Fix indentation.
* psymtab.c: Fix indentation.
* python/py-arch.c: Fix indentation.
* python/py-bpevent.c: Fix indentation.
* python/py-event.c: Fix indentation.
* python/py-event.h: Fix indentation.
* python/py-finishbreakpoint.c: Fix indentation.
* python/py-frame.c: Fix indentation.
* python/py-framefilter.c: Fix indentation.
* python/py-inferior.c: Fix indentation.
* python/py-infthread.c: Fix indentation.
* python/py-objfile.c: Fix indentation.
* python/py-prettyprint.c: Fix indentation.
* python/py-registers.c: Fix indentation.
* python/py-signalevent.c: Fix indentation.
* python/py-stopevent.c: Fix indentation.
* python/py-stopevent.h: Fix indentation.
* python/py-threadevent.c: Fix indentation.
* python/py-tui.c: Fix indentation.
* python/py-unwind.c: Fix indentation.
* python/py-value.c: Fix indentation.
* python/py-xmethods.c: Fix indentation.
* python/python-internal.h: Fix indentation.
* python/python.c: Fix indentation.
* ravenscar-thread.c: Fix indentation.
* record-btrace.c: Fix indentation.
* record-full.c: Fix indentation.
* record.c: Fix indentation.
* reggroups.c: Fix indentation.
* regset.h: Fix indentation.
* remote-fileio.c: Fix indentation.
* remote.c: Fix indentation.
* reverse.c: Fix indentation.
* riscv-linux-tdep.c: Fix indentation.
* riscv-ravenscar-thread.c: Fix indentation.
* riscv-tdep.c: Fix indentation.
* rl78-tdep.c: Fix indentation.
* rs6000-aix-tdep.c: Fix indentation.
* rs6000-lynx178-tdep.c: Fix indentation.
* rs6000-nat.c: Fix indentation.
* rs6000-tdep.c: Fix indentation.
* rust-lang.c: Fix indentation.
* rx-tdep.c: Fix indentation.
* s12z-tdep.c: Fix indentation.
* s390-linux-tdep.c: Fix indentation.
* score-tdep.c: Fix indentation.
* ser-base.c: Fix indentation.
* ser-mingw.c: Fix indentation.
* ser-uds.c: Fix indentation.
* ser-unix.c: Fix indentation.
* serial.c: Fix indentation.
* sh-linux-tdep.c: Fix indentation.
* sh-nbsd-tdep.c: Fix indentation.
* sh-tdep.c: Fix indentation.
* skip.c: Fix indentation.
* sol-thread.c: Fix indentation.
* solib-aix.c: Fix indentation.
* solib-darwin.c: Fix indentation.
* solib-frv.c: Fix indentation.
* solib-svr4.c: Fix indentation.
* solib.c: Fix indentation.
* source.c: Fix indentation.
* sparc-linux-tdep.c: Fix indentation.
* sparc-nbsd-tdep.c: Fix indentation.
* sparc-obsd-tdep.c: Fix indentation.
* sparc-ravenscar-thread.c: Fix indentation.
* sparc-tdep.c: Fix indentation.
* sparc64-linux-tdep.c: Fix indentation.
* sparc64-nbsd-tdep.c: Fix indentation.
* sparc64-obsd-tdep.c: Fix indentation.
* sparc64-tdep.c: Fix indentation.
* stabsread.c: Fix indentation.
* stack.c: Fix indentation.
* stap-probe.c: Fix indentation.
* stubs/ia64vms-stub.c: Fix indentation.
* stubs/m32r-stub.c: Fix indentation.
* stubs/m68k-stub.c: Fix indentation.
* stubs/sh-stub.c: Fix indentation.
* stubs/sparc-stub.c: Fix indentation.
* symfile-mem.c: Fix indentation.
* symfile.c: Fix indentation.
* symfile.h: Fix indentation.
* symmisc.c: Fix indentation.
* symtab.c: Fix indentation.
* symtab.h: Fix indentation.
* target-float.c: Fix indentation.
* target.c: Fix indentation.
* target.h: Fix indentation.
* tic6x-tdep.c: Fix indentation.
* tilegx-linux-tdep.c: Fix indentation.
* tilegx-tdep.c: Fix indentation.
* top.c: Fix indentation.
* tracefile-tfile.c: Fix indentation.
* tracepoint.c: Fix indentation.
* tui/tui-disasm.c: Fix indentation.
* tui/tui-io.c: Fix indentation.
* tui/tui-regs.c: Fix indentation.
* tui/tui-stack.c: Fix indentation.
* tui/tui-win.c: Fix indentation.
* tui/tui-winsource.c: Fix indentation.
* tui/tui.c: Fix indentation.
* typeprint.c: Fix indentation.
* ui-out.h: Fix indentation.
* unittests/copy_bitwise-selftests.c: Fix indentation.
* unittests/memory-map-selftests.c: Fix indentation.
* utils.c: Fix indentation.
* v850-tdep.c: Fix indentation.
* valarith.c: Fix indentation.
* valops.c: Fix indentation.
* valprint.c: Fix indentation.
* valprint.h: Fix indentation.
* value.c: Fix indentation.
* value.h: Fix indentation.
* varobj.c: Fix indentation.
* vax-tdep.c: Fix indentation.
* windows-nat.c: Fix indentation.
* windows-tdep.c: Fix indentation.
* xcoffread.c: Fix indentation.
* xml-syscall.c: Fix indentation.
* xml-tdesc.c: Fix indentation.
* xstormy16-tdep.c: Fix indentation.
* xtensa-config.c: Fix indentation.
* xtensa-linux-nat.c: Fix indentation.
* xtensa-linux-tdep.c: Fix indentation.
* xtensa-tdep.c: Fix indentation.
gdbserver/ChangeLog:
* ax.cc: Fix indentation.
* dll.cc: Fix indentation.
* inferiors.h: Fix indentation.
* linux-low.cc: Fix indentation.
* linux-nios2-low.cc: Fix indentation.
* linux-ppc-ipa.cc: Fix indentation.
* linux-ppc-low.cc: Fix indentation.
* linux-x86-low.cc: Fix indentation.
* linux-xtensa-low.cc: Fix indentation.
* regcache.cc: Fix indentation.
* server.cc: Fix indentation.
* tracepoint.cc: Fix indentation.
gdbsupport/ChangeLog:
* common-exceptions.h: Fix indentation.
* event-loop.cc: Fix indentation.
* fileio.cc: Fix indentation.
* filestuff.cc: Fix indentation.
* gdb-dlfcn.cc: Fix indentation.
* gdb_string_view.h: Fix indentation.
* job-control.cc: Fix indentation.
* signals.cc: Fix indentation.
Change-Id: I4bad7ae6be0fbe14168b8ebafb98ffe14964a695
2020-11-02 23:26:14 +08:00
|
|
|
|
both operands. */
|
2022-09-21 23:05:21 +08:00
|
|
|
|
if (promoted_len1 < builtin->builtin_int->length ())
|
2008-09-11 22:14:20 +08:00
|
|
|
|
{
|
|
|
|
|
is_unsigned1 = 0;
|
2022-09-21 23:05:21 +08:00
|
|
|
|
promoted_len1 = builtin->builtin_int->length ();
|
2008-09-11 22:14:20 +08:00
|
|
|
|
}
|
2022-09-21 23:05:21 +08:00
|
|
|
|
if (promoted_len2 < builtin->builtin_int->length ())
|
2008-09-11 22:14:20 +08:00
|
|
|
|
{
|
|
|
|
|
is_unsigned2 = 0;
|
2022-09-21 23:05:21 +08:00
|
|
|
|
promoted_len2 = builtin->builtin_int->length ();
|
2008-09-11 22:14:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (promoted_len1 > promoted_len2)
|
|
|
|
|
{
|
|
|
|
|
unsigned_operation = is_unsigned1;
|
|
|
|
|
result_len = promoted_len1;
|
|
|
|
|
}
|
|
|
|
|
else if (promoted_len2 > promoted_len1)
|
|
|
|
|
{
|
|
|
|
|
unsigned_operation = is_unsigned2;
|
|
|
|
|
result_len = promoted_len2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned_operation = is_unsigned1 || is_unsigned2;
|
|
|
|
|
result_len = promoted_len1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (language->la_language)
|
|
|
|
|
{
|
2010-11-05 22:31:30 +08:00
|
|
|
|
case language_opencl:
|
2022-09-21 23:05:21 +08:00
|
|
|
|
if (result_len
|
|
|
|
|
<= lookup_signed_typename (language, "int")->length())
|
2010-11-05 22:31:30 +08:00
|
|
|
|
{
|
|
|
|
|
promoted_type =
|
|
|
|
|
(unsigned_operation
|
2019-12-06 02:44:30 +08:00
|
|
|
|
? lookup_unsigned_typename (language, "int")
|
|
|
|
|
: lookup_signed_typename (language, "int"));
|
2010-11-05 22:31:30 +08:00
|
|
|
|
}
|
2022-09-21 23:05:21 +08:00
|
|
|
|
else if (result_len
|
|
|
|
|
<= lookup_signed_typename (language, "long")->length())
|
2010-11-05 22:31:30 +08:00
|
|
|
|
{
|
|
|
|
|
promoted_type =
|
|
|
|
|
(unsigned_operation
|
2019-12-06 02:44:30 +08:00
|
|
|
|
? lookup_unsigned_typename (language, "long")
|
|
|
|
|
: lookup_signed_typename (language,"long"));
|
2010-11-05 22:31:30 +08:00
|
|
|
|
}
|
|
|
|
|
break;
|
2008-09-11 22:14:20 +08:00
|
|
|
|
default:
|
2023-02-28 22:03:55 +08:00
|
|
|
|
if (result_len <= builtin->builtin_int->length ())
|
|
|
|
|
{
|
|
|
|
|
promoted_type = (unsigned_operation
|
|
|
|
|
? builtin->builtin_unsigned_int
|
|
|
|
|
: builtin->builtin_int);
|
|
|
|
|
}
|
|
|
|
|
else if (result_len <= builtin->builtin_long->length ())
|
|
|
|
|
{
|
|
|
|
|
promoted_type = (unsigned_operation
|
|
|
|
|
? builtin->builtin_unsigned_long
|
|
|
|
|
: builtin->builtin_long);
|
|
|
|
|
}
|
|
|
|
|
else if (result_len <= builtin->builtin_long_long->length ())
|
2008-09-11 22:14:20 +08:00
|
|
|
|
{
|
2023-02-28 22:03:55 +08:00
|
|
|
|
promoted_type = (unsigned_operation
|
|
|
|
|
? builtin->builtin_unsigned_long_long
|
|
|
|
|
: builtin->builtin_long_long);
|
2008-09-11 22:14:20 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-02-28 22:03:55 +08:00
|
|
|
|
promoted_type = (unsigned_operation
|
|
|
|
|
? builtin->builtin_uint128
|
|
|
|
|
: builtin->builtin_int128);
|
2008-09-11 22:14:20 +08:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (promoted_type)
|
|
|
|
|
{
|
|
|
|
|
/* Promote both operands to common type. */
|
|
|
|
|
*arg1 = value_cast (promoted_type, *arg1);
|
|
|
|
|
*arg2 = value_cast (promoted_type, *arg2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
* value.h (value_add, value_sub): Remove.
(value_ptradd, value_ptrsub, value_ptrdiff): Add prototypes.
* valarith.c (value_add, value_sub): Remove.
(value_ptradd, value_ptrsub, value_ptrdiff): New functions.
(find_size_for_pointer_math): Add assertion. Update comment.
(value_binop): Update comment.
* eval.c (ptrmath_type_p): New function.
(evaluate_subexp_standard): Replace value_add and value_sub
by value_ptradd, value_ptrsub, value_ptrdiff or value_binop.
Use builtin_type_uint8 instead of builtin_type_char to hold
the increment for BINOP_{PRE,POST}{IN,DE}CREMENT operations.
* valarith.c (value_subscript): Replace value_add by
value_ptradd. Replace value_sub by value_binop.
* ada-lang.c (ada_value_ptr_subscript): Likewise.
(ada_tag_name_2): Replace value_add by value_ptradd.
(ada_evaluate_subexp): Replace value_add and value_sub by
value_binop.
* m2-lang.c (evaluate_subexp_modula2): Replace value_add
by value_ptradd.
* gnu-v2-abi.c (gnuv2_virtual_fn_field): Likewise.
* gnu-v3-abi.c (gnuv3_method_ptr_to_value): Likewise.
2008-09-11 22:13:46 +08:00
|
|
|
|
static int
|
2010-05-11 04:20:21 +08:00
|
|
|
|
ptrmath_type_p (const struct language_defn *lang, struct type *type)
|
* value.h (value_add, value_sub): Remove.
(value_ptradd, value_ptrsub, value_ptrdiff): Add prototypes.
* valarith.c (value_add, value_sub): Remove.
(value_ptradd, value_ptrsub, value_ptrdiff): New functions.
(find_size_for_pointer_math): Add assertion. Update comment.
(value_binop): Update comment.
* eval.c (ptrmath_type_p): New function.
(evaluate_subexp_standard): Replace value_add and value_sub
by value_ptradd, value_ptrsub, value_ptrdiff or value_binop.
Use builtin_type_uint8 instead of builtin_type_char to hold
the increment for BINOP_{PRE,POST}{IN,DE}CREMENT operations.
* valarith.c (value_subscript): Replace value_add by
value_ptradd. Replace value_sub by value_binop.
* ada-lang.c (ada_value_ptr_subscript): Likewise.
(ada_tag_name_2): Replace value_add by value_ptradd.
(ada_evaluate_subexp): Replace value_add and value_sub by
value_binop.
* m2-lang.c (evaluate_subexp_modula2): Replace value_add
by value_ptradd.
* gnu-v2-abi.c (gnuv2_virtual_fn_field): Likewise.
* gnu-v3-abi.c (gnuv3_method_ptr_to_value): Likewise.
2008-09-11 22:13:46 +08:00
|
|
|
|
{
|
|
|
|
|
type = check_typedef (type);
|
Convert lvalue reference type check to general reference type check
In almost all contexts (except for overload resolution rules and expression
semantics), lvalue and rvalue references are equivalent. That means that in all
but these cases we can replace a TYPE_CODE_REF check to a TYPE_IS_REFERENCE
check and, for switch statements, add a case label for a rvalue reference type
next to a case label for an lvalue reference type. This patch does exactly
that.
gdb/ChangeLog
PR gdb/14441
* aarch64-tdep.c (aarch64_type_align)
(aarch64_extract_return_value, aarch64_store_return_value): Change
lvalue reference type checks to general reference type checks.
* amd64-tdep.c (amd64_classify): Likewise.
* amd64-windows-tdep.c (amd64_windows_passed_by_integer_register):
Likewise.
* arm-tdep.c (arm_type_align, arm_extract_return_value)
(arm_store_return_value): Likewise.
* ax-gdb.c (gen_fetch, gen_cast): Likewise.
* c-typeprint.c (c_print_type): Likewise.
* c-varobj.c (adjust_value_for_child_access, c_value_of_variable)
(cplus_number_of_children, cplus_describe_child): Likewise.
* compile/compile-c-symbols.c (generate_vla_size): Likewise.
* completer.c (expression_completer): Likewise.
* cp-support.c (make_symbol_overload_list_adl_namespace):
Likewise.
* darwin-nat-info.c (info_mach_region_command): Likewise.
* dwarf2loc.c (entry_data_value_coerce_ref)
(value_of_dwarf_reg_entry): Likewise.
* eval.c (ptrmath_type_p, evaluate_subexp_standard)
(evaluate_subexp_for_address, evaluate_subexp_for_sizeof):
Likewise.
* findvar.c (extract_typed_address, store_typed_address):
Likewise.
* gdbtypes.c (rank_one_type): Likewise.
* hppa-tdep.c (hppa64_integral_or_pointer_p): Likewise.
* infcall.c (value_arg_coerce): Likewise.
* language.c (pointer_type): Likewise.
* m32c-tdep.c (m32c_reg_arg_type, m32c_m16c_address_to_pointer):
Likewise.
* m88k-tdep.c (m88k_integral_or_pointer_p): Likewise.
* mn10300-tdep.c (mn10300_type_align): Likewise.
* msp430-tdep.c (msp430_push_dummy_call): Likewise.
* ppc-sysv-tdep.c (do_ppc_sysv_return_value)
(ppc64_sysv_abi_push_param, ppc64_sysv_abi_return_value):
Likewise.
* printcmd.c (print_formatted, x_command): Likewise.
* python/py-type.c (typy_get_composite, typy_template_argument):
Likewise.
* python/py-value.c (valpy_referenced_value)
(valpy_get_dynamic_type, value_has_field): Likewise.
* s390-linux-tdep.c (s390_function_arg_integer): Likewise.
* sparc-tdep.c (sparc_integral_or_pointer_p): Likewise.
* sparc64-tdep.c (sparc64_integral_or_pointer_p): Likewise.
* spu-tdep.c (spu_scalar_value_p): Likewise.
* symtab.c (lookup_symbol_aux): Likewise.
* typeprint.c (whatis_exp, print_type_scalar): Likewise.
* valarith.c (binop_types_user_defined_p, unop_user_defined_p):
Likewise.
* valops.c (value_cast_pointers, value_cast)
(value_reinterpret_cast, value_dynamic_cast, value_addr, typecmp)
(value_struct_elt, value_struct_elt_bitpos)
(value_find_oload_method_list, find_overload_match)
(value_rtti_indirect_type): Likewise.
* valprint.c (val_print_scalar_type_p, generic_val_print):
Likewise.
* value.c (value_actual_type, value_as_address, unpack_long)
(pack_long, pack_unsigned_long, coerce_ref_if_computed)
(coerce_ref): Likewise.
* varobj.c (varobj_get_value_type): Likewise.
2017-03-21 04:47:54 +08:00
|
|
|
|
if (TYPE_IS_REFERENCE (type))
|
2022-07-31 10:43:54 +08:00
|
|
|
|
type = type->target_type ();
|
* value.h (value_add, value_sub): Remove.
(value_ptradd, value_ptrsub, value_ptrdiff): Add prototypes.
* valarith.c (value_add, value_sub): Remove.
(value_ptradd, value_ptrsub, value_ptrdiff): New functions.
(find_size_for_pointer_math): Add assertion. Update comment.
(value_binop): Update comment.
* eval.c (ptrmath_type_p): New function.
(evaluate_subexp_standard): Replace value_add and value_sub
by value_ptradd, value_ptrsub, value_ptrdiff or value_binop.
Use builtin_type_uint8 instead of builtin_type_char to hold
the increment for BINOP_{PRE,POST}{IN,DE}CREMENT operations.
* valarith.c (value_subscript): Replace value_add by
value_ptradd. Replace value_sub by value_binop.
* ada-lang.c (ada_value_ptr_subscript): Likewise.
(ada_tag_name_2): Replace value_add by value_ptradd.
(ada_evaluate_subexp): Replace value_add and value_sub by
value_binop.
* m2-lang.c (evaluate_subexp_modula2): Replace value_add
by value_ptradd.
* gnu-v2-abi.c (gnuv2_virtual_fn_field): Likewise.
* gnu-v3-abi.c (gnuv3_method_ptr_to_value): Likewise.
2008-09-11 22:13:46 +08:00
|
|
|
|
|
2020-05-15 01:46:38 +08:00
|
|
|
|
switch (type->code ())
|
* value.h (value_add, value_sub): Remove.
(value_ptradd, value_ptrsub, value_ptrdiff): Add prototypes.
* valarith.c (value_add, value_sub): Remove.
(value_ptradd, value_ptrsub, value_ptrdiff): New functions.
(find_size_for_pointer_math): Add assertion. Update comment.
(value_binop): Update comment.
* eval.c (ptrmath_type_p): New function.
(evaluate_subexp_standard): Replace value_add and value_sub
by value_ptradd, value_ptrsub, value_ptrdiff or value_binop.
Use builtin_type_uint8 instead of builtin_type_char to hold
the increment for BINOP_{PRE,POST}{IN,DE}CREMENT operations.
* valarith.c (value_subscript): Replace value_add by
value_ptradd. Replace value_sub by value_binop.
* ada-lang.c (ada_value_ptr_subscript): Likewise.
(ada_tag_name_2): Replace value_add by value_ptradd.
(ada_evaluate_subexp): Replace value_add and value_sub by
value_binop.
* m2-lang.c (evaluate_subexp_modula2): Replace value_add
by value_ptradd.
* gnu-v2-abi.c (gnuv2_virtual_fn_field): Likewise.
* gnu-v3-abi.c (gnuv3_method_ptr_to_value): Likewise.
2008-09-11 22:13:46 +08:00
|
|
|
|
{
|
|
|
|
|
case TYPE_CODE_PTR:
|
|
|
|
|
case TYPE_CODE_FUNC:
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
2020-07-04 16:06:08 +08:00
|
|
|
|
return type->is_vector () ? 0 : lang->c_style_arrays_p ();
|
* value.h (value_add, value_sub): Remove.
(value_ptradd, value_ptrsub, value_ptrdiff): Add prototypes.
* valarith.c (value_add, value_sub): Remove.
(value_ptradd, value_ptrsub, value_ptrdiff): New functions.
(find_size_for_pointer_math): Add assertion. Update comment.
(value_binop): Update comment.
* eval.c (ptrmath_type_p): New function.
(evaluate_subexp_standard): Replace value_add and value_sub
by value_ptradd, value_ptrsub, value_ptrdiff or value_binop.
Use builtin_type_uint8 instead of builtin_type_char to hold
the increment for BINOP_{PRE,POST}{IN,DE}CREMENT operations.
* valarith.c (value_subscript): Replace value_add by
value_ptradd. Replace value_sub by value_binop.
* ada-lang.c (ada_value_ptr_subscript): Likewise.
(ada_tag_name_2): Replace value_add by value_ptradd.
(ada_evaluate_subexp): Replace value_add and value_sub by
value_binop.
* m2-lang.c (evaluate_subexp_modula2): Replace value_add
by value_ptradd.
* gnu-v2-abi.c (gnuv2_virtual_fn_field): Likewise.
* gnu-v3-abi.c (gnuv3_method_ptr_to_value): Likewise.
2008-09-11 22:13:46 +08:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-21 07:34:41 +08:00
|
|
|
|
/* Represents a fake method with the given parameter types. This is
|
|
|
|
|
used by the parser to construct a temporary "expected" type for
|
Make "p S::method() const::static_var" work too
Trying to print a function local static variable of a const-qualified
method still doesn't work after the previous fixes:
(gdb) p 'S::method() const'::static_var
$1 = {i1 = 1, i2 = 2, i3 = 3}
(gdb) p S::method() const::static_var
No symbol "static_var" in specified context.
The reason is that the expression parser/evaluator loses the "const",
and the above unquoted case is just like trying to print a variable of
the non-const overload, if it exists, even. As if the above unquoted
case had been written as:
(gdb) p S::method()::static_var
No symbol "static_var" in specified context.
We can see the problem without static vars in the picture. With:
struct S
{
void method ();
void method () const;
};
Compare:
(gdb) print 'S::method(void) const'
$1 = {void (const S * const)} 0x400606 <S::method() const>
(gdb) print S::method(void) const
$2 = {void (S * const)} 0x4005d8 <S::method()> # wrong method!
That's what we need to fix. If we fix that, the function local static
case starts working.
The grammar production for function/method types is this one:
exp: exp '(' parameter_typelist ')' const_or_volatile
This results in a TYPE_INSTANCE expression evaluator operator. For
the example above, we get something like this ("set debug expression 1"):
...
0 TYPE_INSTANCE 1 TypeInstance: Type @0x560fda958be0 (void)
5 OP_SCOPE Type @0x560fdaa544d8 (S) Field name: `method'
...
While evaluating TYPE_INSTANCE, we end up in
value_struct_elt_for_reference, trying to find the method named
"method" that has the prototype recorded in TYPE_INSTANCE. In this
case, TYPE_INSTANCE says that we're looking for a method that has
"(void)" as parameters (that's what "1 TypeInstance: Type
@0x560fda958be0 (void)" above means. The trouble is that nowhere in
this mechanism do we communicate to value_struct_elt_for_reference
that we're looking for the _const_ overload.
value_struct_elt_for_reference only compared parameters, and the
non-const "method()" overload has matching parameters, so it's
considered the right match...
Conveniently, the "const_or_volatile" production in the grammar
already records "const" and "volatile" info in the type stack. The
type stack is not used in this code path, but we can borrow the
information. The patch converts the info in the type stack to an
"instance flags" enum, and adds that as another element in
TYPE_INSTANCE operators. This type instance flags is then applied to
the temporary type that is passed to value_struct_elt_for_reference
for matching.
The other side of the problem is that methods in the debug info aren't
marked const/volatile, so with that in place, the matching never finds
const/volatile-qualified methods.
The problem is that in the DWARF, there's no indication at all whether
a method is const/volatile qualified... For example (c++filt applied
to the linkage name for convenience):
<2><d3>: Abbrev Number: 6 (DW_TAG_subprogram)
<d4> DW_AT_external : 1
<d4> DW_AT_name : (indirect string, offset: 0x3df): method
<d8> DW_AT_decl_file : 1
<d9> DW_AT_decl_line : 58
<da> DW_AT_linkage_name: (indirect string, offset: 0x5b2): S::method() const
<de> DW_AT_declaration : 1
<de> DW_AT_object_pointer: <0xe6>
<e2> DW_AT_sibling : <0xec>
I see the same with both GCC and Clang. The patch works around this
by extracting the cv qualification from the "const" and "volatile" in
the demangled name. This will need further tweaking for "&" and
"const &" overloads, but we don't support them in the parser yet,
anyway.
The TYPE_CONST changes were necessary otherwise the comparisons in valops.c:
if (TYPE_CONST (intype) != TYPE_FN_FIELD_CONST (f, j))
continue;
would fail, because when both TYPE_CONST() TYPE_FN_FIELD_CONST() were
true, their values were different.
BTW, I'm recording the const/volatile-ness of methods in the
TYPE_FN_FIELD info because #1 - I'm not sure it's kosher to change the
method's type directly (vs having to call make_cv_type to create a new
type), and #2 it's what stabsread.c does:
...
case 'A': /* Normal functions. */
new_sublist->fn_field.is_const = 0;
new_sublist->fn_field.is_volatile = 0;
(*pp)++;
break;
case 'B': /* `const' member functions. */
new_sublist->fn_field.is_const = 1;
new_sublist->fn_field.is_volatile = 0;
...
After all this, this finally all works:
print S::method(void) const
$1 = {void (const S * const)} 0x400606 <S::method() const>
(gdb) p S::method() const::static_var
$2 = {i1 = 1, i2 = 2, i3 = 3}
gdb/ChangeLog:
2017-09-04 Pedro Alves <palves@redhat.com>
* c-exp.y (function_method, function_method_void): Add current
instance flags to TYPE_INSTANCE.
* dwarf2read.c (check_modifier): New.
(compute_delayed_physnames): Assert that only C++ adds delayed
physnames. Mark fn_fields as const/volatile depending on
physname.
* eval.c (make_params): New type_instance_flags parameter. Use
it as the new type's instance flags.
(evaluate_subexp_standard) <TYPE_INSTANCE>: Extract the instance
flags element and pass it to make_params.
* expprint.c (print_subexp_standard) <TYPE_INSTANCE>: Handle
instance flags element.
(dump_subexp_body_standard) <TYPE_INSTANCE>: Likewise.
* gdbtypes.h: Include "enum-flags.h".
(type_instance_flags): New enum-flags type.
(TYPE_CONST, TYPE_VOLATILE, TYPE_RESTRICT, TYPE_ATOMIC)
(TYPE_CODE_SPACE, TYPE_DATA_SPACE): Return boolean.
* parse.c (operator_length_standard) <TYPE_INSTANCE>: Adjust.
(follow_type_instance_flags): New function.
(operator_check_standard) <TYPE_INSTANCE>: Adjust.
* parser-defs.h (follow_type_instance_flags): Declare.
* valops.c (value_struct_elt_for_reference): const/volatile must
match too.
gdb/testsuite/ChangeLog:
2017-09-04 Pedro Alves <palves@redhat.com>
* gdb.base/func-static.c (S::method const, S::method volatile)
(S::method volatile const): New methods.
(c_s, v_s, cv_s): New instances.
(main): Call method() on them.
* gdb.base/func-static.exp (syntax_re, cannot_resolve_re): New variables.
(cannot_resolve): New procedure.
(cxx_scopes_list): Test cv methods. Add print-scope-quote and
print-quote-unquoted columns.
(do_test): Test printing each scope too.
2017-09-05 03:21:16 +08:00
|
|
|
|
method overload resolution. FLAGS is used as instance flags of the
|
|
|
|
|
new type, in order to be able to make the new type represent a
|
|
|
|
|
const/volatile overload. */
|
2009-11-11 06:17:58 +08:00
|
|
|
|
|
2017-09-21 07:34:41 +08:00
|
|
|
|
class fake_method
|
2009-11-11 06:17:58 +08:00
|
|
|
|
{
|
2017-09-21 07:34:41 +08:00
|
|
|
|
public:
|
|
|
|
|
fake_method (type_instance_flags flags,
|
|
|
|
|
int num_types, struct type **param_types);
|
|
|
|
|
~fake_method ();
|
|
|
|
|
|
|
|
|
|
/* The constructed type. */
|
|
|
|
|
struct type *type () { return &m_type; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
struct type m_type {};
|
|
|
|
|
main_type m_main_type {};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fake_method::fake_method (type_instance_flags flags,
|
|
|
|
|
int num_types, struct type **param_types)
|
|
|
|
|
{
|
|
|
|
|
struct type *type = &m_type;
|
|
|
|
|
|
|
|
|
|
TYPE_MAIN_TYPE (type) = &m_main_type;
|
2022-07-31 00:01:12 +08:00
|
|
|
|
type->set_length (1);
|
2020-05-15 01:45:40 +08:00
|
|
|
|
type->set_code (TYPE_CODE_METHOD);
|
2009-11-11 06:17:58 +08:00
|
|
|
|
TYPE_CHAIN (type) = type;
|
Use type_instance_flags more throughout
A later patch in this series will rewrite enum_flags fixing some API
holes. That would cause build failures around code using
type_instance_flags. Or rather, that should be using it, but wasn't.
This patch fixes it by using type_instance_flags throughout instead of
plain integers.
Note that we can't make the seemingly obvious change to struct
type::instance_flags:
- unsigned instance_flags : 9;
+ ENUM_BITFIELD (type_instance_flag_value) instance_flags : 9;
Because G++ complains then that 9 bits isn't sufficient for holding
all values of type_instance_flag_value.
So the patch adds an type::instance_flags() method, which takes care
of casting appropriately, and adds a separate type::set_instance_flags
method, following the pattern of the ongoing TYPE_XXX macro
elimination. This converts uses of TYPE_INSTANCE_FLAGS to
type::instance_flags() in the places where the code was already being
touched, but there are still many references to the
TYPE_INSTANCE_FLAGS macro left behind. Those could/should be fully
replaced at some point.
gdb/ChangeLog:
* avr-tdep.c (avr_address_class_type_flags): Return
type_instance_flags.
(avr_address_class_type_flags_to_name): Take a
type_instance_flags.
(avr_address_class_name_to_type_flags): Return bool and take a
type_instance_flags.
* d-lang.c (build_d_types): Use type::set_instance_flags.
* ft32-tdep.c (ft32_address_class_type_flags): Return
type_instance_flags.
(ft32_address_class_type_flags_to_name): Take a
type_instance_flags.
(ft32_address_class_name_to_type_flags): Return bool and take a
type_instance_flags.
(ft32_gdbarch_init): Use type::set_instance_flags.
* eval.c (fake_method::fake_method): Use type::set_instance_flags.
* gdbarch.h, gdbarch.c: Regenerate.
* gdbarch.sh (address_class_type_flags): Use type_instance_flags.
(address_class_name_to_type_flags): Use type_instance_flags and
bool.
* gdbtypes.c (address_space_name_to_int)
(address_space_int_to_name, make_qualified_type): Use
type_instance_flags.
(make_qualified_type): Use type_instance_flags and
type::set_instance_flags.
(make_type_with_address_space, make_cv_type, make_vector_type)
(check_typedef): Use type_instance_flags.
(recursive_dump_type): Cast type_instance_flags to unsigned for
printing.
(copy_type_recursive): Use type::set_instance_flags.
(gdbtypes_post_init): Use type::set_instance_flags.
* gdbtypes.h (struct type) <instance_flags>: Rename to ...
<m_instance_flags>: ... this.
<instance_flags, set_instance_flags>: New methods.
(TYPE_INSTANCE_FLAGS): Use the instance_flags method.
(SET_TYPE_INSTANCE_FLAGS): New.
(address_space_name_to_int, address_space_int_to_name)
(make_type_with_address_space): Pass flags using
type_instance_flags instead of int.
* stabsread.c (cleanup_undefined_types_noname): Use
type::set_instance_flags.
* s390-tdep.c (s390_address_class_type_flags): Return
type_instance_flags.
(s390_address_class_type_flags_to_name): Take a
type_instance_flags.
(s390_address_class_name_to_type_flags): Return bool and take a
type_instance_flags.
* type-stack.c (type_stack::follow_types): Use
type_instance_flags.
* dwarf2/read.c (read_tag_pointer_type): Use type_instance_flags.
2020-09-15 04:16:56 +08:00
|
|
|
|
type->set_instance_flags (flags);
|
2012-07-09 22:20:52 +08:00
|
|
|
|
if (num_types > 0)
|
2012-07-06 22:48:48 +08:00
|
|
|
|
{
|
2012-07-09 22:20:52 +08:00
|
|
|
|
if (param_types[num_types - 1] == NULL)
|
|
|
|
|
{
|
|
|
|
|
--num_types;
|
2020-09-14 23:08:01 +08:00
|
|
|
|
type->set_has_varargs (true);
|
2012-07-09 22:20:52 +08:00
|
|
|
|
}
|
2020-05-15 01:46:38 +08:00
|
|
|
|
else if (check_typedef (param_types[num_types - 1])->code ()
|
2012-07-09 22:20:52 +08:00
|
|
|
|
== TYPE_CODE_VOID)
|
|
|
|
|
{
|
|
|
|
|
--num_types;
|
|
|
|
|
/* Caller should have ensured this. */
|
|
|
|
|
gdb_assert (num_types == 0);
|
2020-09-14 23:08:00 +08:00
|
|
|
|
type->set_is_prototyped (true);
|
2012-07-09 22:20:52 +08:00
|
|
|
|
}
|
2012-07-06 22:48:48 +08:00
|
|
|
|
}
|
2012-07-09 22:20:52 +08:00
|
|
|
|
|
gdb: Don't leak memory with TYPE_ALLOC / TYPE_ZALLOC
This patch started as an observation from valgrind that GDB appeared
to be loosing track of some memory associated with types. An example
valgrind stack would be:
24 bytes in 1 blocks are possibly lost in loss record 419 of 5,361
at 0x4C2EA1E: calloc (vg_replace_malloc.c:711)
by 0x623D26: xcalloc (common-utils.c:85)
by 0x623D65: xzalloc(unsigned long) (common-utils.c:95)
by 0x72A066: make_function_type(type*, type**) (gdbtypes.c:510)
by 0x72A098: lookup_function_type(type*) (gdbtypes.c:521)
by 0x73635D: gdbtypes_post_init(gdbarch*) (gdbtypes.c:5439)
by 0x727590: gdbarch_data(gdbarch*, gdbarch_data*) (gdbarch.c:5230)
by 0x735B99: builtin_type(gdbarch*) (gdbtypes.c:5313)
by 0x514D95: elf_rel_plt_read(minimal_symbol_reader&, objfile*, bfd_symbol**) (elfread.c:542)
by 0x51662F: elf_read_minimal_symbols(objfile*, int, elfinfo const*) (elfread.c:1121)
by 0x5168A5: elf_symfile_read(objfile*, enum_flags<symfile_add_flag>) (elfread.c:1207)
by 0x8520F5: read_symbols(objfile*, enum_flags<symfile_add_flag>) (symfile.c:794)
When we look in make_function_type we find a call to TYPE_ZALLOC
(inside the INIT_FUNC_SPECIFIC macro). It is this call to TYPE_ZALLOC
that is allocating memory with xcalloc, that is then getting lost.
The problem is tht calling TYPE_ALLOC or TYPE_ZALLOC currently
allocates memory from either the objfile obstack or by using malloc.
The problem with this is that types are allocated either on the
objfile obstack, or on the gdbarch obstack.
As a result, if we discard a type associated with an objfile then
auxiliary data allocated with TYPE_(Z)ALLOC will be correctly
discarded. But, if we were ever to discard a gdbarch then any
auxiliary type data would be leaked. Right now there are very few
places in GDB where a gdbarch is ever discarded, but it shouldn't hurt
to close down these bugs as we spot them.
This commit ensures that auxiliary type data is allocated from the
same obstack as the type itself, which should reduce leaked memory.
The one problem case that I found with this change was in eval.c,
where in one place we allocate a local type structure, and then used
TYPE_ZALLOC to allocate some space for the type. This local type is
neither object file owned, nor gdbarch owned, and so the updated
TYPE_ALLOC code is unable to find an objstack to allocate space on.
My proposed solution for this issue is that the space should be
allocated with a direct call to xzalloc. We could extend TYPE_ALLOC
to check for type->gdbarch being null, and then fall back to a direct
call to xzalloc, however, I think that making this rare case of a
local type require special handling is not a bad thing, this serves to
highlight that clearing up the memory will require special handling
too.
This special case of a local type is interesting as the types owner
field (contained within the main_type) is completely null. While
reflecting on this I looked at how types use the get_type_arch
function. It seems clear that, based on how this is used, it is never
intended that null will be returned from this function. This only
goes to reinforce, how locally alloctaed types, with no owner, are
both special, and need to be handled carefully. To help spot errors
earlier, I added an assert into get_type_arch that the returned arch
is not null.
Inside gdbarch.c I found a few other places where auxiliary type data
was being allocated directly on the heap rather than on the types
obstack. I have fixed these to call TYPE_ALLOC now.
Finally, it is worth noting that as we don't clean up our gdbarch
objects yet, then this will not make much of an impact on the amount
of memory reported as lost at program termination time. Memory
allocated for auxiliary type information is still not freed, however,
it is now on the correct obstack. If we do ever start freeing our
gdbarch structures then the associated type data will be cleaned up
correctly.
Tested on X86-64 GNU/Linux with no regressions.
gdb/ChangeLog:
* eval.c (fake_method::fake_method): Call xzalloc directly for a
type that is neither object file owned, nor gdbarch owned.
* gdbtypes.c (get_type_gdbarch): Add an assert that returned
gdbarch is non-NULL.
(alloc_type_instance): Allocate non-objfile owned types on the
gdbarch obstack.
(copy_type_recursive): Allocate TYPE_FIELDS and TYPE_RANGE_DATA
using TYPE_ALLOC to ensure memory is allocated on the correct
obstack.
* gdbtypes.h (TYPE_ALLOC): Allocate space on either the objfile
obstack, or the gdbarch obstack.
(TYPE_ZALLOC): Rewrite using TYPE_ALLOC.
2018-09-10 20:50:34 +08:00
|
|
|
|
/* We don't use TYPE_ZALLOC here to allocate space as TYPE is owned by
|
|
|
|
|
neither an objfile nor a gdbarch. As a result we must manually
|
|
|
|
|
allocate memory for auxiliary fields, and free the memory ourselves
|
|
|
|
|
when we are done with it. */
|
2020-05-23 04:55:14 +08:00
|
|
|
|
type->set_num_fields (num_types);
|
2020-05-23 04:55:16 +08:00
|
|
|
|
type->set_fields
|
|
|
|
|
((struct field *) xzalloc (sizeof (struct field) * num_types));
|
2009-11-11 06:17:58 +08:00
|
|
|
|
|
|
|
|
|
while (num_types-- > 0)
|
2020-06-09 03:26:04 +08:00
|
|
|
|
type->field (num_types).set_type (param_types[num_types]);
|
2017-09-21 07:34:41 +08:00
|
|
|
|
}
|
2009-11-11 06:17:58 +08:00
|
|
|
|
|
2017-09-21 07:34:41 +08:00
|
|
|
|
fake_method::~fake_method ()
|
|
|
|
|
{
|
2020-05-23 04:55:17 +08:00
|
|
|
|
xfree (m_type.fields ());
|
2009-11-11 06:17:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
namespace expr
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
type_instance_operation::evaluate (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
type_instance_flags flags = std::get<0> (m_storage);
|
|
|
|
|
std::vector<type *> &types = std::get<1> (m_storage);
|
|
|
|
|
|
|
|
|
|
fake_method fake_expect_type (flags, types.size (), types.data ());
|
|
|
|
|
return std::get<2> (m_storage)->evaluate (fake_expect_type.type (),
|
|
|
|
|
exp, noside);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-05 03:21:14 +08:00
|
|
|
|
/* Helper for evaluating an OP_VAR_VALUE. */
|
|
|
|
|
|
(Ada) fix handling of minimal symbols (UNOP_CAST and UNOP_ADDR)
Consider a program which provides a symbol without debugging
information. For instance, compiling the following code without -g:
Some_Minimal_Symbol : Integer := 1234;
pragma Export (C, Some_Minimal_Symbol, "some_minsym");
Trying to print this variable with GDB now causes an error, which
is now expected:
(gdb) p some_minsym
'some_minsym' has unknown type; cast it to its declared type
However, trying to cast this symbol, or to take its address
does not work:
(gdb) p integer(some_minsym)
'some_minsym' has unknown type; cast it to its declared type
(gdb) p &some_minsym
'some_minsym' has unknown type; cast it to its declared type
Another manisfestation of this issue can be seen when trying to
insert an Ada exception catchpoint for a specific standard exception
(this only occurs if the Ada runtime is built without debugging
information, which is the default). For instance:
$ (gdb) catch exception constraint_error
warning: failed to reevaluate internal exception condition for catchpoint 0: 'constraint_error' has unknown type; cast it to its declared type
This is because, internally, the cachtpoint uses a condition referencing
a minimal symbol, more precisely:
long_integer (e) = long_integer (&constraint_error)
This patch fixes all issues listed above:
1. resolve_subexp: Special-case the handling of OP_VAR_MSYM_VALUE
expression elements, where there are no ambiguities to be resolved
in that situation;
2. ada_evaluate_subexp: Enhance the handling of the UNOP_CAST
handling so as to process the case where the target of
the cast is a minimal symbol (as well as a symbol with debugging
information). This mimics what's done in C.
gdb/ChangeLog:
* ada-lang.c (resolve_subexp): Add handling of OP_VAR_MSYM_VALUE.
(ada_evaluate_subexp_for_cast): New function.
(ada_evaluate_subexp) <UNOP_CAST>: Replace code by call to
ada_evaluate_subexp_for_cast.
(ada_evaluate_subexp) <nosideret>: Replace code by call to
eval_skip_value.
* eval.c (evaluate_var_value): Make non-static.
(evaluate_var_msym_value, eval_skip_value): Likewise.
* value.h (evaluate_var_value, evaluate_var_msym_value)
(eval_skip_value): Declare.
gdb/testsuite/ChangeLog:
* gdb.ada/minsyms: New testcase.
Tested on x86_64-linux. No regression. Fixes the following failures:
catch_ex.exp: continuing to Program_Error exception
catch_ex.exp: continuing to failed assertion
catch_ex.exp: continuing to unhandled exception
catch_ex.exp: continuing to program completion
complete.exp: p <Exported_Capitalized>
complete.exp: p Exported_Capitalized
complete.exp: p exported_capitalized
mi_catch_ex.exp: catch Program_Error (unexpected output)
mi_catch_ex.exp: continue to exception catchpoint hit (unknown output after running)
mi_catch_ex.exp: continue to assert failure catchpoint hit (unknown output after running)
mi_catch_ex.exp: continue to unhandled exception catchpoint hit (unknown output after running)
mi_ex_cond.exp: catch C_E if i = 2 (unexpected output)
2017-11-16 08:02:33 +08:00
|
|
|
|
value *
|
2017-09-05 03:21:14 +08:00
|
|
|
|
evaluate_var_value (enum noside noside, const block *blk, symbol *var)
|
|
|
|
|
{
|
2023-02-01 04:41:35 +08:00
|
|
|
|
/* JYG: We used to just return value::zero of the symbol type if
|
2017-09-05 03:21:14 +08:00
|
|
|
|
we're asked to avoid side effects. Otherwise we return
|
|
|
|
|
value_of_variable (...). However I'm not sure if
|
|
|
|
|
value_of_variable () has any side effect. We need a full value
|
|
|
|
|
object returned here for whatis_exp () to call evaluate_type ()
|
|
|
|
|
and then pass the full value to value_rtti_target_type () if we
|
|
|
|
|
are dealing with a pointer or reference to a base class and print
|
|
|
|
|
object is on. */
|
|
|
|
|
|
|
|
|
|
struct value *ret = NULL;
|
|
|
|
|
|
2019-04-04 06:02:42 +08:00
|
|
|
|
try
|
2017-09-05 03:21:14 +08:00
|
|
|
|
{
|
|
|
|
|
ret = value_of_variable (var, blk);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-04 05:59:07 +08:00
|
|
|
|
catch (const gdb_exception_error &except)
|
2017-09-05 03:21:14 +08:00
|
|
|
|
{
|
|
|
|
|
if (noside != EVAL_AVOID_SIDE_EFFECTS)
|
Replace throw_exception with throw in some cases
This replaces throw_exception with "throw;" when possible. This was
written by script. The rule that is followed is that uses of the
form:
catch (... &name)
{
...
throw_exception (name);
}
... can be rewritten. This should always be safe, because exceptions
are caught by const reference, and therefore can't be modified in the
body of the catch.
gdb/ChangeLog
2019-04-08 Tom Tromey <tom@tromey.com>
* valops.c (value_rtti_indirect_type): Replace throw_exception
with throw.
* tracefile-tfile.c (tfile_target_open): Replace throw_exception
with throw.
* thread.c (thr_try_catch_cmd): Replace throw_exception with
throw.
* target.c (target_translate_tls_address): Replace throw_exception
with throw.
* stack.c (frame_apply_command_count): Replace throw_exception
with throw.
* solib-spu.c (append_ocl_sos): Replace throw_exception with
throw.
* s390-tdep.c (s390_frame_unwind_cache): Replace throw_exception
with throw.
* rs6000-tdep.c (rs6000_frame_cache)
(rs6000_epilogue_frame_cache): Replace throw_exception with throw.
* remote.c: Replace throw_exception with throw.
* record-full.c (record_full_message, record_full_wait_1)
(record_full_restore): Replace throw_exception with throw.
* record-btrace.c:
(get_thread_current_frame_id, record_btrace_start_replaying)
(cmd_record_btrace_bts_start, cmd_record_btrace_pt_start)
(cmd_record_btrace_start): Replace throw_exception with throw.
* parse.c (parse_exp_in_context_1): Replace throw_exception with
throw.
* linux-nat.c (detach_one_lwp, linux_resume_one_lwp)
(resume_stopped_resumed_lwps): Replace throw_exception with throw.
* linespec.c:
(find_linespec_symbols): Replace throw_exception with throw.
* infrun.c (displaced_step_prepare, resume): Replace
throw_exception with throw.
* infcmd.c (post_create_inferior): Replace throw_exception with
throw.
* inf-loop.c (inferior_event_handler): Replace throw_exception
with throw.
* i386-tdep.c (i386_frame_cache, i386_epilogue_frame_cache)
(i386_sigtramp_frame_cache): Replace throw_exception with throw.
* frame.c (frame_unwind_pc, get_prev_frame_if_no_cycle)
(get_prev_frame_always, get_frame_pc_if_available)
(get_frame_address_in_block_if_available, get_frame_language):
Replace throw_exception with throw.
* frame-unwind.c (frame_unwind_try_unwinder): Replace
throw_exception with throw.
* eval.c (fetch_subexp_value, evaluate_var_value)
(evaluate_funcall, evaluate_subexp_standard): Replace
throw_exception with throw.
* dwarf2loc.c (call_site_find_chain)
(dwarf2_evaluate_loc_desc_full, dwarf2_locexpr_baton_eval):
Replace throw_exception with throw.
* dwarf2-frame.c (dwarf2_frame_cache): Replace throw_exception
with throw.
* darwin-nat.c (darwin_attach_pid): Replace throw_exception with
throw.
* cp-abi.c (baseclass_offset): Replace throw_exception with throw.
* completer.c (complete_line_internal): Replace throw_exception
with throw.
* compile/compile-object-run.c (compile_object_run): Replace
throw_exception with throw.
* cli/cli-script.c (process_next_line): Replace throw_exception
with throw.
* btrace.c (btrace_compute_ftrace_pt, btrace_compute_ftrace)
(btrace_enable, btrace_maint_update_pt_packets): Replace
throw_exception with throw.
* breakpoint.c (create_breakpoint, save_breakpoints): Replace
throw_exception with throw.
* break-catch-throw.c (re_set_exception_catchpoint): Replace
throw_exception with throw.
* amd64-tdep.c (amd64_frame_cache, amd64_sigtramp_frame_cache)
(amd64_epilogue_frame_cache): Replace throw_exception with throw.
* aarch64-tdep.c (aarch64_make_prologue_cache)
(aarch64_make_stub_cache): Replace throw_exception with throw.
gdb/gdbserver/ChangeLog
2019-04-08 Tom Tromey <tom@tromey.com>
* linux-low.c (linux_detach_one_lwp): Replace throw_exception with
throw.
(linux_resume_one_lwp): Likewise.
2019-01-29 01:45:45 +08:00
|
|
|
|
throw;
|
2017-09-05 03:21:14 +08:00
|
|
|
|
|
2023-02-01 04:41:35 +08:00
|
|
|
|
ret = value::zero (var->type (), not_lval);
|
2017-09-05 03:21:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
namespace expr
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
var_value_operation::evaluate (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
2021-04-16 00:05:00 +08:00
|
|
|
|
symbol *var = std::get<0> (m_storage).symbol;
|
2022-01-28 11:16:41 +08:00
|
|
|
|
if (var->type ()->code () == TYPE_CODE_ERROR)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
error_unknown_type (var->print_name ());
|
2021-04-16 00:05:00 +08:00
|
|
|
|
return evaluate_var_value (noside, std::get<0> (m_storage).block, var);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} /* namespace expr */
|
|
|
|
|
|
Introduce OP_VAR_MSYM_VALUE
The previous patch left GDB with an inconsistency. While with normal
expression evaluation the "unknown return type" error shows the name
of the function that misses debug info:
(gdb) p getenv ("PATH")
'getenv' has unknown return type; cast the call to its declared return type
^^^^^^
which can by handy in more complicated expressions, "ptype" does not:
(gdb) ptype getenv ("PATH")
function has unknown return type; cast the call to its declared return type
^^^^^^^^
This commit is a step toward fixing it.
The problem is that while evaluating the expression above, we have no
reference to the minimal symbol where we could extract the name from.
This is because the resulting expression tree has no reference to the
minsym at all. During parsing, the type and address of the minsym are
extracted and an UNOP_MEMVAL / UNOP_MEMVAL_TLS operator is generated
(see write_exp_elt_msym). With "set debug expression", here's what
you see:
0 OP_FUNCALL Number of args: 0
3 UNOP_MEMVAL Type @0x565334a51930 (<text variable, no debug info>)
6 OP_LONG Type @0x565334a51c60 (__CORE_ADDR), value 140737345035648 (0x7ffff7751d80)
The "print" case finds the function name, because
call_function_by_hand looks up the function by address again.
However, for "ptype", we don't reach that code, because obviously we
don't really call the function.
Unlike minsym references, references to variables with debug info have
a pointer to the variable's symbol in the expression tree, with
OP_VAR_VALUE:
(gdb) ptype main()
...
0 OP_FUNCALL Number of args: 0
3 OP_VAR_VALUE Block @0x0, symbol @0x559bbbd9b358 (main(int, char**))
...
so I don't see why do minsyms need to be different. So to prepare for
fixing the missing function name issue, this commit adds a new
OP_VAR_MSYM_VALUE operator that mimics OP_VAR_VALUE, except that it's
for minsyms instead of debug symbols. For infcalls, we now get
expressions like these:
0 OP_FUNCALL Number of args: 0
3 OP_VAR_MSYM_VALUE Objfile @0x1e41bf0, msymbol @0x7fffe599b000 (getenv)
In the following patch, we'll make OP_FUNCALL extract the function
name from the symbol stored in OP_VAR_VALUE/OP_VAR_MSYM_VALUE.
OP_VAR_MSYM_VALUE will be used more in a later patch in the series
too.
gdb/ChangeLog:
2017-09-04 Pedro Alves <palves@redhat.com>
* ada-lang.c (resolve_subexp): Handle OP_VAR_MSYM_VALUE.
* ax-gdb.c (gen_msym_var_ref): New function.
(gen_expr): Handle OP_VAR_MSYM_VALUE.
* eval.c (evaluate_var_msym_value): New function.
* eval.c (evaluate_subexp_standard): Handle OP_VAR_MSYM_VALUE.
<OP_FUNCALL>: Extract function name from symbol/minsym and pass it
to call_function_by_hand.
* expprint.c (print_subexp_standard, dump_subexp_body_standard):
Handle OP_VAR_MSYM_VALUE.
(union exp_element) <msymbol>: New field.
* minsyms.h (struct type): Forward declare.
(find_minsym_type_and_address): Declare.
* parse.c (write_exp_elt_msym): New function.
(write_exp_msymbol): Delete, refactored as ...
(find_minsym_type_and_address): ... this new function.
(write_exp_msymbol): Reimplement using OP_VAR_MSYM_VALUE.
(operator_length_standard, operator_check_standard): Handle
OP_VAR_MSYM_VALUE.
* std-operator.def (OP_VAR_MSYM_VALUE): New.
2017-09-05 03:21:13 +08:00
|
|
|
|
/* Helper for evaluating an OP_VAR_MSYM_VALUE. */
|
|
|
|
|
|
(Ada) fix handling of minimal symbols (UNOP_CAST and UNOP_ADDR)
Consider a program which provides a symbol without debugging
information. For instance, compiling the following code without -g:
Some_Minimal_Symbol : Integer := 1234;
pragma Export (C, Some_Minimal_Symbol, "some_minsym");
Trying to print this variable with GDB now causes an error, which
is now expected:
(gdb) p some_minsym
'some_minsym' has unknown type; cast it to its declared type
However, trying to cast this symbol, or to take its address
does not work:
(gdb) p integer(some_minsym)
'some_minsym' has unknown type; cast it to its declared type
(gdb) p &some_minsym
'some_minsym' has unknown type; cast it to its declared type
Another manisfestation of this issue can be seen when trying to
insert an Ada exception catchpoint for a specific standard exception
(this only occurs if the Ada runtime is built without debugging
information, which is the default). For instance:
$ (gdb) catch exception constraint_error
warning: failed to reevaluate internal exception condition for catchpoint 0: 'constraint_error' has unknown type; cast it to its declared type
This is because, internally, the cachtpoint uses a condition referencing
a minimal symbol, more precisely:
long_integer (e) = long_integer (&constraint_error)
This patch fixes all issues listed above:
1. resolve_subexp: Special-case the handling of OP_VAR_MSYM_VALUE
expression elements, where there are no ambiguities to be resolved
in that situation;
2. ada_evaluate_subexp: Enhance the handling of the UNOP_CAST
handling so as to process the case where the target of
the cast is a minimal symbol (as well as a symbol with debugging
information). This mimics what's done in C.
gdb/ChangeLog:
* ada-lang.c (resolve_subexp): Add handling of OP_VAR_MSYM_VALUE.
(ada_evaluate_subexp_for_cast): New function.
(ada_evaluate_subexp) <UNOP_CAST>: Replace code by call to
ada_evaluate_subexp_for_cast.
(ada_evaluate_subexp) <nosideret>: Replace code by call to
eval_skip_value.
* eval.c (evaluate_var_value): Make non-static.
(evaluate_var_msym_value, eval_skip_value): Likewise.
* value.h (evaluate_var_value, evaluate_var_msym_value)
(eval_skip_value): Declare.
gdb/testsuite/ChangeLog:
* gdb.ada/minsyms: New testcase.
Tested on x86_64-linux. No regression. Fixes the following failures:
catch_ex.exp: continuing to Program_Error exception
catch_ex.exp: continuing to failed assertion
catch_ex.exp: continuing to unhandled exception
catch_ex.exp: continuing to program completion
complete.exp: p <Exported_Capitalized>
complete.exp: p Exported_Capitalized
complete.exp: p exported_capitalized
mi_catch_ex.exp: catch Program_Error (unexpected output)
mi_catch_ex.exp: continue to exception catchpoint hit (unknown output after running)
mi_catch_ex.exp: continue to assert failure catchpoint hit (unknown output after running)
mi_catch_ex.exp: continue to unhandled exception catchpoint hit (unknown output after running)
mi_ex_cond.exp: catch C_E if i = 2 (unexpected output)
2017-11-16 08:02:33 +08:00
|
|
|
|
value *
|
Introduce OP_VAR_MSYM_VALUE
The previous patch left GDB with an inconsistency. While with normal
expression evaluation the "unknown return type" error shows the name
of the function that misses debug info:
(gdb) p getenv ("PATH")
'getenv' has unknown return type; cast the call to its declared return type
^^^^^^
which can by handy in more complicated expressions, "ptype" does not:
(gdb) ptype getenv ("PATH")
function has unknown return type; cast the call to its declared return type
^^^^^^^^
This commit is a step toward fixing it.
The problem is that while evaluating the expression above, we have no
reference to the minimal symbol where we could extract the name from.
This is because the resulting expression tree has no reference to the
minsym at all. During parsing, the type and address of the minsym are
extracted and an UNOP_MEMVAL / UNOP_MEMVAL_TLS operator is generated
(see write_exp_elt_msym). With "set debug expression", here's what
you see:
0 OP_FUNCALL Number of args: 0
3 UNOP_MEMVAL Type @0x565334a51930 (<text variable, no debug info>)
6 OP_LONG Type @0x565334a51c60 (__CORE_ADDR), value 140737345035648 (0x7ffff7751d80)
The "print" case finds the function name, because
call_function_by_hand looks up the function by address again.
However, for "ptype", we don't reach that code, because obviously we
don't really call the function.
Unlike minsym references, references to variables with debug info have
a pointer to the variable's symbol in the expression tree, with
OP_VAR_VALUE:
(gdb) ptype main()
...
0 OP_FUNCALL Number of args: 0
3 OP_VAR_VALUE Block @0x0, symbol @0x559bbbd9b358 (main(int, char**))
...
so I don't see why do minsyms need to be different. So to prepare for
fixing the missing function name issue, this commit adds a new
OP_VAR_MSYM_VALUE operator that mimics OP_VAR_VALUE, except that it's
for minsyms instead of debug symbols. For infcalls, we now get
expressions like these:
0 OP_FUNCALL Number of args: 0
3 OP_VAR_MSYM_VALUE Objfile @0x1e41bf0, msymbol @0x7fffe599b000 (getenv)
In the following patch, we'll make OP_FUNCALL extract the function
name from the symbol stored in OP_VAR_VALUE/OP_VAR_MSYM_VALUE.
OP_VAR_MSYM_VALUE will be used more in a later patch in the series
too.
gdb/ChangeLog:
2017-09-04 Pedro Alves <palves@redhat.com>
* ada-lang.c (resolve_subexp): Handle OP_VAR_MSYM_VALUE.
* ax-gdb.c (gen_msym_var_ref): New function.
(gen_expr): Handle OP_VAR_MSYM_VALUE.
* eval.c (evaluate_var_msym_value): New function.
* eval.c (evaluate_subexp_standard): Handle OP_VAR_MSYM_VALUE.
<OP_FUNCALL>: Extract function name from symbol/minsym and pass it
to call_function_by_hand.
* expprint.c (print_subexp_standard, dump_subexp_body_standard):
Handle OP_VAR_MSYM_VALUE.
(union exp_element) <msymbol>: New field.
* minsyms.h (struct type): Forward declare.
(find_minsym_type_and_address): Declare.
* parse.c (write_exp_elt_msym): New function.
(write_exp_msymbol): Delete, refactored as ...
(find_minsym_type_and_address): ... this new function.
(write_exp_msymbol): Reimplement using OP_VAR_MSYM_VALUE.
(operator_length_standard, operator_check_standard): Handle
OP_VAR_MSYM_VALUE.
* std-operator.def (OP_VAR_MSYM_VALUE): New.
2017-09-05 03:21:13 +08:00
|
|
|
|
evaluate_var_msym_value (enum noside noside,
|
|
|
|
|
struct objfile *objfile, minimal_symbol *msymbol)
|
|
|
|
|
{
|
Calling ifunc functions when target has no debug info but resolver has
After the previous patch, on Fedora 27 (glibc 2.26), if you try
calling strlen in the inferior, you now get:
(top-gdb) p strlen ("hello")
'__strlen_avx2' has unknown return type; cast the call to its declared return type
This is correct, because __strlen_avx2 is written in assembly.
We can improve on this though -- if the final ifunc resolved/target
function has no debug info, but the ifunc _resolver_ does have debug
info, we can try extracting the final function's type from the type
that the resolver returns. E.g.,:
typedef size_t (*strlen_t) (const char*);
size_t my_strlen (const char *) { /* some implementation */ }
strlen_t strlen_resolver (unsigned long hwcap) { return my_strlen; }
extern size_t strlen (const char *s);
__typeof (strlen) strlen __attribute__ ((ifunc ("strlen_resolver")));
In the strlen example above, the resolver returns strlen_t, which is a
typedef for pointer to a function that returns size_t. "strlen_t" is
the type of both the user-visible "strlen", and of the the target
function that implements it.
This patch teaches GDB to extract that type.
This is done for actual inferior function calls (in infcall.c), and
for ptype (in eval_call). By the time we get to either of these
places, we've already lost the original symbol/minsym, and only have
values and types to work with. Hence the changes to c-exp.y and
evaluate_var_msym_value, to ensure that we propagate the ifunc
minsymbol's info.
The change to make ifunc symbols have no/unknown return type exposes a
latent problem -- gdb.compile/compile-ifunc.exp calls a no-debug-info
function, but we did not warn about it. The test is fixed by this
commit too.
gdb/ChangeLog:
2018-04-26 Pedro Alves <palves@redhat.com>
* blockframe.c (find_gnu_ifunc_target_type): New function.
(find_function_type): New.
* eval.c (evaluate_var_msym_value): For GNU ifunc types, always
return a value with a memory address.
(eval_call): For calls to GNU ifunc functions, try to find the
type of the target function from the type that the resolver
returns.
* gdbtypes.c (objfile_type): Don't install a return type for ifunc
symbols.
* infcall.c (find_function_return_type): Delete.
(find_function_addr): Add 'function_type' parameter. For calls to
GNU ifunc functions, try to find the type of the target function
from the type that the resolver returns, and return it via
FUNCTION_TYPE.
(call_function_by_hand_dummy): Adjust to use the function type
returned by find_function_addr.
(find_function_addr): Add 'function_type' parameter and move
description here.
* symtab.h (find_function_type, find_gnu_ifunc_target_type): New
declarations.
gdb/testsuite/ChangeLog:
2018-04-26 Pedro Alves <palves@redhat.com>
* gdb.compile/compile-ifunc.exp: Also expect "function has unknown
return type" warnings.
2018-04-26 20:01:26 +08:00
|
|
|
|
CORE_ADDR address;
|
|
|
|
|
type *the_type = find_minsym_type_and_address (msymbol, objfile, &address);
|
|
|
|
|
|
2020-09-14 23:08:06 +08:00
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS && !the_type->is_gnu_ifunc ())
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (the_type, not_lval);
|
Introduce OP_VAR_MSYM_VALUE
The previous patch left GDB with an inconsistency. While with normal
expression evaluation the "unknown return type" error shows the name
of the function that misses debug info:
(gdb) p getenv ("PATH")
'getenv' has unknown return type; cast the call to its declared return type
^^^^^^
which can by handy in more complicated expressions, "ptype" does not:
(gdb) ptype getenv ("PATH")
function has unknown return type; cast the call to its declared return type
^^^^^^^^
This commit is a step toward fixing it.
The problem is that while evaluating the expression above, we have no
reference to the minimal symbol where we could extract the name from.
This is because the resulting expression tree has no reference to the
minsym at all. During parsing, the type and address of the minsym are
extracted and an UNOP_MEMVAL / UNOP_MEMVAL_TLS operator is generated
(see write_exp_elt_msym). With "set debug expression", here's what
you see:
0 OP_FUNCALL Number of args: 0
3 UNOP_MEMVAL Type @0x565334a51930 (<text variable, no debug info>)
6 OP_LONG Type @0x565334a51c60 (__CORE_ADDR), value 140737345035648 (0x7ffff7751d80)
The "print" case finds the function name, because
call_function_by_hand looks up the function by address again.
However, for "ptype", we don't reach that code, because obviously we
don't really call the function.
Unlike minsym references, references to variables with debug info have
a pointer to the variable's symbol in the expression tree, with
OP_VAR_VALUE:
(gdb) ptype main()
...
0 OP_FUNCALL Number of args: 0
3 OP_VAR_VALUE Block @0x0, symbol @0x559bbbd9b358 (main(int, char**))
...
so I don't see why do minsyms need to be different. So to prepare for
fixing the missing function name issue, this commit adds a new
OP_VAR_MSYM_VALUE operator that mimics OP_VAR_VALUE, except that it's
for minsyms instead of debug symbols. For infcalls, we now get
expressions like these:
0 OP_FUNCALL Number of args: 0
3 OP_VAR_MSYM_VALUE Objfile @0x1e41bf0, msymbol @0x7fffe599b000 (getenv)
In the following patch, we'll make OP_FUNCALL extract the function
name from the symbol stored in OP_VAR_VALUE/OP_VAR_MSYM_VALUE.
OP_VAR_MSYM_VALUE will be used more in a later patch in the series
too.
gdb/ChangeLog:
2017-09-04 Pedro Alves <palves@redhat.com>
* ada-lang.c (resolve_subexp): Handle OP_VAR_MSYM_VALUE.
* ax-gdb.c (gen_msym_var_ref): New function.
(gen_expr): Handle OP_VAR_MSYM_VALUE.
* eval.c (evaluate_var_msym_value): New function.
* eval.c (evaluate_subexp_standard): Handle OP_VAR_MSYM_VALUE.
<OP_FUNCALL>: Extract function name from symbol/minsym and pass it
to call_function_by_hand.
* expprint.c (print_subexp_standard, dump_subexp_body_standard):
Handle OP_VAR_MSYM_VALUE.
(union exp_element) <msymbol>: New field.
* minsyms.h (struct type): Forward declare.
(find_minsym_type_and_address): Declare.
* parse.c (write_exp_elt_msym): New function.
(write_exp_msymbol): Delete, refactored as ...
(find_minsym_type_and_address): ... this new function.
(write_exp_msymbol): Reimplement using OP_VAR_MSYM_VALUE.
(operator_length_standard, operator_check_standard): Handle
OP_VAR_MSYM_VALUE.
* std-operator.def (OP_VAR_MSYM_VALUE): New.
2017-09-05 03:21:13 +08:00
|
|
|
|
else
|
Calling ifunc functions when target has no debug info but resolver has
After the previous patch, on Fedora 27 (glibc 2.26), if you try
calling strlen in the inferior, you now get:
(top-gdb) p strlen ("hello")
'__strlen_avx2' has unknown return type; cast the call to its declared return type
This is correct, because __strlen_avx2 is written in assembly.
We can improve on this though -- if the final ifunc resolved/target
function has no debug info, but the ifunc _resolver_ does have debug
info, we can try extracting the final function's type from the type
that the resolver returns. E.g.,:
typedef size_t (*strlen_t) (const char*);
size_t my_strlen (const char *) { /* some implementation */ }
strlen_t strlen_resolver (unsigned long hwcap) { return my_strlen; }
extern size_t strlen (const char *s);
__typeof (strlen) strlen __attribute__ ((ifunc ("strlen_resolver")));
In the strlen example above, the resolver returns strlen_t, which is a
typedef for pointer to a function that returns size_t. "strlen_t" is
the type of both the user-visible "strlen", and of the the target
function that implements it.
This patch teaches GDB to extract that type.
This is done for actual inferior function calls (in infcall.c), and
for ptype (in eval_call). By the time we get to either of these
places, we've already lost the original symbol/minsym, and only have
values and types to work with. Hence the changes to c-exp.y and
evaluate_var_msym_value, to ensure that we propagate the ifunc
minsymbol's info.
The change to make ifunc symbols have no/unknown return type exposes a
latent problem -- gdb.compile/compile-ifunc.exp calls a no-debug-info
function, but we did not warn about it. The test is fixed by this
commit too.
gdb/ChangeLog:
2018-04-26 Pedro Alves <palves@redhat.com>
* blockframe.c (find_gnu_ifunc_target_type): New function.
(find_function_type): New.
* eval.c (evaluate_var_msym_value): For GNU ifunc types, always
return a value with a memory address.
(eval_call): For calls to GNU ifunc functions, try to find the
type of the target function from the type that the resolver
returns.
* gdbtypes.c (objfile_type): Don't install a return type for ifunc
symbols.
* infcall.c (find_function_return_type): Delete.
(find_function_addr): Add 'function_type' parameter. For calls to
GNU ifunc functions, try to find the type of the target function
from the type that the resolver returns, and return it via
FUNCTION_TYPE.
(call_function_by_hand_dummy): Adjust to use the function type
returned by find_function_addr.
(find_function_addr): Add 'function_type' parameter and move
description here.
* symtab.h (find_function_type, find_gnu_ifunc_target_type): New
declarations.
gdb/testsuite/ChangeLog:
2018-04-26 Pedro Alves <palves@redhat.com>
* gdb.compile/compile-ifunc.exp: Also expect "function has unknown
return type" warnings.
2018-04-26 20:01:26 +08:00
|
|
|
|
return value_at_lazy (the_type, address);
|
Introduce OP_VAR_MSYM_VALUE
The previous patch left GDB with an inconsistency. While with normal
expression evaluation the "unknown return type" error shows the name
of the function that misses debug info:
(gdb) p getenv ("PATH")
'getenv' has unknown return type; cast the call to its declared return type
^^^^^^
which can by handy in more complicated expressions, "ptype" does not:
(gdb) ptype getenv ("PATH")
function has unknown return type; cast the call to its declared return type
^^^^^^^^
This commit is a step toward fixing it.
The problem is that while evaluating the expression above, we have no
reference to the minimal symbol where we could extract the name from.
This is because the resulting expression tree has no reference to the
minsym at all. During parsing, the type and address of the minsym are
extracted and an UNOP_MEMVAL / UNOP_MEMVAL_TLS operator is generated
(see write_exp_elt_msym). With "set debug expression", here's what
you see:
0 OP_FUNCALL Number of args: 0
3 UNOP_MEMVAL Type @0x565334a51930 (<text variable, no debug info>)
6 OP_LONG Type @0x565334a51c60 (__CORE_ADDR), value 140737345035648 (0x7ffff7751d80)
The "print" case finds the function name, because
call_function_by_hand looks up the function by address again.
However, for "ptype", we don't reach that code, because obviously we
don't really call the function.
Unlike minsym references, references to variables with debug info have
a pointer to the variable's symbol in the expression tree, with
OP_VAR_VALUE:
(gdb) ptype main()
...
0 OP_FUNCALL Number of args: 0
3 OP_VAR_VALUE Block @0x0, symbol @0x559bbbd9b358 (main(int, char**))
...
so I don't see why do minsyms need to be different. So to prepare for
fixing the missing function name issue, this commit adds a new
OP_VAR_MSYM_VALUE operator that mimics OP_VAR_VALUE, except that it's
for minsyms instead of debug symbols. For infcalls, we now get
expressions like these:
0 OP_FUNCALL Number of args: 0
3 OP_VAR_MSYM_VALUE Objfile @0x1e41bf0, msymbol @0x7fffe599b000 (getenv)
In the following patch, we'll make OP_FUNCALL extract the function
name from the symbol stored in OP_VAR_VALUE/OP_VAR_MSYM_VALUE.
OP_VAR_MSYM_VALUE will be used more in a later patch in the series
too.
gdb/ChangeLog:
2017-09-04 Pedro Alves <palves@redhat.com>
* ada-lang.c (resolve_subexp): Handle OP_VAR_MSYM_VALUE.
* ax-gdb.c (gen_msym_var_ref): New function.
(gen_expr): Handle OP_VAR_MSYM_VALUE.
* eval.c (evaluate_var_msym_value): New function.
* eval.c (evaluate_subexp_standard): Handle OP_VAR_MSYM_VALUE.
<OP_FUNCALL>: Extract function name from symbol/minsym and pass it
to call_function_by_hand.
* expprint.c (print_subexp_standard, dump_subexp_body_standard):
Handle OP_VAR_MSYM_VALUE.
(union exp_element) <msymbol>: New field.
* minsyms.h (struct type): Forward declare.
(find_minsym_type_and_address): Declare.
* parse.c (write_exp_elt_msym): New function.
(write_exp_msymbol): Delete, refactored as ...
(find_minsym_type_and_address): ... this new function.
(write_exp_msymbol): Reimplement using OP_VAR_MSYM_VALUE.
(operator_length_standard, operator_check_standard): Handle
OP_VAR_MSYM_VALUE.
* std-operator.def (OP_VAR_MSYM_VALUE): New.
2017-09-05 03:21:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-07 23:27:16 +08:00
|
|
|
|
/* See expression.h. */
|
2017-09-05 19:13:57 +08:00
|
|
|
|
|
2020-05-07 23:27:16 +08:00
|
|
|
|
value *
|
|
|
|
|
evaluate_subexp_do_call (expression *exp, enum noside noside,
|
2020-12-16 08:53:34 +08:00
|
|
|
|
value *callee,
|
|
|
|
|
gdb::array_view<value *> argvec,
|
2020-05-07 23:27:16 +08:00
|
|
|
|
const char *function_name,
|
|
|
|
|
type *default_return_type)
|
2017-09-05 19:13:57 +08:00
|
|
|
|
{
|
2020-12-16 08:53:34 +08:00
|
|
|
|
if (callee == NULL)
|
2017-09-05 19:13:57 +08:00
|
|
|
|
error (_("Cannot evaluate function -- may be inlined"));
|
2024-06-12 21:24:02 +08:00
|
|
|
|
|
|
|
|
|
type *ftype = callee->type ();
|
|
|
|
|
|
|
|
|
|
/* If the callee is a struct, there might be a user-defined function call
|
|
|
|
|
operator that should be used instead. */
|
|
|
|
|
std::vector<value *> vals;
|
|
|
|
|
if (overload_resolution
|
|
|
|
|
&& exp->language_defn->la_language == language_cplus
|
|
|
|
|
&& check_typedef (ftype)->code () == TYPE_CODE_STRUCT)
|
|
|
|
|
{
|
|
|
|
|
/* Include space for the `this' pointer at the start. */
|
|
|
|
|
vals.resize (argvec.size () + 1);
|
|
|
|
|
|
|
|
|
|
vals[0] = value_addr (callee);
|
|
|
|
|
for (int i = 0; i < argvec.size (); ++i)
|
|
|
|
|
vals[i + 1] = argvec[i];
|
|
|
|
|
|
|
|
|
|
int static_memfuncp;
|
|
|
|
|
find_overload_match (vals, "operator()", METHOD, &vals[0], nullptr,
|
|
|
|
|
&callee, nullptr, &static_memfuncp, 0, noside);
|
|
|
|
|
if (!static_memfuncp)
|
|
|
|
|
argvec = vals;
|
|
|
|
|
|
|
|
|
|
ftype = callee->type ();
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-05 19:13:57 +08:00
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
{
|
|
|
|
|
/* If the return type doesn't look like a function type,
|
|
|
|
|
call an error. This can happen if somebody tries to turn
|
|
|
|
|
a variable into a function call. */
|
|
|
|
|
|
2020-05-15 01:46:38 +08:00
|
|
|
|
if (ftype->code () == TYPE_CODE_INTERNAL_FUNCTION)
|
2017-09-05 19:13:57 +08:00
|
|
|
|
{
|
[gdb/exp] Allow internal function to indicate return type
Currently an internal function handler has this prototype:
...
struct value *handler (struct gdbarch *gdbarch,
const struct language_defn *language,
void *cookie, int argc, struct value **argv);
...
Also allow an internal function with a handler with an additional
"enum noside noside" parameter:
...
struct value *handler (struct gdbarch *gdbarch,
const struct language_defn *language, void *cookie,
int argc, struct value **argv, enum noside noside);
...
In case such a handler is called with noside == EVAL_AVOID_SIDE_EFFECTS, it's
expected to return some value with the correct return type.
At least, provided it can do so without side effects, otherwise it should
throw an error.
No functional changes.
Tested on x86_64-linux and aarch64-linux.
Reviewed-By: Keith Seitz <keiths@redhat.com>
2024-07-24 22:32:35 +08:00
|
|
|
|
/* The call to call_internal_function below handles noside. */
|
2017-09-05 19:13:57 +08:00
|
|
|
|
}
|
2020-05-15 01:46:38 +08:00
|
|
|
|
else if (ftype->code () == TYPE_CODE_XMETHOD)
|
2017-09-05 19:13:57 +08:00
|
|
|
|
{
|
2023-02-01 11:59:39 +08:00
|
|
|
|
type *return_type = callee->result_type_of_xmethod (argvec);
|
2017-09-05 19:13:57 +08:00
|
|
|
|
|
|
|
|
|
if (return_type == NULL)
|
|
|
|
|
error (_("Xmethod is missing return type."));
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (return_type, not_lval);
|
2017-09-05 19:13:57 +08:00
|
|
|
|
}
|
2020-05-15 01:46:38 +08:00
|
|
|
|
else if (ftype->code () == TYPE_CODE_FUNC
|
|
|
|
|
|| ftype->code () == TYPE_CODE_METHOD)
|
2017-09-05 19:13:57 +08:00
|
|
|
|
{
|
2020-09-14 23:08:06 +08:00
|
|
|
|
if (ftype->is_gnu_ifunc ())
|
Calling ifunc functions when target has no debug info but resolver has
After the previous patch, on Fedora 27 (glibc 2.26), if you try
calling strlen in the inferior, you now get:
(top-gdb) p strlen ("hello")
'__strlen_avx2' has unknown return type; cast the call to its declared return type
This is correct, because __strlen_avx2 is written in assembly.
We can improve on this though -- if the final ifunc resolved/target
function has no debug info, but the ifunc _resolver_ does have debug
info, we can try extracting the final function's type from the type
that the resolver returns. E.g.,:
typedef size_t (*strlen_t) (const char*);
size_t my_strlen (const char *) { /* some implementation */ }
strlen_t strlen_resolver (unsigned long hwcap) { return my_strlen; }
extern size_t strlen (const char *s);
__typeof (strlen) strlen __attribute__ ((ifunc ("strlen_resolver")));
In the strlen example above, the resolver returns strlen_t, which is a
typedef for pointer to a function that returns size_t. "strlen_t" is
the type of both the user-visible "strlen", and of the the target
function that implements it.
This patch teaches GDB to extract that type.
This is done for actual inferior function calls (in infcall.c), and
for ptype (in eval_call). By the time we get to either of these
places, we've already lost the original symbol/minsym, and only have
values and types to work with. Hence the changes to c-exp.y and
evaluate_var_msym_value, to ensure that we propagate the ifunc
minsymbol's info.
The change to make ifunc symbols have no/unknown return type exposes a
latent problem -- gdb.compile/compile-ifunc.exp calls a no-debug-info
function, but we did not warn about it. The test is fixed by this
commit too.
gdb/ChangeLog:
2018-04-26 Pedro Alves <palves@redhat.com>
* blockframe.c (find_gnu_ifunc_target_type): New function.
(find_function_type): New.
* eval.c (evaluate_var_msym_value): For GNU ifunc types, always
return a value with a memory address.
(eval_call): For calls to GNU ifunc functions, try to find the
type of the target function from the type that the resolver
returns.
* gdbtypes.c (objfile_type): Don't install a return type for ifunc
symbols.
* infcall.c (find_function_return_type): Delete.
(find_function_addr): Add 'function_type' parameter. For calls to
GNU ifunc functions, try to find the type of the target function
from the type that the resolver returns, and return it via
FUNCTION_TYPE.
(call_function_by_hand_dummy): Adjust to use the function type
returned by find_function_addr.
(find_function_addr): Add 'function_type' parameter and move
description here.
* symtab.h (find_function_type, find_gnu_ifunc_target_type): New
declarations.
gdb/testsuite/ChangeLog:
2018-04-26 Pedro Alves <palves@redhat.com>
* gdb.compile/compile-ifunc.exp: Also expect "function has unknown
return type" warnings.
2018-04-26 20:01:26 +08:00
|
|
|
|
{
|
2023-02-01 03:27:30 +08:00
|
|
|
|
CORE_ADDR address = callee->address ();
|
Calling ifunc functions when target has no debug info but resolver has
After the previous patch, on Fedora 27 (glibc 2.26), if you try
calling strlen in the inferior, you now get:
(top-gdb) p strlen ("hello")
'__strlen_avx2' has unknown return type; cast the call to its declared return type
This is correct, because __strlen_avx2 is written in assembly.
We can improve on this though -- if the final ifunc resolved/target
function has no debug info, but the ifunc _resolver_ does have debug
info, we can try extracting the final function's type from the type
that the resolver returns. E.g.,:
typedef size_t (*strlen_t) (const char*);
size_t my_strlen (const char *) { /* some implementation */ }
strlen_t strlen_resolver (unsigned long hwcap) { return my_strlen; }
extern size_t strlen (const char *s);
__typeof (strlen) strlen __attribute__ ((ifunc ("strlen_resolver")));
In the strlen example above, the resolver returns strlen_t, which is a
typedef for pointer to a function that returns size_t. "strlen_t" is
the type of both the user-visible "strlen", and of the the target
function that implements it.
This patch teaches GDB to extract that type.
This is done for actual inferior function calls (in infcall.c), and
for ptype (in eval_call). By the time we get to either of these
places, we've already lost the original symbol/minsym, and only have
values and types to work with. Hence the changes to c-exp.y and
evaluate_var_msym_value, to ensure that we propagate the ifunc
minsymbol's info.
The change to make ifunc symbols have no/unknown return type exposes a
latent problem -- gdb.compile/compile-ifunc.exp calls a no-debug-info
function, but we did not warn about it. The test is fixed by this
commit too.
gdb/ChangeLog:
2018-04-26 Pedro Alves <palves@redhat.com>
* blockframe.c (find_gnu_ifunc_target_type): New function.
(find_function_type): New.
* eval.c (evaluate_var_msym_value): For GNU ifunc types, always
return a value with a memory address.
(eval_call): For calls to GNU ifunc functions, try to find the
type of the target function from the type that the resolver
returns.
* gdbtypes.c (objfile_type): Don't install a return type for ifunc
symbols.
* infcall.c (find_function_return_type): Delete.
(find_function_addr): Add 'function_type' parameter. For calls to
GNU ifunc functions, try to find the type of the target function
from the type that the resolver returns, and return it via
FUNCTION_TYPE.
(call_function_by_hand_dummy): Adjust to use the function type
returned by find_function_addr.
(find_function_addr): Add 'function_type' parameter and move
description here.
* symtab.h (find_function_type, find_gnu_ifunc_target_type): New
declarations.
gdb/testsuite/ChangeLog:
2018-04-26 Pedro Alves <palves@redhat.com>
* gdb.compile/compile-ifunc.exp: Also expect "function has unknown
return type" warnings.
2018-04-26 20:01:26 +08:00
|
|
|
|
type *resolved_type = find_gnu_ifunc_target_type (address);
|
|
|
|
|
|
|
|
|
|
if (resolved_type != NULL)
|
|
|
|
|
ftype = resolved_type;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-31 10:43:54 +08:00
|
|
|
|
type *return_type = ftype->target_type ();
|
2017-09-05 19:13:57 +08:00
|
|
|
|
|
|
|
|
|
if (return_type == NULL)
|
|
|
|
|
return_type = default_return_type;
|
|
|
|
|
|
|
|
|
|
if (return_type == NULL)
|
|
|
|
|
error_call_unknown_return_type (function_name);
|
|
|
|
|
|
2023-02-01 04:25:17 +08:00
|
|
|
|
return value::allocate (return_type);
|
2017-09-05 19:13:57 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
error (_("Expression of type other than "
|
|
|
|
|
"\"Function returning ...\" used as function"));
|
|
|
|
|
}
|
2023-01-31 22:52:09 +08:00
|
|
|
|
switch (callee->type ()->code ())
|
2017-09-05 19:13:57 +08:00
|
|
|
|
{
|
|
|
|
|
case TYPE_CODE_INTERNAL_FUNCTION:
|
|
|
|
|
return call_internal_function (exp->gdbarch, exp->language_defn,
|
[gdb/exp] Allow internal function to indicate return type
Currently an internal function handler has this prototype:
...
struct value *handler (struct gdbarch *gdbarch,
const struct language_defn *language,
void *cookie, int argc, struct value **argv);
...
Also allow an internal function with a handler with an additional
"enum noside noside" parameter:
...
struct value *handler (struct gdbarch *gdbarch,
const struct language_defn *language, void *cookie,
int argc, struct value **argv, enum noside noside);
...
In case such a handler is called with noside == EVAL_AVOID_SIDE_EFFECTS, it's
expected to return some value with the correct return type.
At least, provided it can do so without side effects, otherwise it should
throw an error.
No functional changes.
Tested on x86_64-linux and aarch64-linux.
Reviewed-By: Keith Seitz <keiths@redhat.com>
2024-07-24 22:32:35 +08:00
|
|
|
|
callee, argvec.size (), argvec.data (),
|
|
|
|
|
noside);
|
2017-09-05 19:13:57 +08:00
|
|
|
|
case TYPE_CODE_XMETHOD:
|
2023-02-01 11:59:39 +08:00
|
|
|
|
return callee->call_xmethod (argvec);
|
2017-09-05 19:13:57 +08:00
|
|
|
|
default:
|
2020-12-16 08:53:34 +08:00
|
|
|
|
return call_function_by_hand (callee, default_return_type, argvec);
|
2017-09-05 19:13:57 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
namespace expr
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
operation::evaluate_funcall (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside,
|
|
|
|
|
const char *function_name,
|
|
|
|
|
const std::vector<operation_up> &args)
|
|
|
|
|
{
|
|
|
|
|
std::vector<value *> vals (args.size ());
|
|
|
|
|
|
|
|
|
|
value *callee = evaluate_with_coercion (exp, noside);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = callee->type ();
|
2021-03-09 22:36:26 +08:00
|
|
|
|
if (type->code () == TYPE_CODE_PTR)
|
2022-07-31 10:43:54 +08:00
|
|
|
|
type = type->target_type ();
|
2024-06-12 21:24:02 +08:00
|
|
|
|
/* If type is a struct, num_fields would refer to the number of
|
|
|
|
|
members in the type, not the number of arguments. */
|
|
|
|
|
bool type_has_arguments
|
|
|
|
|
= type->code () == TYPE_CODE_FUNC || type->code () == TYPE_CODE_METHOD;
|
2021-03-08 22:27:57 +08:00
|
|
|
|
for (int i = 0; i < args.size (); ++i)
|
2021-03-09 22:36:26 +08:00
|
|
|
|
{
|
2024-06-12 21:24:02 +08:00
|
|
|
|
if (type_has_arguments && i < type->num_fields ())
|
2021-03-09 22:36:26 +08:00
|
|
|
|
vals[i] = args[i]->evaluate (type->field (i).type (), exp, noside);
|
|
|
|
|
else
|
|
|
|
|
vals[i] = args[i]->evaluate_with_coercion (exp, noside);
|
|
|
|
|
}
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
return evaluate_subexp_do_call (exp, noside, callee, vals,
|
|
|
|
|
function_name, expect_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
var_value_operation::evaluate_funcall (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside,
|
|
|
|
|
const std::vector<operation_up> &args)
|
|
|
|
|
{
|
|
|
|
|
if (!overload_resolution
|
|
|
|
|
|| exp->language_defn->la_language != language_cplus)
|
|
|
|
|
return operation::evaluate_funcall (expect_type, exp, noside, args);
|
|
|
|
|
|
|
|
|
|
std::vector<value *> argvec (args.size ());
|
|
|
|
|
for (int i = 0; i < args.size (); ++i)
|
|
|
|
|
argvec[i] = args[i]->evaluate_with_coercion (exp, noside);
|
|
|
|
|
|
|
|
|
|
struct symbol *symp;
|
|
|
|
|
find_overload_match (argvec, NULL, NON_METHOD,
|
2021-04-16 00:05:00 +08:00
|
|
|
|
NULL, std::get<0> (m_storage).symbol,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
NULL, &symp, NULL, 0, noside);
|
|
|
|
|
|
2022-01-28 11:16:41 +08:00
|
|
|
|
if (symp->type ()->code () == TYPE_CODE_ERROR)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
error_unknown_type (symp->print_name ());
|
2021-04-16 00:05:00 +08:00
|
|
|
|
value *callee = evaluate_var_value (noside, std::get<0> (m_storage).block,
|
|
|
|
|
symp);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
return evaluate_subexp_do_call (exp, noside, callee, argvec,
|
|
|
|
|
nullptr, expect_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
scope_operation::evaluate_funcall (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside,
|
|
|
|
|
const std::vector<operation_up> &args)
|
|
|
|
|
{
|
|
|
|
|
if (!overload_resolution
|
|
|
|
|
|| exp->language_defn->la_language != language_cplus)
|
|
|
|
|
return operation::evaluate_funcall (expect_type, exp, noside, args);
|
|
|
|
|
|
|
|
|
|
/* Unpack it locally so we can properly handle overload
|
|
|
|
|
resolution. */
|
|
|
|
|
const std::string &name = std::get<1> (m_storage);
|
|
|
|
|
struct type *type = std::get<0> (m_storage);
|
|
|
|
|
|
|
|
|
|
symbol *function = NULL;
|
|
|
|
|
const char *function_name = NULL;
|
|
|
|
|
std::vector<value *> argvec (1 + args.size ());
|
|
|
|
|
if (type->code () == TYPE_CODE_NAMESPACE)
|
|
|
|
|
{
|
|
|
|
|
function = cp_lookup_symbol_namespace (type->name (),
|
|
|
|
|
name.c_str (),
|
|
|
|
|
get_selected_block (0),
|
2023-03-31 13:00:26 +08:00
|
|
|
|
SEARCH_FUNCTION_DOMAIN).symbol;
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (function == NULL)
|
|
|
|
|
error (_("No symbol \"%s\" in namespace \"%s\"."),
|
|
|
|
|
name.c_str (), type->name ());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gdb_assert (type->code () == TYPE_CODE_STRUCT
|
|
|
|
|
|| type->code () == TYPE_CODE_UNION);
|
|
|
|
|
function_name = name.c_str ();
|
|
|
|
|
|
|
|
|
|
/* We need a properly typed value for method lookup. */
|
2023-02-01 04:41:35 +08:00
|
|
|
|
argvec[0] = value::zero (type, lval_memory);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < args.size (); ++i)
|
|
|
|
|
argvec[i + 1] = args[i]->evaluate_with_coercion (exp, noside);
|
|
|
|
|
gdb::array_view<value *> arg_view = argvec;
|
|
|
|
|
|
|
|
|
|
value *callee = nullptr;
|
|
|
|
|
if (function_name != nullptr)
|
|
|
|
|
{
|
|
|
|
|
int static_memfuncp;
|
|
|
|
|
|
|
|
|
|
find_overload_match (arg_view, function_name, METHOD,
|
|
|
|
|
&argvec[0], nullptr, &callee, nullptr,
|
|
|
|
|
&static_memfuncp, 0, noside);
|
|
|
|
|
if (!static_memfuncp)
|
|
|
|
|
{
|
|
|
|
|
/* For the time being, we don't handle this. */
|
|
|
|
|
error (_("Call to overloaded function %s requires "
|
|
|
|
|
"`this' pointer"),
|
|
|
|
|
function_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arg_view = arg_view.slice (1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
symbol *symp;
|
|
|
|
|
arg_view = arg_view.slice (1);
|
|
|
|
|
find_overload_match (arg_view, nullptr,
|
|
|
|
|
NON_METHOD, nullptr, function,
|
|
|
|
|
nullptr, &symp, nullptr, 1, noside);
|
|
|
|
|
callee = value_of_variable (symp, get_selected_block (0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return evaluate_subexp_do_call (exp, noside, callee, arg_view,
|
|
|
|
|
nullptr, expect_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
structop_member_base::evaluate_funcall (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside,
|
|
|
|
|
const std::vector<operation_up> &args)
|
|
|
|
|
{
|
|
|
|
|
/* First, evaluate the structure into lhs. */
|
|
|
|
|
value *lhs;
|
|
|
|
|
if (opcode () == STRUCTOP_MEMBER)
|
|
|
|
|
lhs = std::get<0> (m_storage)->evaluate_for_address (exp, noside);
|
|
|
|
|
else
|
|
|
|
|
lhs = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
|
|
|
|
|
std::vector<value *> vals (args.size () + 1);
|
|
|
|
|
gdb::array_view<value *> val_view = vals;
|
|
|
|
|
/* If the function is a virtual function, then the aggregate
|
|
|
|
|
value (providing the structure) plays its part by providing
|
|
|
|
|
the vtable. Otherwise, it is just along for the ride: call
|
|
|
|
|
the function directly. */
|
|
|
|
|
value *rhs = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
value *callee;
|
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
type *a1_type = check_typedef (rhs->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (a1_type->code () == TYPE_CODE_METHODPTR)
|
|
|
|
|
{
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2023-02-01 04:41:35 +08:00
|
|
|
|
callee = value::zero (a1_type->target_type (), not_lval);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
else
|
|
|
|
|
callee = cplus_method_ptr_to_value (&lhs, rhs);
|
|
|
|
|
|
|
|
|
|
vals[0] = lhs;
|
|
|
|
|
}
|
|
|
|
|
else if (a1_type->code () == TYPE_CODE_MEMBERPTR)
|
|
|
|
|
{
|
|
|
|
|
struct type *type_ptr
|
|
|
|
|
= lookup_pointer_type (TYPE_SELF_TYPE (a1_type));
|
|
|
|
|
struct type *target_type_ptr
|
2022-07-31 10:43:54 +08:00
|
|
|
|
= lookup_pointer_type (a1_type->target_type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
/* Now, convert this value to an address. */
|
|
|
|
|
lhs = value_cast (type_ptr, lhs);
|
|
|
|
|
|
|
|
|
|
long mem_offset = value_as_long (rhs);
|
|
|
|
|
|
|
|
|
|
callee = value_from_pointer (target_type_ptr,
|
|
|
|
|
value_as_long (lhs) + mem_offset);
|
|
|
|
|
callee = value_ind (callee);
|
|
|
|
|
|
|
|
|
|
val_view = val_view.slice (1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
error (_("Non-pointer-to-member value used in pointer-to-member "
|
|
|
|
|
"construct"));
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < args.size (); ++i)
|
|
|
|
|
vals[i + 1] = args[i]->evaluate_with_coercion (exp, noside);
|
|
|
|
|
|
|
|
|
|
return evaluate_subexp_do_call (exp, noside, callee, val_view,
|
|
|
|
|
nullptr, expect_type);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
structop_base_operation::evaluate_funcall
|
|
|
|
|
(struct type *expect_type, struct expression *exp, enum noside noside,
|
|
|
|
|
const std::vector<operation_up> &args)
|
|
|
|
|
{
|
gdb: replace NULL terminated array with array_view
After the previous commit, this commit updates the value_struct_elt
function to take an array_view rather than a NULL terminated array of
values.
The requirement for a NULL terminated array of values actually stems
from typecmp, so the change from an array to array_view needs to be
propagated through to this function.
While making this change I noticed that this fixes another bug, in
value_x_binop and value_x_unop GDB creates an array of values which
doesn't have a NULL at the end. An array_view of this array is passed
to value_user_defined_op, which then unpacks the array_view and passed
the raw array to value_struct_elt, but only if the language is not
C++.
As value_x_binop and value_x_unop can only request member functions
with the names of C++ operators, then most of the time, assuming the
inferior is not a C++ program, then GDB will not find a matching
member function with the call to value_struct_elt, and so typecmp will
never be called, and so, GDB will avoid undefined behaviour.
However, it is worth remembering that, when GDB's language is set to
"auto", the current language is selected based on the language of the
current compilation unit. As C++ programs usually link against libc,
which is written in C, then, if the inferior is stopped in libc GDB
will set the language to C. And so, it is possible that we will end
up using value_struct_elt to try and lookup, and match, a C++
operator. If this occurs then GDB will experience undefined
behaviour.
I have extended the test added in the previous commit to also cover
this case.
Finally, this commit changes the API from passing around a pointer to
an array to passing around a pointer to an array_view. The reason for
this is that we need to be able to distinguish between the cases where
we call value_struct_elt with no arguments, i.e. we are looking up a
struct member, but we either don't have the arguments we want to pass
yet, or we don't expect there to be any need for GDB to use the
argument types to resolve any overloading; and the second case where
we call value_struct_elt looking for a function that takes no
arguments, that is, the argument list is empty.
NOTE: While writing this I realise that if we pass an array_view at
all then it will always have at least one item in it, the `this'
pointer for the object we are planning to call the method on. So we
could, I guess, pass an empty array_view to indicate the case where we
don't know anything about the arguments, and when the array_view is
length 1 or more, it means we do have the arguments. However, though
we could do this, I don't think this would be better, the length 0 vs
length 1 difference seems a little too subtle, I think that there's a
better solution...
I think a better solution would be to wrap the array_view in a
gdb::optional, this would make the whole, do we have an array view or
not question explicit.
I haven't done this as part of this commit as making that change is
much more extensive, every user of value_struct_elt will need to be
updated, and as this commit already contains a bug fix, I wanted to
keep the large refactoring in a separate commit, so, check out the
next commit for the use of gdb::optional.
gdb/ChangeLog:
PR gdb/27994
* eval.c (structop_base_operation::evaluate_funcall): Pass
array_view instead of array to value_struct_elt.
* valarith.c (value_user_defined_op): Likewise.
* valops.c (typecmp): Change parameter type from array pointer to
array_view. Update header comment, and update body accordingly.
(search_struct_method): Likewise.
(value_struct_elt): Likewise.
* value.h (value_struct_elt): Update declaration.
gdb/testsuite/ChangeLog:
PR gdb/27994
* gdb.cp/method-call-in-c.cc (struct foo_type): Add operator+=,
change initial value of var member variable.
(main): Make use of foo_type's operator+=.
* gdb.cp/method-call-in-c.exp: Test use of operator+=.
2021-06-22 17:17:53 +08:00
|
|
|
|
/* Allocate space for the function call arguments, Including space for a
|
|
|
|
|
`this' pointer at the start. */
|
|
|
|
|
std::vector<value *> vals (args.size () + 1);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* First, evaluate the structure into vals[0]. */
|
|
|
|
|
enum exp_opcode op = opcode ();
|
|
|
|
|
if (op == STRUCTOP_STRUCT)
|
|
|
|
|
{
|
|
|
|
|
/* If v is a variable in a register, and the user types
|
|
|
|
|
v.method (), this will produce an error, because v has no
|
|
|
|
|
address.
|
|
|
|
|
|
|
|
|
|
A possible way around this would be to allocate a copy of
|
|
|
|
|
the variable on the stack, copy in the contents, call the
|
|
|
|
|
function, and copy out the contents. I.e. convert this
|
|
|
|
|
from call by reference to call by copy-return (or
|
|
|
|
|
whatever it's called). However, this does not work
|
|
|
|
|
because it is not the same: the method being called could
|
|
|
|
|
stash a copy of the address, and then future uses through
|
|
|
|
|
that address (after the method returns) would be expected
|
|
|
|
|
to use the variable itself, not some copy of it. */
|
|
|
|
|
vals[0] = std::get<0> (m_storage)->evaluate_for_address (exp, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
vals[0] = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
/* Check to see if the operator '->' has been overloaded.
|
|
|
|
|
If the operator has been overloaded replace vals[0] with the
|
|
|
|
|
value returned by the custom operator and continue
|
|
|
|
|
evaluation. */
|
|
|
|
|
while (unop_user_defined_p (op, vals[0]))
|
|
|
|
|
{
|
|
|
|
|
struct value *value = nullptr;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
value = value_x_unop (vals[0], op, noside);
|
|
|
|
|
}
|
|
|
|
|
catch (const gdb_exception_error &except)
|
|
|
|
|
{
|
|
|
|
|
if (except.error == NOT_FOUND_ERROR)
|
|
|
|
|
break;
|
|
|
|
|
else
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vals[0] = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
gdb: replace NULL terminated array with array_view
After the previous commit, this commit updates the value_struct_elt
function to take an array_view rather than a NULL terminated array of
values.
The requirement for a NULL terminated array of values actually stems
from typecmp, so the change from an array to array_view needs to be
propagated through to this function.
While making this change I noticed that this fixes another bug, in
value_x_binop and value_x_unop GDB creates an array of values which
doesn't have a NULL at the end. An array_view of this array is passed
to value_user_defined_op, which then unpacks the array_view and passed
the raw array to value_struct_elt, but only if the language is not
C++.
As value_x_binop and value_x_unop can only request member functions
with the names of C++ operators, then most of the time, assuming the
inferior is not a C++ program, then GDB will not find a matching
member function with the call to value_struct_elt, and so typecmp will
never be called, and so, GDB will avoid undefined behaviour.
However, it is worth remembering that, when GDB's language is set to
"auto", the current language is selected based on the language of the
current compilation unit. As C++ programs usually link against libc,
which is written in C, then, if the inferior is stopped in libc GDB
will set the language to C. And so, it is possible that we will end
up using value_struct_elt to try and lookup, and match, a C++
operator. If this occurs then GDB will experience undefined
behaviour.
I have extended the test added in the previous commit to also cover
this case.
Finally, this commit changes the API from passing around a pointer to
an array to passing around a pointer to an array_view. The reason for
this is that we need to be able to distinguish between the cases where
we call value_struct_elt with no arguments, i.e. we are looking up a
struct member, but we either don't have the arguments we want to pass
yet, or we don't expect there to be any need for GDB to use the
argument types to resolve any overloading; and the second case where
we call value_struct_elt looking for a function that takes no
arguments, that is, the argument list is empty.
NOTE: While writing this I realise that if we pass an array_view at
all then it will always have at least one item in it, the `this'
pointer for the object we are planning to call the method on. So we
could, I guess, pass an empty array_view to indicate the case where we
don't know anything about the arguments, and when the array_view is
length 1 or more, it means we do have the arguments. However, though
we could do this, I don't think this would be better, the length 0 vs
length 1 difference seems a little too subtle, I think that there's a
better solution...
I think a better solution would be to wrap the array_view in a
gdb::optional, this would make the whole, do we have an array view or
not question explicit.
I haven't done this as part of this commit as making that change is
much more extensive, every user of value_struct_elt will need to be
updated, and as this commit already contains a bug fix, I wanted to
keep the large refactoring in a separate commit, so, check out the
next commit for the use of gdb::optional.
gdb/ChangeLog:
PR gdb/27994
* eval.c (structop_base_operation::evaluate_funcall): Pass
array_view instead of array to value_struct_elt.
* valarith.c (value_user_defined_op): Likewise.
* valops.c (typecmp): Change parameter type from array pointer to
array_view. Update header comment, and update body accordingly.
(search_struct_method): Likewise.
(value_struct_elt): Likewise.
* value.h (value_struct_elt): Update declaration.
gdb/testsuite/ChangeLog:
PR gdb/27994
* gdb.cp/method-call-in-c.cc (struct foo_type): Add operator+=,
change initial value of var member variable.
(main): Make use of foo_type's operator+=.
* gdb.cp/method-call-in-c.exp: Test use of operator+=.
2021-06-22 17:17:53 +08:00
|
|
|
|
/* Evaluate the arguments. The '+ 1' here is to allow for the `this'
|
|
|
|
|
pointer we placed into vals[0]. */
|
2021-03-08 22:27:57 +08:00
|
|
|
|
for (int i = 0; i < args.size (); ++i)
|
|
|
|
|
vals[i + 1] = args[i]->evaluate_with_coercion (exp, noside);
|
gdb: fix regression in evaluate_funcall for non C++ like cases
This regression, as it is exposed by the test added in this commit,
first became noticable with this commit:
commit d182f2797922a305fbd1ef6a483cc39a56b43e02
Date: Mon Mar 8 07:27:57 2021 -0700
Convert c-exp.y to use operations
But, this commit only added converted the C expression parser to make
use of code that was added in this commit:
commit a00b7254fb614af557de7ae7cc0eb39a0ce0e408
Date: Mon Mar 8 07:27:57 2021 -0700
Implement function call operations
And it was this second commit that actually introduced the bugs (there
are two).
In structop_base_operation::evaluate_funcall we build up an argument
list in the vector vals. Later in this function the argument list
might be passed to value_struct_elt.
Prior to commit a00b7254fb614 the vals vector (or argvec as it used to
be called) stored the value for the function callee in the argvec at
index 0. This 'callee' value is what ends up being passed to
evaluate_subexp_do_call, and represents the function to be called, the
value contents are the address of the function, and the value type is
the function signature. The remaining items held in the argvec were
the values to pass to the function. For a non-static member function
the `this' pointer would be at index 1 in the array.
After commit a00b7254fb614 this callee value is now held in a separate
variable, not the vals array. So, for non-static member functions,
the `this' pointer is now at index 0, with any other arguments after
that.
What this means is that previous, when we called value_struct_elt we
would pass the address of argvec[1] as this was the first argument.
But now we should be passing the address of vals[0]. Unfortunately,
we are still passing vals[1], effectively skipping the first
argument.
The second issue is that, prior to commit a00b7254fb614, the argvec
array was NULL terminated. This is required as value_struct_elt
calls search_struct_method, which calls typecmp, and typecmp requires
that the array have a NULL at the end.
After commit a00b7254fb614 this NULL has been lost, and we are
therefore violating the API requirements of typecmp.
This commit fixes both of these regressions. I also extended the
header comments on search_struct_method and value_struct_elt to make
it clearer that the array required a NULL marker at the end.
You will notice in the test attached to this commit that I test
calling a non-static member function, but not calling a static member
function. The reason for this is that calling static member functions
is currently broken due to a different bug. That will be fixed in a
later patch in this series, at which time I'll add a test for calling
a static member function.
gdb/ChangeLog:
PR gdb/27994
* eval.c (structop_base_operation::evaluate_funcall): Add a
nullptr to the end of the args array, which should not be included
in the argument array_view. Pass all the arguments through to
value_struct_elt.
* valops.c (search_struct_method): Update header comment.
(value_struct_elt): Likewise.
gdb/testsuite/ChangeLog:
PR gdb/27994
* gdb.cp/method-call-in-c.cc: New file.
* gdb.cp/method-call-in-c.exp: New file.
2021-06-22 06:33:11 +08:00
|
|
|
|
|
gdb: replace NULL terminated array with array_view
After the previous commit, this commit updates the value_struct_elt
function to take an array_view rather than a NULL terminated array of
values.
The requirement for a NULL terminated array of values actually stems
from typecmp, so the change from an array to array_view needs to be
propagated through to this function.
While making this change I noticed that this fixes another bug, in
value_x_binop and value_x_unop GDB creates an array of values which
doesn't have a NULL at the end. An array_view of this array is passed
to value_user_defined_op, which then unpacks the array_view and passed
the raw array to value_struct_elt, but only if the language is not
C++.
As value_x_binop and value_x_unop can only request member functions
with the names of C++ operators, then most of the time, assuming the
inferior is not a C++ program, then GDB will not find a matching
member function with the call to value_struct_elt, and so typecmp will
never be called, and so, GDB will avoid undefined behaviour.
However, it is worth remembering that, when GDB's language is set to
"auto", the current language is selected based on the language of the
current compilation unit. As C++ programs usually link against libc,
which is written in C, then, if the inferior is stopped in libc GDB
will set the language to C. And so, it is possible that we will end
up using value_struct_elt to try and lookup, and match, a C++
operator. If this occurs then GDB will experience undefined
behaviour.
I have extended the test added in the previous commit to also cover
this case.
Finally, this commit changes the API from passing around a pointer to
an array to passing around a pointer to an array_view. The reason for
this is that we need to be able to distinguish between the cases where
we call value_struct_elt with no arguments, i.e. we are looking up a
struct member, but we either don't have the arguments we want to pass
yet, or we don't expect there to be any need for GDB to use the
argument types to resolve any overloading; and the second case where
we call value_struct_elt looking for a function that takes no
arguments, that is, the argument list is empty.
NOTE: While writing this I realise that if we pass an array_view at
all then it will always have at least one item in it, the `this'
pointer for the object we are planning to call the method on. So we
could, I guess, pass an empty array_view to indicate the case where we
don't know anything about the arguments, and when the array_view is
length 1 or more, it means we do have the arguments. However, though
we could do this, I don't think this would be better, the length 0 vs
length 1 difference seems a little too subtle, I think that there's a
better solution...
I think a better solution would be to wrap the array_view in a
gdb::optional, this would make the whole, do we have an array view or
not question explicit.
I haven't done this as part of this commit as making that change is
much more extensive, every user of value_struct_elt will need to be
updated, and as this commit already contains a bug fix, I wanted to
keep the large refactoring in a separate commit, so, check out the
next commit for the use of gdb::optional.
gdb/ChangeLog:
PR gdb/27994
* eval.c (structop_base_operation::evaluate_funcall): Pass
array_view instead of array to value_struct_elt.
* valarith.c (value_user_defined_op): Likewise.
* valops.c (typecmp): Change parameter type from array pointer to
array_view. Update header comment, and update body accordingly.
(search_struct_method): Likewise.
(value_struct_elt): Likewise.
* value.h (value_struct_elt): Update declaration.
gdb/testsuite/ChangeLog:
PR gdb/27994
* gdb.cp/method-call-in-c.cc (struct foo_type): Add operator+=,
change initial value of var member variable.
(main): Make use of foo_type's operator+=.
* gdb.cp/method-call-in-c.exp: Test use of operator+=.
2021-06-22 17:17:53 +08:00
|
|
|
|
/* The array view includes the `this' pointer. */
|
|
|
|
|
gdb::array_view<value *> arg_view (vals);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
int static_memfuncp;
|
|
|
|
|
value *callee;
|
|
|
|
|
const char *tstr = std::get<1> (m_storage).c_str ();
|
|
|
|
|
if (overload_resolution
|
|
|
|
|
&& exp->language_defn->la_language == language_cplus)
|
|
|
|
|
{
|
|
|
|
|
/* Language is C++, do some overload resolution before
|
|
|
|
|
evaluation. */
|
|
|
|
|
value *val0 = vals[0];
|
|
|
|
|
find_overload_match (arg_view, tstr, METHOD,
|
|
|
|
|
&val0, nullptr, &callee, nullptr,
|
|
|
|
|
&static_memfuncp, 0, noside);
|
|
|
|
|
vals[0] = val0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* Non-C++ case -- or no overload resolution. */
|
|
|
|
|
{
|
|
|
|
|
struct value *temp = vals[0];
|
|
|
|
|
|
2021-06-23 02:27:53 +08:00
|
|
|
|
callee = value_struct_elt (&temp, arg_view, tstr,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
&static_memfuncp,
|
|
|
|
|
op == STRUCTOP_STRUCT
|
|
|
|
|
? "structure" : "structure pointer");
|
|
|
|
|
/* value_struct_elt updates temp with the correct value of the
|
|
|
|
|
``this'' pointer if necessary, so modify it to reflect any
|
|
|
|
|
``this'' changes. */
|
2023-01-31 22:52:09 +08:00
|
|
|
|
vals[0] = value_from_longest (lookup_pointer_type (temp->type ()),
|
2023-02-01 03:27:30 +08:00
|
|
|
|
temp->address ()
|
2023-02-01 01:40:38 +08:00
|
|
|
|
+ temp->embedded_offset ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Take out `this' if needed. */
|
|
|
|
|
if (static_memfuncp)
|
|
|
|
|
arg_view = arg_view.slice (1);
|
|
|
|
|
|
|
|
|
|
return evaluate_subexp_do_call (exp, noside, callee, arg_view,
|
|
|
|
|
nullptr, expect_type);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-23 00:48:25 +08:00
|
|
|
|
/* Helper for structop_base_operation::complete which recursively adds
|
|
|
|
|
field and method names from TYPE, a struct or union type, to the
|
2022-02-23 04:12:02 +08:00
|
|
|
|
OUTPUT list. PREFIX is prepended to each result. */
|
2022-02-23 00:48:25 +08:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
add_struct_fields (struct type *type, completion_list &output,
|
2022-02-23 04:12:02 +08:00
|
|
|
|
const char *fieldname, int namelen, const char *prefix)
|
2022-02-23 00:48:25 +08:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int computed_type_name = 0;
|
|
|
|
|
const char *type_name = NULL;
|
|
|
|
|
|
|
|
|
|
type = check_typedef (type);
|
|
|
|
|
for (i = 0; i < type->num_fields (); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (i < TYPE_N_BASECLASSES (type))
|
|
|
|
|
add_struct_fields (TYPE_BASECLASS (type, i),
|
2022-02-23 04:12:02 +08:00
|
|
|
|
output, fieldname, namelen, prefix);
|
2022-02-23 00:48:25 +08:00
|
|
|
|
else if (type->field (i).name ())
|
|
|
|
|
{
|
|
|
|
|
if (type->field (i).name ()[0] != '\0')
|
|
|
|
|
{
|
|
|
|
|
if (! strncmp (type->field (i).name (),
|
|
|
|
|
fieldname, namelen))
|
2022-02-23 04:12:02 +08:00
|
|
|
|
output.emplace_back (concat (prefix, type->field (i).name (),
|
|
|
|
|
nullptr));
|
2022-02-23 00:48:25 +08:00
|
|
|
|
}
|
|
|
|
|
else if (type->field (i).type ()->code () == TYPE_CODE_UNION)
|
|
|
|
|
{
|
|
|
|
|
/* Recurse into anonymous unions. */
|
|
|
|
|
add_struct_fields (type->field (i).type (),
|
2022-02-23 04:12:02 +08:00
|
|
|
|
output, fieldname, namelen, prefix);
|
2022-02-23 00:48:25 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i)
|
|
|
|
|
{
|
|
|
|
|
const char *name = TYPE_FN_FIELDLIST_NAME (type, i);
|
|
|
|
|
|
|
|
|
|
if (name && ! strncmp (name, fieldname, namelen))
|
|
|
|
|
{
|
|
|
|
|
if (!computed_type_name)
|
|
|
|
|
{
|
|
|
|
|
type_name = type->name ();
|
|
|
|
|
computed_type_name = 1;
|
|
|
|
|
}
|
|
|
|
|
/* Omit constructors from the completion list. */
|
|
|
|
|
if (!type_name || strcmp (type_name, name))
|
2022-02-23 04:12:02 +08:00
|
|
|
|
output.emplace_back (concat (prefix, name, nullptr));
|
2022-02-23 00:48:25 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See expop.h. */
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
structop_base_operation::complete (struct expression *exp,
|
2022-02-23 04:12:02 +08:00
|
|
|
|
completion_tracker &tracker,
|
|
|
|
|
const char *prefix)
|
2022-02-23 00:48:25 +08:00
|
|
|
|
{
|
|
|
|
|
const std::string &fieldname = std::get<1> (m_storage);
|
|
|
|
|
|
|
|
|
|
value *lhs = std::get<0> (m_storage)->evaluate (nullptr, exp,
|
|
|
|
|
EVAL_AVOID_SIDE_EFFECTS);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = lhs->type ();
|
2022-02-23 00:48:25 +08:00
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
type = check_typedef (type);
|
|
|
|
|
if (!type->is_pointer_or_reference ())
|
|
|
|
|
break;
|
2022-07-31 10:43:54 +08:00
|
|
|
|
type = type->target_type ();
|
2022-02-23 00:48:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type->code () == TYPE_CODE_UNION
|
|
|
|
|
|| type->code () == TYPE_CODE_STRUCT)
|
|
|
|
|
{
|
|
|
|
|
completion_list result;
|
|
|
|
|
|
|
|
|
|
add_struct_fields (type, result, fieldname.c_str (),
|
2022-02-23 04:12:02 +08:00
|
|
|
|
fieldname.length (), prefix);
|
2022-02-23 00:48:25 +08:00
|
|
|
|
tracker.add_completions (std::move (result));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
} /* namespace expr */
|
|
|
|
|
|
2020-03-31 20:49:06 +08:00
|
|
|
|
/* Return true if type is integral or reference to integral */
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
is_integral_or_integral_reference (struct type *type)
|
|
|
|
|
{
|
|
|
|
|
if (is_integral_type (type))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
type = check_typedef (type);
|
|
|
|
|
return (type != nullptr
|
|
|
|
|
&& TYPE_IS_REFERENCE (type)
|
2022-07-31 10:43:54 +08:00
|
|
|
|
&& is_integral_type (type->target_type ()));
|
2020-03-31 20:49:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* Helper function that implements the body of OP_SCOPE. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_scope (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside,
|
|
|
|
|
struct type *type, const char *string)
|
|
|
|
|
{
|
|
|
|
|
struct value *arg1 = value_aggregate_elt (type, string, expect_type,
|
|
|
|
|
0, noside);
|
|
|
|
|
if (arg1 == NULL)
|
|
|
|
|
error (_("There is no field named %s"), string);
|
|
|
|
|
return arg1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* Helper function that implements the body of OP_VAR_ENTRY_VALUE. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_var_entry_value (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, symbol *sym)
|
|
|
|
|
{
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (sym->type (), not_lval);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
2024-01-20 04:32:32 +08:00
|
|
|
|
const symbol_computed_ops *computed_ops = sym->computed_ops ();
|
|
|
|
|
if (computed_ops == nullptr
|
|
|
|
|
|| computed_ops->read_variable_at_entry == nullptr)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
error (_("Symbol \"%s\" does not have any specific entry value"),
|
|
|
|
|
sym->print_name ());
|
|
|
|
|
|
2022-07-26 01:06:35 +08:00
|
|
|
|
frame_info_ptr frame = get_selected_frame (NULL);
|
2024-01-20 04:32:32 +08:00
|
|
|
|
return computed_ops->read_variable_at_entry (sym, frame);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* Helper function that implements the body of OP_VAR_MSYM_VALUE. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_var_msym_value (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, bool outermost_p,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
bound_minimal_symbol msymbol)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
{
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *val = evaluate_var_msym_value (noside, msymbol.objfile,
|
|
|
|
|
msymbol.minsym);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = val->type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (type->code () == TYPE_CODE_ERROR
|
|
|
|
|
&& (noside != EVAL_AVOID_SIDE_EFFECTS || !outermost_p))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
error_unknown_type (msymbol.minsym->print_name ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* Helper function that implements the body of OP_FUNC_STATIC_VAR. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_func_static_var (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside,
|
|
|
|
|
value *func, const char *var)
|
|
|
|
|
{
|
2023-02-01 03:27:30 +08:00
|
|
|
|
CORE_ADDR addr = func->address ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
const block *blk = block_for_pc (addr);
|
2023-03-31 13:00:26 +08:00
|
|
|
|
struct block_symbol sym = lookup_symbol (var, blk, SEARCH_VAR_DOMAIN,
|
|
|
|
|
nullptr);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (sym.symbol == NULL)
|
|
|
|
|
error (_("No symbol \"%s\" in specified context."), var);
|
|
|
|
|
return evaluate_var_value (noside, sym.block, sym.symbol);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* Helper function that implements the body of OP_REGISTER. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_register (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, const char *name)
|
|
|
|
|
{
|
|
|
|
|
int regno;
|
|
|
|
|
struct value *val;
|
|
|
|
|
|
|
|
|
|
regno = user_reg_map_name_to_regnum (exp->gdbarch,
|
|
|
|
|
name, strlen (name));
|
|
|
|
|
if (regno == -1)
|
|
|
|
|
error (_("Register $%s not available."), name);
|
|
|
|
|
|
|
|
|
|
/* In EVAL_AVOID_SIDE_EFFECTS mode, we only need to return
|
|
|
|
|
a value with the appropriate register type. Unfortunately,
|
|
|
|
|
we don't have easy access to the type of user registers.
|
|
|
|
|
So for these registers, we fetch the register value regardless
|
|
|
|
|
of the evaluation mode. */
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS
|
|
|
|
|
&& regno < gdbarch_num_cooked_regs (exp->gdbarch))
|
2023-02-01 04:41:35 +08:00
|
|
|
|
val = value::zero (register_type (exp->gdbarch, regno), not_lval);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
else
|
2023-12-02 00:27:21 +08:00
|
|
|
|
val = value_of_register
|
|
|
|
|
(regno, get_next_frame_sentinel_okay (get_selected_frame ()));
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (val == NULL)
|
|
|
|
|
error (_("Value of register %s not available."), name);
|
|
|
|
|
else
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-09 00:47:39 +08:00
|
|
|
|
namespace expr
|
|
|
|
|
{
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
2022-03-09 00:47:39 +08:00
|
|
|
|
value *
|
|
|
|
|
string_operation::evaluate (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
{
|
2022-03-09 00:47:39 +08:00
|
|
|
|
const std::string &str = std::get<0> (m_storage);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct type *type = language_string_char_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch);
|
2022-03-09 00:47:39 +08:00
|
|
|
|
return value_string (str.c_str (), str.size (), type);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-30 00:51:33 +08:00
|
|
|
|
struct value *
|
|
|
|
|
ternop_slice_operation::evaluate (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
struct value *array
|
|
|
|
|
= std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
struct value *low
|
|
|
|
|
= std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
struct value *upper
|
|
|
|
|
= std::get<2> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
|
|
|
|
|
int lowbound = value_as_long (low);
|
|
|
|
|
int upperbound = value_as_long (upper);
|
|
|
|
|
return value_slice (array, lowbound, upperbound - lowbound + 1);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-09 00:47:39 +08:00
|
|
|
|
} /* namespace expr */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* Helper function that implements the body of OP_OBJC_SELECTOR. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_objc_selector (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside,
|
|
|
|
|
const char *sel)
|
|
|
|
|
{
|
|
|
|
|
struct type *selector_type = builtin_type (exp->gdbarch)->builtin_data_ptr;
|
|
|
|
|
return value_from_longest (selector_type,
|
|
|
|
|
lookup_child_selector (exp->gdbarch, sel));
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for STRUCTOP_STRUCT. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_structop_struct (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside,
|
|
|
|
|
struct value *arg1, const char *string)
|
|
|
|
|
{
|
2021-06-23 02:27:53 +08:00
|
|
|
|
struct value *arg3 = value_struct_elt (&arg1, {}, string,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
NULL, "structure");
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2023-02-09 21:55:48 +08:00
|
|
|
|
arg3 = value::zero (arg3->type (), arg3->lval ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return arg3;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for STRUCTOP_PTR. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_structop_ptr (struct type *expect_type, struct expression *exp,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
enum noside noside,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *arg1, const char *string)
|
|
|
|
|
{
|
|
|
|
|
/* Check to see if operator '->' has been overloaded. If so replace
|
|
|
|
|
arg1 with the value returned by evaluating operator->(). */
|
2021-03-08 22:27:57 +08:00
|
|
|
|
while (unop_user_defined_p (STRUCTOP_PTR, arg1))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
{
|
|
|
|
|
struct value *value = NULL;
|
|
|
|
|
try
|
|
|
|
|
{
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value = value_x_unop (arg1, STRUCTOP_PTR, noside);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
catch (const gdb_exception_error &except)
|
|
|
|
|
{
|
|
|
|
|
if (except.error == NOT_FOUND_ERROR)
|
|
|
|
|
break;
|
|
|
|
|
else
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arg1 = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* JYG: if print object is on we need to replace the base type
|
|
|
|
|
with rtti type in order to continue on with successful
|
|
|
|
|
lookup of member / method only available in the rtti type. */
|
|
|
|
|
{
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *arg_type = arg1->type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct type *real_type;
|
|
|
|
|
int full, using_enc;
|
|
|
|
|
LONGEST top;
|
|
|
|
|
struct value_print_options opts;
|
|
|
|
|
|
|
|
|
|
get_user_print_options (&opts);
|
2022-07-31 10:43:54 +08:00
|
|
|
|
if (opts.objectprint && arg_type->target_type ()
|
|
|
|
|
&& (arg_type->target_type ()->code () == TYPE_CODE_STRUCT))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
{
|
|
|
|
|
real_type = value_rtti_indirect_type (arg1, &full, &top,
|
|
|
|
|
&using_enc);
|
|
|
|
|
if (real_type)
|
|
|
|
|
arg1 = value_cast (real_type, arg1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-23 02:27:53 +08:00
|
|
|
|
struct value *arg3 = value_struct_elt (&arg1, {}, string,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
NULL, "structure pointer");
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2023-02-09 21:55:48 +08:00
|
|
|
|
arg3 = value::zero (arg3->type (), arg3->lval ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return arg3;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for STRUCTOP_MEMBER. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_member (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside,
|
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
|
|
|
|
long mem_offset;
|
|
|
|
|
|
|
|
|
|
struct value *arg3;
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = check_typedef (arg2->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
switch (type->code ())
|
|
|
|
|
{
|
|
|
|
|
case TYPE_CODE_METHODPTR:
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (type->target_type (), not_lval);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
arg2 = cplus_method_ptr_to_value (&arg1, arg2);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
gdb_assert (arg2->type ()->code () == TYPE_CODE_PTR);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return value_ind (arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_MEMBERPTR:
|
|
|
|
|
/* Now, convert these values to an address. */
|
2023-01-31 22:52:09 +08:00
|
|
|
|
if (check_typedef (arg1->type ())->code () != TYPE_CODE_PTR)
|
2022-12-24 03:55:10 +08:00
|
|
|
|
arg1 = value_addr (arg1);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
arg1 = value_cast_pointers (lookup_pointer_type (TYPE_SELF_TYPE (type)),
|
|
|
|
|
arg1, 1);
|
|
|
|
|
|
|
|
|
|
mem_offset = value_as_long (arg2);
|
|
|
|
|
|
2022-07-31 10:43:54 +08:00
|
|
|
|
arg3 = value_from_pointer (lookup_pointer_type (type->target_type ()),
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value_as_long (arg1) + mem_offset);
|
|
|
|
|
return value_ind (arg3);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
error (_("non-pointer-to-member value used "
|
|
|
|
|
"in pointer-to-member construct"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for BINOP_ADD. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_add (struct type *expect_type, struct expression *exp,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
enum noside noside,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (binop_user_defined_p (BINOP_ADD, arg1, arg2))
|
|
|
|
|
return value_x_binop (arg1, arg2, BINOP_ADD, OP_NULL, noside);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
else if (ptrmath_type_p (exp->language_defn, arg1->type ())
|
|
|
|
|
&& is_integral_or_integral_reference (arg2->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return value_ptradd (arg1, value_as_long (arg2));
|
2023-01-31 22:52:09 +08:00
|
|
|
|
else if (ptrmath_type_p (exp->language_defn, arg2->type ())
|
|
|
|
|
&& is_integral_or_integral_reference (arg1->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return value_ptradd (arg2, value_as_long (arg1));
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
|
|
|
|
|
return value_binop (arg1, arg2, BINOP_ADD);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for BINOP_SUB. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_sub (struct type *expect_type, struct expression *exp,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
enum noside noside,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (binop_user_defined_p (BINOP_SUB, arg1, arg2))
|
|
|
|
|
return value_x_binop (arg1, arg2, BINOP_SUB, OP_NULL, noside);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
else if (ptrmath_type_p (exp->language_defn, arg1->type ())
|
|
|
|
|
&& ptrmath_type_p (exp->language_defn, arg2->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
{
|
|
|
|
|
/* FIXME -- should be ptrdiff_t */
|
|
|
|
|
struct type *type = builtin_type (exp->gdbarch)->builtin_long;
|
|
|
|
|
return value_from_longest (type, value_ptrdiff (arg1, arg2));
|
|
|
|
|
}
|
2023-01-31 22:52:09 +08:00
|
|
|
|
else if (ptrmath_type_p (exp->language_defn, arg1->type ())
|
|
|
|
|
&& is_integral_or_integral_reference (arg2->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return value_ptradd (arg1, - value_as_long (arg2));
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
|
|
|
|
|
return value_binop (arg1, arg2, BINOP_SUB);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* Helper function for several different binary operations. */
|
|
|
|
|
|
Introduce binop_operation
This adds two new template classes, binop_operation and
usual_ax_binop_operation, and then uses these to implement a number of
binary operations that follow similar patterns.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* expop.h (class binop_operation, class usual_ax_binop_operation):
New.
(exp_operation, intdiv_operation, mod_operation, mul_operation)
(div_operation, rem_operation, lsh_operation, rsh_operation)
(bitwise_and_operation, bitwise_ior_operation)
(bitwise_xor_operation): New typedefs.
* eval.c (eval_op_binary): No longer static.
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_binary (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
|
|
|
|
if (binop_user_defined_p (op, arg1, arg2))
|
|
|
|
|
return value_x_binop (arg1, arg2, op, OP_NULL, noside);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* If EVAL_AVOID_SIDE_EFFECTS and we're dividing by zero,
|
|
|
|
|
fudge arg2 to avoid division-by-zero, the caller is
|
|
|
|
|
(theoretically) only looking for the type of the result. */
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS
|
|
|
|
|
/* ??? Do we really want to test for BINOP_MOD here?
|
|
|
|
|
The implementation of value_binop gives it a well-defined
|
|
|
|
|
value. */
|
|
|
|
|
&& (op == BINOP_DIV
|
|
|
|
|
|| op == BINOP_INTDIV
|
|
|
|
|
|| op == BINOP_REM
|
|
|
|
|
|| op == BINOP_MOD)
|
|
|
|
|
&& value_logical_not (arg2))
|
|
|
|
|
{
|
|
|
|
|
struct value *v_one;
|
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
v_one = value_one (arg2->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &arg1, &v_one);
|
|
|
|
|
return value_binop (arg1, v_one, op);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* For shift and integer exponentiation operations,
|
|
|
|
|
only promote the first argument. */
|
|
|
|
|
if ((op == BINOP_LSH || op == BINOP_RSH || op == BINOP_EXP)
|
2023-01-31 22:52:09 +08:00
|
|
|
|
&& is_integral_type (arg2->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
unop_promote (exp->language_defn, exp->gdbarch, &arg1);
|
|
|
|
|
else
|
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
|
|
|
|
|
|
|
|
|
|
return value_binop (arg1, arg2, op);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for BINOP_SUBSCRIPT. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_subscript (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
|
|
|
|
if (binop_user_defined_p (op, arg1, arg2))
|
|
|
|
|
return value_x_binop (arg1, arg2, op, OP_NULL, noside);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* If the user attempts to subscript something that is not an
|
|
|
|
|
array or pointer type (like a plain int variable for example),
|
|
|
|
|
then report this as an error. */
|
|
|
|
|
|
|
|
|
|
arg1 = coerce_ref (arg1);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = check_typedef (arg1->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (type->code () != TYPE_CODE_ARRAY
|
|
|
|
|
&& type->code () != TYPE_CODE_PTR)
|
|
|
|
|
{
|
|
|
|
|
if (type->name ())
|
|
|
|
|
error (_("cannot subscript something of type `%s'"),
|
|
|
|
|
type->name ());
|
|
|
|
|
else
|
|
|
|
|
error (_("cannot subscript requested type"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2023-02-09 21:55:48 +08:00
|
|
|
|
return value::zero (type->target_type (), arg1->lval ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
else
|
|
|
|
|
return value_subscript (arg1, value_as_long (arg2));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for BINOP_EQUAL. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_equal (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
|
|
|
|
if (binop_user_defined_p (op, arg1, arg2))
|
|
|
|
|
{
|
|
|
|
|
return value_x_binop (arg1, arg2, op, OP_NULL, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
|
|
|
|
|
int tem = value_equal (arg1, arg2);
|
|
|
|
|
struct type *type = language_bool_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch);
|
|
|
|
|
return value_from_longest (type, (LONGEST) tem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for BINOP_NOTEQUAL. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_notequal (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
|
|
|
|
if (binop_user_defined_p (op, arg1, arg2))
|
|
|
|
|
{
|
|
|
|
|
return value_x_binop (arg1, arg2, op, OP_NULL, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
|
|
|
|
|
int tem = value_equal (arg1, arg2);
|
|
|
|
|
struct type *type = language_bool_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch);
|
|
|
|
|
return value_from_longest (type, (LONGEST) ! tem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for BINOP_LESS. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_less (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
|
|
|
|
if (binop_user_defined_p (op, arg1, arg2))
|
|
|
|
|
{
|
|
|
|
|
return value_x_binop (arg1, arg2, op, OP_NULL, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
|
|
|
|
|
int tem = value_less (arg1, arg2);
|
|
|
|
|
struct type *type = language_bool_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch);
|
|
|
|
|
return value_from_longest (type, (LONGEST) tem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for BINOP_GTR. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_gtr (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
|
|
|
|
if (binop_user_defined_p (op, arg1, arg2))
|
|
|
|
|
{
|
|
|
|
|
return value_x_binop (arg1, arg2, op, OP_NULL, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
|
|
|
|
|
int tem = value_less (arg2, arg1);
|
|
|
|
|
struct type *type = language_bool_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch);
|
|
|
|
|
return value_from_longest (type, (LONGEST) tem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for BINOP_GEQ. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_geq (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
|
|
|
|
if (binop_user_defined_p (op, arg1, arg2))
|
|
|
|
|
{
|
|
|
|
|
return value_x_binop (arg1, arg2, op, OP_NULL, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
|
|
|
|
|
int tem = value_less (arg2, arg1) || value_equal (arg1, arg2);
|
|
|
|
|
struct type *type = language_bool_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch);
|
|
|
|
|
return value_from_longest (type, (LONGEST) tem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for BINOP_LEQ. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_leq (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
|
|
|
|
if (binop_user_defined_p (op, arg1, arg2))
|
|
|
|
|
{
|
|
|
|
|
return value_x_binop (arg1, arg2, op, OP_NULL, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
|
|
|
|
|
int tem = value_less (arg1, arg2) || value_equal (arg1, arg2);
|
|
|
|
|
struct type *type = language_bool_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch);
|
|
|
|
|
return value_from_longest (type, (LONGEST) tem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for BINOP_REPEAT. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_repeat (struct type *expect_type, struct expression *exp,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
enum noside noside, enum exp_opcode op,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = check_typedef (arg2->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (type->code () != TYPE_CODE_INT
|
|
|
|
|
&& type->code () != TYPE_CODE_ENUM)
|
|
|
|
|
error (_("Non-integral right operand for \"@\" operator."));
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
{
|
2023-01-31 22:52:09 +08:00
|
|
|
|
return allocate_repeat_value (arg1->type (),
|
2021-03-08 22:27:57 +08:00
|
|
|
|
longest_to_int (value_as_long (arg2)));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return value_repeat (arg1, longest_to_int (value_as_long (arg2)));
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for UNOP_PLUS. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_plus (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1)
|
|
|
|
|
{
|
|
|
|
|
if (unop_user_defined_p (op, arg1))
|
|
|
|
|
return value_x_unop (arg1, op, noside);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unop_promote (exp->language_defn, exp->gdbarch, &arg1);
|
|
|
|
|
return value_pos (arg1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for UNOP_NEG. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_neg (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1)
|
|
|
|
|
{
|
|
|
|
|
if (unop_user_defined_p (op, arg1))
|
|
|
|
|
return value_x_unop (arg1, op, noside);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unop_promote (exp->language_defn, exp->gdbarch, &arg1);
|
|
|
|
|
return value_neg (arg1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for UNOP_COMPLEMENT. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_complement (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1)
|
|
|
|
|
{
|
|
|
|
|
if (unop_user_defined_p (UNOP_COMPLEMENT, arg1))
|
|
|
|
|
return value_x_unop (arg1, UNOP_COMPLEMENT, noside);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unop_promote (exp->language_defn, exp->gdbarch, &arg1);
|
|
|
|
|
return value_complement (arg1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for UNOP_LOGICAL_NOT. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_lognot (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1)
|
|
|
|
|
{
|
|
|
|
|
if (unop_user_defined_p (op, arg1))
|
|
|
|
|
return value_x_unop (arg1, op, noside);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct type *type = language_bool_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch);
|
|
|
|
|
return value_from_longest (type, (LONGEST) value_logical_not (arg1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for UNOP_IND. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_ind (struct type *expect_type, struct expression *exp,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
enum noside noside,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *arg1)
|
|
|
|
|
{
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = check_typedef (arg1->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (type->code () == TYPE_CODE_METHODPTR
|
|
|
|
|
|| type->code () == TYPE_CODE_MEMBERPTR)
|
|
|
|
|
error (_("Attempt to dereference pointer "
|
|
|
|
|
"to member without an object"));
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (unop_user_defined_p (UNOP_IND, arg1))
|
|
|
|
|
return value_x_unop (arg1, UNOP_IND, noside);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
else if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
{
|
2023-01-31 22:52:09 +08:00
|
|
|
|
type = check_typedef (arg1->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
/* If the type pointed to is dynamic then in order to resolve the
|
|
|
|
|
dynamic properties we must actually dereference the pointer.
|
|
|
|
|
There is a risk that this dereference will have side-effects
|
|
|
|
|
in the inferior, but being able to print accurate type
|
|
|
|
|
information seems worth the risk. */
|
2021-09-12 03:58:04 +08:00
|
|
|
|
if (!type->is_pointer_or_reference ()
|
2022-07-31 10:43:54 +08:00
|
|
|
|
|| !is_dynamic_type (type->target_type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
{
|
2021-09-12 03:58:04 +08:00
|
|
|
|
if (type->is_pointer_or_reference ()
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* In C you can dereference an array to get the 1st elt. */
|
|
|
|
|
|| type->code () == TYPE_CODE_ARRAY)
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (type->target_type (),
|
2021-03-08 22:27:57 +08:00
|
|
|
|
lval_memory);
|
|
|
|
|
else if (type->code () == TYPE_CODE_INT)
|
|
|
|
|
/* GDB allows dereferencing an int. */
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (builtin_type (exp->gdbarch)->builtin_int,
|
2021-03-08 22:27:57 +08:00
|
|
|
|
lval_memory);
|
|
|
|
|
else
|
|
|
|
|
error (_("Attempt to take contents of a non-pointer value."));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allow * on an integer so we can cast it to whatever we want.
|
|
|
|
|
This returns an int, which seems like the most C-like thing to
|
|
|
|
|
do. "long long" variables are rare enough that
|
|
|
|
|
BUILTIN_TYPE_LONGEST would seem to be a mistake. */
|
|
|
|
|
if (type->code () == TYPE_CODE_INT)
|
|
|
|
|
return value_at_lazy (builtin_type (exp->gdbarch)->builtin_int,
|
2024-02-27 04:50:54 +08:00
|
|
|
|
value_as_address (arg1));
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return value_ind (arg1);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for UNOP_ALIGNOF. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_alignof (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside,
|
|
|
|
|
struct value *arg1)
|
|
|
|
|
{
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = arg1->type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* FIXME: This should be size_t. */
|
|
|
|
|
struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
|
|
|
|
|
ULONGEST align = type_align (type);
|
|
|
|
|
if (align == 0)
|
|
|
|
|
error (_("could not determine alignment of type"));
|
|
|
|
|
return value_from_longest (size_type, align);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for UNOP_MEMVAL. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_memval (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside,
|
|
|
|
|
struct value *arg1, struct type *type)
|
|
|
|
|
{
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (type, lval_memory);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
else
|
|
|
|
|
return value_at_lazy (type, value_as_address (arg1));
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for UNOP_PREINCREMENT. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_preinc (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1)
|
|
|
|
|
{
|
Remove EVAL_SKIP
EVAL_SKIP was needed in the old expression implementation due to its
linearized tree structure. This is not needed in the new
implementation, because it is trivial to not evaluate a subexpression.
This patch removes the last vestiges of EVAL_SKIP.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (eval_skip_value): Don't declare.
* opencl-lang.c (eval_opencl_assign): Update.
* m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): Update.
* f-lang.c (eval_op_f_abs, eval_op_f_mod, eval_op_f_ceil)
(eval_op_f_floor, eval_op_f_modulo, eval_op_f_cmplx): Remove.
* expression.h (enum noside) <EVAL_SKIP>: Remove.
* expop.h (typeof_operation::evaluate)
(decltype_operation::evaluate, unop_addr_operation::evaluate)
(unop_sizeof_operation::evaluate, assign_operation::evaluate)
(cxx_cast_operation::evaluate): Update.
* eval.c (eval_skip_value): Remove.
(eval_op_scope, eval_op_var_entry_value)
(eval_op_func_static_var, eval_op_string, eval_op_objc_selector)
(eval_op_concat, eval_op_ternop, eval_op_structop_struct)
(eval_op_structop_ptr, eval_op_member, eval_op_add, eval_op_sub)
(eval_op_binary, eval_op_subscript, eval_op_equal)
(eval_op_notequal, eval_op_less, eval_op_gtr, eval_op_geq)
(eval_op_leq, eval_op_repeat, eval_op_plus, eval_op_neg)
(eval_op_complement, eval_op_lognot, eval_op_ind)
(eval_op_memval, eval_op_preinc, eval_op_predec)
(eval_op_postinc, eval_op_postdec, eval_op_type)
(eval_binop_assign_modify, eval_op_objc_msgcall)
(eval_multi_subscript, logical_and_operation::evaluate)
(logical_or_operation::evaluate, array_operation::evaluate)
(operation::evaluate_for_cast)
(var_msym_value_operation::evaluate_for_cast)
(var_value_operation::evaluate_for_cast): Update.
* c-lang.c (c_string_operation::evaluate): Update.
* c-exp.h (objc_nsstring_operation::evaluate)
(objc_selector_operation::evaluate): Update.
* ada-lang.c (ada_assign_operation::evaluate)
(eval_ternop_in_range, ada_unop_neg, ada_unop_in_range)
(ada_atr_size): Update.
2021-03-08 22:27:57 +08:00
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return arg1;
|
|
|
|
|
else if (unop_user_defined_p (op, arg1))
|
|
|
|
|
{
|
|
|
|
|
return value_x_unop (arg1, op, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct value *arg2;
|
2023-01-31 22:52:09 +08:00
|
|
|
|
if (ptrmath_type_p (exp->language_defn, arg1->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
arg2 = value_ptradd (arg1, 1);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct value *tmp = arg1;
|
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
arg2 = value_one (arg1->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
|
|
|
|
|
arg2 = value_binop (tmp, arg2, BINOP_ADD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value_assign (arg1, arg2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for UNOP_PREDECREMENT. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_predec (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1)
|
|
|
|
|
{
|
Remove EVAL_SKIP
EVAL_SKIP was needed in the old expression implementation due to its
linearized tree structure. This is not needed in the new
implementation, because it is trivial to not evaluate a subexpression.
This patch removes the last vestiges of EVAL_SKIP.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (eval_skip_value): Don't declare.
* opencl-lang.c (eval_opencl_assign): Update.
* m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): Update.
* f-lang.c (eval_op_f_abs, eval_op_f_mod, eval_op_f_ceil)
(eval_op_f_floor, eval_op_f_modulo, eval_op_f_cmplx): Remove.
* expression.h (enum noside) <EVAL_SKIP>: Remove.
* expop.h (typeof_operation::evaluate)
(decltype_operation::evaluate, unop_addr_operation::evaluate)
(unop_sizeof_operation::evaluate, assign_operation::evaluate)
(cxx_cast_operation::evaluate): Update.
* eval.c (eval_skip_value): Remove.
(eval_op_scope, eval_op_var_entry_value)
(eval_op_func_static_var, eval_op_string, eval_op_objc_selector)
(eval_op_concat, eval_op_ternop, eval_op_structop_struct)
(eval_op_structop_ptr, eval_op_member, eval_op_add, eval_op_sub)
(eval_op_binary, eval_op_subscript, eval_op_equal)
(eval_op_notequal, eval_op_less, eval_op_gtr, eval_op_geq)
(eval_op_leq, eval_op_repeat, eval_op_plus, eval_op_neg)
(eval_op_complement, eval_op_lognot, eval_op_ind)
(eval_op_memval, eval_op_preinc, eval_op_predec)
(eval_op_postinc, eval_op_postdec, eval_op_type)
(eval_binop_assign_modify, eval_op_objc_msgcall)
(eval_multi_subscript, logical_and_operation::evaluate)
(logical_or_operation::evaluate, array_operation::evaluate)
(operation::evaluate_for_cast)
(var_msym_value_operation::evaluate_for_cast)
(var_value_operation::evaluate_for_cast): Update.
* c-lang.c (c_string_operation::evaluate): Update.
* c-exp.h (objc_nsstring_operation::evaluate)
(objc_selector_operation::evaluate): Update.
* ada-lang.c (ada_assign_operation::evaluate)
(eval_ternop_in_range, ada_unop_neg, ada_unop_in_range)
(ada_atr_size): Update.
2021-03-08 22:27:57 +08:00
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return arg1;
|
|
|
|
|
else if (unop_user_defined_p (op, arg1))
|
|
|
|
|
{
|
|
|
|
|
return value_x_unop (arg1, op, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct value *arg2;
|
2023-01-31 22:52:09 +08:00
|
|
|
|
if (ptrmath_type_p (exp->language_defn, arg1->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
arg2 = value_ptradd (arg1, -1);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct value *tmp = arg1;
|
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
arg2 = value_one (arg1->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
|
|
|
|
|
arg2 = value_binop (tmp, arg2, BINOP_SUB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value_assign (arg1, arg2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for UNOP_POSTINCREMENT. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_postinc (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1)
|
|
|
|
|
{
|
Remove EVAL_SKIP
EVAL_SKIP was needed in the old expression implementation due to its
linearized tree structure. This is not needed in the new
implementation, because it is trivial to not evaluate a subexpression.
This patch removes the last vestiges of EVAL_SKIP.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (eval_skip_value): Don't declare.
* opencl-lang.c (eval_opencl_assign): Update.
* m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): Update.
* f-lang.c (eval_op_f_abs, eval_op_f_mod, eval_op_f_ceil)
(eval_op_f_floor, eval_op_f_modulo, eval_op_f_cmplx): Remove.
* expression.h (enum noside) <EVAL_SKIP>: Remove.
* expop.h (typeof_operation::evaluate)
(decltype_operation::evaluate, unop_addr_operation::evaluate)
(unop_sizeof_operation::evaluate, assign_operation::evaluate)
(cxx_cast_operation::evaluate): Update.
* eval.c (eval_skip_value): Remove.
(eval_op_scope, eval_op_var_entry_value)
(eval_op_func_static_var, eval_op_string, eval_op_objc_selector)
(eval_op_concat, eval_op_ternop, eval_op_structop_struct)
(eval_op_structop_ptr, eval_op_member, eval_op_add, eval_op_sub)
(eval_op_binary, eval_op_subscript, eval_op_equal)
(eval_op_notequal, eval_op_less, eval_op_gtr, eval_op_geq)
(eval_op_leq, eval_op_repeat, eval_op_plus, eval_op_neg)
(eval_op_complement, eval_op_lognot, eval_op_ind)
(eval_op_memval, eval_op_preinc, eval_op_predec)
(eval_op_postinc, eval_op_postdec, eval_op_type)
(eval_binop_assign_modify, eval_op_objc_msgcall)
(eval_multi_subscript, logical_and_operation::evaluate)
(logical_or_operation::evaluate, array_operation::evaluate)
(operation::evaluate_for_cast)
(var_msym_value_operation::evaluate_for_cast)
(var_value_operation::evaluate_for_cast): Update.
* c-lang.c (c_string_operation::evaluate): Update.
* c-exp.h (objc_nsstring_operation::evaluate)
(objc_selector_operation::evaluate): Update.
* ada-lang.c (ada_assign_operation::evaluate)
(eval_ternop_in_range, ada_unop_neg, ada_unop_in_range)
(ada_atr_size): Update.
2021-03-08 22:27:57 +08:00
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return arg1;
|
|
|
|
|
else if (unop_user_defined_p (op, arg1))
|
|
|
|
|
{
|
|
|
|
|
return value_x_unop (arg1, op, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-02-01 07:23:22 +08:00
|
|
|
|
struct value *arg3 = arg1->non_lval ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *arg2;
|
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
if (ptrmath_type_p (exp->language_defn, arg1->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
arg2 = value_ptradd (arg1, 1);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct value *tmp = arg1;
|
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
arg2 = value_one (arg1->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
|
|
|
|
|
arg2 = value_binop (tmp, arg2, BINOP_ADD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value_assign (arg1, arg2);
|
|
|
|
|
return arg3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for UNOP_POSTDECREMENT. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_postdec (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1)
|
|
|
|
|
{
|
Remove EVAL_SKIP
EVAL_SKIP was needed in the old expression implementation due to its
linearized tree structure. This is not needed in the new
implementation, because it is trivial to not evaluate a subexpression.
This patch removes the last vestiges of EVAL_SKIP.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (eval_skip_value): Don't declare.
* opencl-lang.c (eval_opencl_assign): Update.
* m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): Update.
* f-lang.c (eval_op_f_abs, eval_op_f_mod, eval_op_f_ceil)
(eval_op_f_floor, eval_op_f_modulo, eval_op_f_cmplx): Remove.
* expression.h (enum noside) <EVAL_SKIP>: Remove.
* expop.h (typeof_operation::evaluate)
(decltype_operation::evaluate, unop_addr_operation::evaluate)
(unop_sizeof_operation::evaluate, assign_operation::evaluate)
(cxx_cast_operation::evaluate): Update.
* eval.c (eval_skip_value): Remove.
(eval_op_scope, eval_op_var_entry_value)
(eval_op_func_static_var, eval_op_string, eval_op_objc_selector)
(eval_op_concat, eval_op_ternop, eval_op_structop_struct)
(eval_op_structop_ptr, eval_op_member, eval_op_add, eval_op_sub)
(eval_op_binary, eval_op_subscript, eval_op_equal)
(eval_op_notequal, eval_op_less, eval_op_gtr, eval_op_geq)
(eval_op_leq, eval_op_repeat, eval_op_plus, eval_op_neg)
(eval_op_complement, eval_op_lognot, eval_op_ind)
(eval_op_memval, eval_op_preinc, eval_op_predec)
(eval_op_postinc, eval_op_postdec, eval_op_type)
(eval_binop_assign_modify, eval_op_objc_msgcall)
(eval_multi_subscript, logical_and_operation::evaluate)
(logical_or_operation::evaluate, array_operation::evaluate)
(operation::evaluate_for_cast)
(var_msym_value_operation::evaluate_for_cast)
(var_value_operation::evaluate_for_cast): Update.
* c-lang.c (c_string_operation::evaluate): Update.
* c-exp.h (objc_nsstring_operation::evaluate)
(objc_selector_operation::evaluate): Update.
* ada-lang.c (ada_assign_operation::evaluate)
(eval_ternop_in_range, ada_unop_neg, ada_unop_in_range)
(ada_atr_size): Update.
2021-03-08 22:27:57 +08:00
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return arg1;
|
|
|
|
|
else if (unop_user_defined_p (op, arg1))
|
|
|
|
|
{
|
|
|
|
|
return value_x_unop (arg1, op, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-02-01 07:23:22 +08:00
|
|
|
|
struct value *arg3 = arg1->non_lval ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *arg2;
|
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
if (ptrmath_type_p (exp->language_defn, arg1->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
arg2 = value_ptradd (arg1, -1);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct value *tmp = arg1;
|
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
arg2 = value_one (arg1->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
|
|
|
|
|
arg2 = value_binop (tmp, arg2, BINOP_SUB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value_assign (arg1, arg2);
|
|
|
|
|
return arg3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for OP_TYPE. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_op_type (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, struct type *type)
|
|
|
|
|
{
|
Remove EVAL_SKIP
EVAL_SKIP was needed in the old expression implementation due to its
linearized tree structure. This is not needed in the new
implementation, because it is trivial to not evaluate a subexpression.
This patch removes the last vestiges of EVAL_SKIP.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (eval_skip_value): Don't declare.
* opencl-lang.c (eval_opencl_assign): Update.
* m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): Update.
* f-lang.c (eval_op_f_abs, eval_op_f_mod, eval_op_f_ceil)
(eval_op_f_floor, eval_op_f_modulo, eval_op_f_cmplx): Remove.
* expression.h (enum noside) <EVAL_SKIP>: Remove.
* expop.h (typeof_operation::evaluate)
(decltype_operation::evaluate, unop_addr_operation::evaluate)
(unop_sizeof_operation::evaluate, assign_operation::evaluate)
(cxx_cast_operation::evaluate): Update.
* eval.c (eval_skip_value): Remove.
(eval_op_scope, eval_op_var_entry_value)
(eval_op_func_static_var, eval_op_string, eval_op_objc_selector)
(eval_op_concat, eval_op_ternop, eval_op_structop_struct)
(eval_op_structop_ptr, eval_op_member, eval_op_add, eval_op_sub)
(eval_op_binary, eval_op_subscript, eval_op_equal)
(eval_op_notequal, eval_op_less, eval_op_gtr, eval_op_geq)
(eval_op_leq, eval_op_repeat, eval_op_plus, eval_op_neg)
(eval_op_complement, eval_op_lognot, eval_op_ind)
(eval_op_memval, eval_op_preinc, eval_op_predec)
(eval_op_postinc, eval_op_postdec, eval_op_type)
(eval_binop_assign_modify, eval_op_objc_msgcall)
(eval_multi_subscript, logical_and_operation::evaluate)
(logical_or_operation::evaluate, array_operation::evaluate)
(operation::evaluate_for_cast)
(var_msym_value_operation::evaluate_for_cast)
(var_value_operation::evaluate_for_cast): Update.
* c-lang.c (c_string_operation::evaluate): Update.
* c-exp.h (objc_nsstring_operation::evaluate)
(objc_selector_operation::evaluate): Update.
* ada-lang.c (ada_assign_operation::evaluate)
(eval_ternop_in_range, ada_unop_neg, ada_unop_in_range)
(ada_atr_size): Update.
2021-03-08 22:27:57 +08:00
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2023-02-01 04:25:17 +08:00
|
|
|
|
return value::allocate (type);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
else
|
|
|
|
|
error (_("Attempt to use a type name as an expression"));
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* A helper function for BINOP_ASSIGN_MODIFY. */
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct value *
|
2021-03-08 22:27:57 +08:00
|
|
|
|
eval_binop_assign_modify (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, enum exp_opcode op,
|
|
|
|
|
struct value *arg1, struct value *arg2)
|
|
|
|
|
{
|
Remove EVAL_SKIP
EVAL_SKIP was needed in the old expression implementation due to its
linearized tree structure. This is not needed in the new
implementation, because it is trivial to not evaluate a subexpression.
This patch removes the last vestiges of EVAL_SKIP.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (eval_skip_value): Don't declare.
* opencl-lang.c (eval_opencl_assign): Update.
* m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): Update.
* f-lang.c (eval_op_f_abs, eval_op_f_mod, eval_op_f_ceil)
(eval_op_f_floor, eval_op_f_modulo, eval_op_f_cmplx): Remove.
* expression.h (enum noside) <EVAL_SKIP>: Remove.
* expop.h (typeof_operation::evaluate)
(decltype_operation::evaluate, unop_addr_operation::evaluate)
(unop_sizeof_operation::evaluate, assign_operation::evaluate)
(cxx_cast_operation::evaluate): Update.
* eval.c (eval_skip_value): Remove.
(eval_op_scope, eval_op_var_entry_value)
(eval_op_func_static_var, eval_op_string, eval_op_objc_selector)
(eval_op_concat, eval_op_ternop, eval_op_structop_struct)
(eval_op_structop_ptr, eval_op_member, eval_op_add, eval_op_sub)
(eval_op_binary, eval_op_subscript, eval_op_equal)
(eval_op_notequal, eval_op_less, eval_op_gtr, eval_op_geq)
(eval_op_leq, eval_op_repeat, eval_op_plus, eval_op_neg)
(eval_op_complement, eval_op_lognot, eval_op_ind)
(eval_op_memval, eval_op_preinc, eval_op_predec)
(eval_op_postinc, eval_op_postdec, eval_op_type)
(eval_binop_assign_modify, eval_op_objc_msgcall)
(eval_multi_subscript, logical_and_operation::evaluate)
(logical_or_operation::evaluate, array_operation::evaluate)
(operation::evaluate_for_cast)
(var_msym_value_operation::evaluate_for_cast)
(var_value_operation::evaluate_for_cast): Update.
* c-lang.c (c_string_operation::evaluate): Update.
* c-exp.h (objc_nsstring_operation::evaluate)
(objc_selector_operation::evaluate): Update.
* ada-lang.c (ada_assign_operation::evaluate)
(eval_ternop_in_range, ada_unop_neg, ada_unop_in_range)
(ada_atr_size): Update.
2021-03-08 22:27:57 +08:00
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return arg1;
|
|
|
|
|
if (binop_user_defined_p (op, arg1, arg2))
|
|
|
|
|
return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op, noside);
|
|
|
|
|
else if (op == BINOP_ADD && ptrmath_type_p (exp->language_defn,
|
2023-01-31 22:52:09 +08:00
|
|
|
|
arg1->type ())
|
|
|
|
|
&& is_integral_type (arg2->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
arg2 = value_ptradd (arg1, value_as_long (arg2));
|
|
|
|
|
else if (op == BINOP_SUB && ptrmath_type_p (exp->language_defn,
|
2023-01-31 22:52:09 +08:00
|
|
|
|
arg1->type ())
|
|
|
|
|
&& is_integral_type (arg2->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
arg2 = value_ptradd (arg1, - value_as_long (arg2));
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct value *tmp = arg1;
|
|
|
|
|
|
|
|
|
|
/* For shift and integer exponentiation operations,
|
|
|
|
|
only promote the first argument. */
|
|
|
|
|
if ((op == BINOP_LSH || op == BINOP_RSH || op == BINOP_EXP)
|
2023-01-31 22:52:09 +08:00
|
|
|
|
&& is_integral_type (arg2->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
unop_promote (exp->language_defn, exp->gdbarch, &tmp);
|
|
|
|
|
else
|
|
|
|
|
binop_promote (exp->language_defn, exp->gdbarch, &tmp, &arg2);
|
|
|
|
|
|
|
|
|
|
arg2 = value_binop (tmp, arg2, op);
|
|
|
|
|
}
|
|
|
|
|
return value_assign (arg1, arg2);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* Note that ARGS needs 2 empty slots up front and must end with a
|
|
|
|
|
null pointer. */
|
|
|
|
|
static struct value *
|
|
|
|
|
eval_op_objc_msgcall (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, CORE_ADDR selector,
|
|
|
|
|
value *target, gdb::array_view<value *> args)
|
|
|
|
|
{
|
|
|
|
|
CORE_ADDR responds_selector = 0;
|
|
|
|
|
CORE_ADDR method_selector = 0;
|
|
|
|
|
|
|
|
|
|
int struct_return = 0;
|
|
|
|
|
|
|
|
|
|
struct value *msg_send = NULL;
|
|
|
|
|
struct value *msg_send_stret = NULL;
|
|
|
|
|
int gnu_runtime = 0;
|
|
|
|
|
|
|
|
|
|
struct value *method = NULL;
|
|
|
|
|
struct value *called_method = NULL;
|
|
|
|
|
|
|
|
|
|
struct type *selector_type = NULL;
|
|
|
|
|
struct type *long_type;
|
|
|
|
|
struct type *type;
|
|
|
|
|
|
|
|
|
|
struct value *ret = NULL;
|
|
|
|
|
CORE_ADDR addr = 0;
|
|
|
|
|
|
|
|
|
|
value *argvec[5];
|
|
|
|
|
|
|
|
|
|
long_type = builtin_type (exp->gdbarch)->builtin_long;
|
|
|
|
|
selector_type = builtin_type (exp->gdbarch)->builtin_data_ptr;
|
|
|
|
|
|
|
|
|
|
if (value_as_long (target) == 0)
|
|
|
|
|
return value_from_longest (long_type, 0);
|
|
|
|
|
|
2024-07-17 11:52:02 +08:00
|
|
|
|
if (lookup_minimal_symbol (current_program_space, "objc_msg_lookup").minsym
|
|
|
|
|
!= nullptr)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
gnu_runtime = 1;
|
|
|
|
|
|
|
|
|
|
/* Find the method dispatch (Apple runtime) or method lookup
|
|
|
|
|
(GNU runtime) function for Objective-C. These will be used
|
|
|
|
|
to lookup the symbol information for the method. If we
|
|
|
|
|
can't find any symbol information, then we'll use these to
|
|
|
|
|
call the method, otherwise we can call the method
|
|
|
|
|
directly. The msg_send_stret function is used in the special
|
|
|
|
|
case of a method that returns a structure (Apple runtime
|
|
|
|
|
only). */
|
|
|
|
|
if (gnu_runtime)
|
|
|
|
|
{
|
|
|
|
|
type = selector_type;
|
|
|
|
|
|
|
|
|
|
type = lookup_function_type (type);
|
|
|
|
|
type = lookup_pointer_type (type);
|
|
|
|
|
type = lookup_function_type (type);
|
|
|
|
|
type = lookup_pointer_type (type);
|
|
|
|
|
|
|
|
|
|
msg_send = find_function_in_inferior ("objc_msg_lookup", NULL);
|
|
|
|
|
msg_send_stret
|
|
|
|
|
= find_function_in_inferior ("objc_msg_lookup", NULL);
|
|
|
|
|
|
|
|
|
|
msg_send = value_from_pointer (type, value_as_address (msg_send));
|
|
|
|
|
msg_send_stret = value_from_pointer (type,
|
|
|
|
|
value_as_address (msg_send_stret));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
msg_send = find_function_in_inferior ("objc_msgSend", NULL);
|
|
|
|
|
/* Special dispatcher for methods returning structs. */
|
|
|
|
|
msg_send_stret
|
|
|
|
|
= find_function_in_inferior ("objc_msgSend_stret", NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Verify the target object responds to this method. The
|
|
|
|
|
standard top-level 'Object' class uses a different name for
|
|
|
|
|
the verification method than the non-standard, but more
|
|
|
|
|
often used, 'NSObject' class. Make sure we check for both. */
|
|
|
|
|
|
|
|
|
|
responds_selector
|
|
|
|
|
= lookup_child_selector (exp->gdbarch, "respondsToSelector:");
|
|
|
|
|
if (responds_selector == 0)
|
|
|
|
|
responds_selector
|
|
|
|
|
= lookup_child_selector (exp->gdbarch, "respondsTo:");
|
|
|
|
|
|
|
|
|
|
if (responds_selector == 0)
|
|
|
|
|
error (_("no 'respondsTo:' or 'respondsToSelector:' method"));
|
|
|
|
|
|
|
|
|
|
method_selector
|
|
|
|
|
= lookup_child_selector (exp->gdbarch, "methodForSelector:");
|
|
|
|
|
if (method_selector == 0)
|
|
|
|
|
method_selector
|
|
|
|
|
= lookup_child_selector (exp->gdbarch, "methodFor:");
|
|
|
|
|
|
|
|
|
|
if (method_selector == 0)
|
|
|
|
|
error (_("no 'methodFor:' or 'methodForSelector:' method"));
|
|
|
|
|
|
|
|
|
|
/* Call the verification method, to make sure that the target
|
|
|
|
|
class implements the desired method. */
|
|
|
|
|
|
|
|
|
|
argvec[0] = msg_send;
|
|
|
|
|
argvec[1] = target;
|
|
|
|
|
argvec[2] = value_from_longest (long_type, responds_selector);
|
|
|
|
|
argvec[3] = value_from_longest (long_type, selector);
|
|
|
|
|
argvec[4] = 0;
|
|
|
|
|
|
|
|
|
|
ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
|
|
|
|
|
if (gnu_runtime)
|
|
|
|
|
{
|
|
|
|
|
/* Function objc_msg_lookup returns a pointer. */
|
|
|
|
|
argvec[0] = ret;
|
|
|
|
|
ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
|
|
|
|
|
}
|
|
|
|
|
if (value_as_long (ret) == 0)
|
|
|
|
|
error (_("Target does not respond to this message selector."));
|
|
|
|
|
|
|
|
|
|
/* Call "methodForSelector:" method, to get the address of a
|
|
|
|
|
function method that implements this selector for this
|
|
|
|
|
class. If we can find a symbol at that address, then we
|
|
|
|
|
know the return type, parameter types etc. (that's a good
|
|
|
|
|
thing). */
|
|
|
|
|
|
|
|
|
|
argvec[0] = msg_send;
|
|
|
|
|
argvec[1] = target;
|
|
|
|
|
argvec[2] = value_from_longest (long_type, method_selector);
|
|
|
|
|
argvec[3] = value_from_longest (long_type, selector);
|
|
|
|
|
argvec[4] = 0;
|
|
|
|
|
|
|
|
|
|
ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
|
|
|
|
|
if (gnu_runtime)
|
|
|
|
|
{
|
|
|
|
|
argvec[0] = ret;
|
|
|
|
|
ret = call_function_by_hand (argvec[0], NULL, {argvec + 1, 3});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ret should now be the selector. */
|
|
|
|
|
|
|
|
|
|
addr = value_as_long (ret);
|
|
|
|
|
if (addr)
|
|
|
|
|
{
|
|
|
|
|
struct symbol *sym = NULL;
|
|
|
|
|
|
|
|
|
|
/* The address might point to a function descriptor;
|
|
|
|
|
resolve it to the actual code address instead. */
|
2021-03-25 06:08:12 +08:00
|
|
|
|
addr = gdbarch_convert_from_func_ptr_addr
|
|
|
|
|
(exp->gdbarch, addr, current_inferior ()->top_target ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
/* Is it a high_level symbol? */
|
|
|
|
|
sym = find_pc_function (addr);
|
|
|
|
|
if (sym != NULL)
|
|
|
|
|
method = value_of_variable (sym, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we found a method with symbol information, check to see
|
|
|
|
|
if it returns a struct. Otherwise assume it doesn't. */
|
|
|
|
|
|
|
|
|
|
if (method)
|
|
|
|
|
{
|
|
|
|
|
CORE_ADDR funaddr;
|
|
|
|
|
struct type *val_type;
|
|
|
|
|
|
|
|
|
|
funaddr = find_function_addr (method, &val_type);
|
|
|
|
|
|
|
|
|
|
block_for_pc (funaddr);
|
|
|
|
|
|
|
|
|
|
val_type = check_typedef (val_type);
|
|
|
|
|
|
|
|
|
|
if ((val_type == NULL)
|
|
|
|
|
|| (val_type->code () == TYPE_CODE_ERROR))
|
|
|
|
|
{
|
|
|
|
|
if (expect_type != NULL)
|
|
|
|
|
val_type = expect_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct_return = using_struct_return (exp->gdbarch, method,
|
|
|
|
|
val_type);
|
|
|
|
|
}
|
|
|
|
|
else if (expect_type != NULL)
|
|
|
|
|
{
|
|
|
|
|
struct_return = using_struct_return (exp->gdbarch, NULL,
|
|
|
|
|
check_typedef (expect_type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Found a function symbol. Now we will substitute its
|
|
|
|
|
value in place of the message dispatcher (obj_msgSend),
|
|
|
|
|
so that we call the method directly instead of thru
|
|
|
|
|
the dispatcher. The main reason for doing this is that
|
|
|
|
|
we can now evaluate the return value and parameter values
|
|
|
|
|
according to their known data types, in case we need to
|
|
|
|
|
do things like promotion, dereferencing, special handling
|
|
|
|
|
of structs and doubles, etc.
|
|
|
|
|
|
|
|
|
|
We want to use the type signature of 'method', but still
|
|
|
|
|
jump to objc_msgSend() or objc_msgSend_stret() to better
|
|
|
|
|
mimic the behavior of the runtime. */
|
|
|
|
|
|
|
|
|
|
if (method)
|
|
|
|
|
{
|
2023-01-31 22:52:09 +08:00
|
|
|
|
if (method->type ()->code () != TYPE_CODE_FUNC)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
error (_("method address has symbol information "
|
|
|
|
|
"with non-function type; skipping"));
|
|
|
|
|
|
|
|
|
|
/* Create a function pointer of the appropriate type, and
|
|
|
|
|
replace its value with the value of msg_send or
|
|
|
|
|
msg_send_stret. We must use a pointer here, as
|
|
|
|
|
msg_send and msg_send_stret are of pointer type, and
|
|
|
|
|
the representation may be different on systems that use
|
|
|
|
|
function descriptors. */
|
|
|
|
|
if (struct_return)
|
|
|
|
|
called_method
|
2023-01-31 22:52:09 +08:00
|
|
|
|
= value_from_pointer (lookup_pointer_type (method->type ()),
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value_as_address (msg_send_stret));
|
|
|
|
|
else
|
|
|
|
|
called_method
|
2023-01-31 22:52:09 +08:00
|
|
|
|
= value_from_pointer (lookup_pointer_type (method->type ()),
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value_as_address (msg_send));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (struct_return)
|
|
|
|
|
called_method = msg_send_stret;
|
|
|
|
|
else
|
|
|
|
|
called_method = msg_send;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
{
|
|
|
|
|
/* If the return type doesn't look like a function type,
|
|
|
|
|
call an error. This can happen if somebody tries to
|
|
|
|
|
turn a variable into a function call. This is here
|
|
|
|
|
because people often want to call, eg, strcmp, which
|
|
|
|
|
gdb doesn't know is a function. If gdb isn't asked for
|
|
|
|
|
it's opinion (ie. through "whatis"), it won't offer
|
|
|
|
|
it. */
|
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *callee_type = called_method->type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
if (callee_type && callee_type->code () == TYPE_CODE_PTR)
|
2022-07-31 10:43:54 +08:00
|
|
|
|
callee_type = callee_type->target_type ();
|
|
|
|
|
callee_type = callee_type->target_type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
if (callee_type)
|
|
|
|
|
{
|
|
|
|
|
if ((callee_type->code () == TYPE_CODE_ERROR) && expect_type)
|
2023-02-01 04:25:17 +08:00
|
|
|
|
return value::allocate (expect_type);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
else
|
2023-02-01 04:25:17 +08:00
|
|
|
|
return value::allocate (callee_type);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
error (_("Expression of type other than "
|
|
|
|
|
"\"method returning ...\" used as a method"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now depending on whether we found a symbol for the method,
|
|
|
|
|
we will either call the runtime dispatcher or the method
|
|
|
|
|
directly. */
|
|
|
|
|
|
|
|
|
|
args[0] = target;
|
|
|
|
|
args[1] = value_from_longest (long_type, selector);
|
|
|
|
|
|
|
|
|
|
if (gnu_runtime && (method != NULL))
|
|
|
|
|
{
|
|
|
|
|
/* Function objc_msg_lookup returns a pointer. */
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *tem_type = called_method->type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
tem_type = lookup_pointer_type (lookup_function_type (tem_type));
|
2023-01-31 23:24:35 +08:00
|
|
|
|
called_method->deprecated_set_type (tem_type);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
called_method = call_function_by_hand (called_method, NULL, args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return call_function_by_hand (called_method, NULL, args);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* Helper function for MULTI_SUBSCRIPT. */
|
|
|
|
|
|
|
|
|
|
static struct value *
|
|
|
|
|
eval_multi_subscript (struct type *expect_type, struct expression *exp,
|
|
|
|
|
enum noside noside, value *arg1,
|
|
|
|
|
gdb::array_view<value *> args)
|
|
|
|
|
{
|
|
|
|
|
for (value *arg2 : args)
|
|
|
|
|
{
|
|
|
|
|
if (binop_user_defined_p (MULTI_SUBSCRIPT, arg1, arg2))
|
|
|
|
|
{
|
|
|
|
|
arg1 = value_x_binop (arg1, arg2, MULTI_SUBSCRIPT, OP_NULL, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
arg1 = coerce_ref (arg1);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = check_typedef (arg1->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
switch (type->code ())
|
|
|
|
|
{
|
|
|
|
|
case TYPE_CODE_PTR:
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
|
|
|
|
case TYPE_CODE_STRING:
|
|
|
|
|
arg1 = value_subscript (arg1, value_as_long (arg2));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
if (type->name ())
|
|
|
|
|
error (_("cannot subscript something of type `%s'"),
|
|
|
|
|
type->name ());
|
|
|
|
|
else
|
|
|
|
|
error (_("cannot subscript requested type"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (arg1);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
namespace expr
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
objc_msgcall_operation::evaluate (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
enum noside sub_no_side = EVAL_NORMAL;
|
|
|
|
|
struct type *selector_type = builtin_type (exp->gdbarch)->builtin_data_ptr;
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
sub_no_side = EVAL_NORMAL;
|
|
|
|
|
else
|
|
|
|
|
sub_no_side = noside;
|
|
|
|
|
value *target
|
|
|
|
|
= std::get<1> (m_storage)->evaluate (selector_type, exp, sub_no_side);
|
|
|
|
|
|
|
|
|
|
if (value_as_long (target) == 0)
|
|
|
|
|
sub_no_side = EVAL_AVOID_SIDE_EFFECTS;
|
|
|
|
|
else
|
|
|
|
|
sub_no_side = noside;
|
|
|
|
|
std::vector<operation_up> &args = std::get<2> (m_storage);
|
|
|
|
|
value **argvec = XALLOCAVEC (struct value *, args.size () + 3);
|
|
|
|
|
argvec[0] = nullptr;
|
|
|
|
|
argvec[1] = nullptr;
|
|
|
|
|
for (int i = 0; i < args.size (); ++i)
|
|
|
|
|
argvec[i + 2] = args[i]->evaluate_with_coercion (exp, sub_no_side);
|
|
|
|
|
argvec[args.size () + 2] = nullptr;
|
|
|
|
|
|
|
|
|
|
return eval_op_objc_msgcall (expect_type, exp, noside, std::
|
|
|
|
|
get<0> (m_storage), target,
|
|
|
|
|
gdb::make_array_view (argvec,
|
|
|
|
|
args.size () + 3));
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
multi_subscript_operation::evaluate (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *arg1 = std::get<0> (m_storage)->evaluate_with_coercion (exp, noside);
|
|
|
|
|
std::vector<operation_up> &values = std::get<1> (m_storage);
|
|
|
|
|
value **argvec = XALLOCAVEC (struct value *, values.size ());
|
|
|
|
|
for (int ix = 0; ix < values.size (); ++ix)
|
|
|
|
|
argvec[ix] = values[ix]->evaluate_with_coercion (exp, noside);
|
|
|
|
|
return eval_multi_subscript (expect_type, exp, noside, arg1,
|
|
|
|
|
gdb::make_array_view (argvec, values.size ()));
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
logical_and_operation::evaluate (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
|
|
|
|
|
value *arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp,
|
|
|
|
|
EVAL_AVOID_SIDE_EFFECTS);
|
|
|
|
|
|
|
|
|
|
if (binop_user_defined_p (BINOP_LOGICAL_AND, arg1, arg2))
|
|
|
|
|
{
|
|
|
|
|
arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
return value_x_binop (arg1, arg2, BINOP_LOGICAL_AND, OP_NULL, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-08-27 08:17:40 +08:00
|
|
|
|
bool tem = value_logical_not (arg1);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (!tem)
|
|
|
|
|
{
|
|
|
|
|
arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
tem = value_logical_not (arg2);
|
|
|
|
|
}
|
|
|
|
|
struct type *type = language_bool_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch);
|
|
|
|
|
return value_from_longest (type, !tem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
logical_or_operation::evaluate (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
|
|
|
|
|
value *arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp,
|
|
|
|
|
EVAL_AVOID_SIDE_EFFECTS);
|
|
|
|
|
|
|
|
|
|
if (binop_user_defined_p (BINOP_LOGICAL_OR, arg1, arg2))
|
|
|
|
|
{
|
|
|
|
|
arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
return value_x_binop (arg1, arg2, BINOP_LOGICAL_OR, OP_NULL, noside);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-08-27 08:17:40 +08:00
|
|
|
|
bool tem = value_logical_not (arg1);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (tem)
|
|
|
|
|
{
|
|
|
|
|
arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
tem = value_logical_not (arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct type *type = language_bool_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch);
|
|
|
|
|
return value_from_longest (type, !tem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
adl_func_operation::evaluate (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
std::vector<operation_up> &arg_ops = std::get<2> (m_storage);
|
|
|
|
|
std::vector<value *> args (arg_ops.size ());
|
|
|
|
|
for (int i = 0; i < arg_ops.size (); ++i)
|
|
|
|
|
args[i] = arg_ops[i]->evaluate_with_coercion (exp, noside);
|
|
|
|
|
|
|
|
|
|
struct symbol *symp;
|
|
|
|
|
find_overload_match (args, std::get<0> (m_storage).c_str (),
|
|
|
|
|
NON_METHOD,
|
|
|
|
|
nullptr, nullptr,
|
|
|
|
|
nullptr, &symp, nullptr, 0, noside);
|
2022-01-28 11:16:41 +08:00
|
|
|
|
if (symp->type ()->code () == TYPE_CODE_ERROR)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
error_unknown_type (symp->print_name ());
|
|
|
|
|
value *callee = evaluate_var_value (noside, std::get<1> (m_storage), symp);
|
|
|
|
|
return evaluate_subexp_do_call (exp, noside, callee, args,
|
|
|
|
|
nullptr, expect_type);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* This function evaluates brace-initializers (in C/C++) for
|
|
|
|
|
structure types. */
|
|
|
|
|
|
|
|
|
|
struct value *
|
|
|
|
|
array_operation::evaluate_struct_tuple (struct value *struct_val,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside, int nargs)
|
|
|
|
|
{
|
|
|
|
|
const std::vector<operation_up> &in_args = std::get<2> (m_storage);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *struct_type = check_typedef (struct_val->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct type *field_type;
|
|
|
|
|
int fieldno = -1;
|
|
|
|
|
|
|
|
|
|
int idx = 0;
|
|
|
|
|
while (--nargs >= 0)
|
|
|
|
|
{
|
|
|
|
|
struct value *val = NULL;
|
|
|
|
|
int bitpos, bitsize;
|
|
|
|
|
bfd_byte *addr;
|
|
|
|
|
|
|
|
|
|
fieldno++;
|
|
|
|
|
/* Skip static fields. */
|
|
|
|
|
while (fieldno < struct_type->num_fields ()
|
2023-04-23 02:41:43 +08:00
|
|
|
|
&& struct_type->field (fieldno).is_static ())
|
2021-03-08 22:27:57 +08:00
|
|
|
|
fieldno++;
|
|
|
|
|
if (fieldno >= struct_type->num_fields ())
|
|
|
|
|
error (_("too many initializers"));
|
|
|
|
|
field_type = struct_type->field (fieldno).type ();
|
|
|
|
|
if (field_type->code () == TYPE_CODE_UNION
|
2021-08-30 23:49:49 +08:00
|
|
|
|
&& struct_type->field (fieldno).name ()[0] == '0')
|
2021-03-08 22:27:57 +08:00
|
|
|
|
error (_("don't know which variant you want to set"));
|
|
|
|
|
|
|
|
|
|
/* Here, struct_type is the type of the inner struct,
|
|
|
|
|
while substruct_type is the type of the inner struct.
|
|
|
|
|
These are the same for normal structures, but a variant struct
|
|
|
|
|
contains anonymous union fields that contain substruct fields.
|
|
|
|
|
The value fieldno is the index of the top-level (normal or
|
|
|
|
|
anonymous union) field in struct_field, while the value
|
|
|
|
|
subfieldno is the index of the actual real (named inner) field
|
|
|
|
|
in substruct_type. */
|
|
|
|
|
|
|
|
|
|
field_type = struct_type->field (fieldno).type ();
|
|
|
|
|
if (val == 0)
|
|
|
|
|
val = in_args[idx++]->evaluate (field_type, exp, noside);
|
|
|
|
|
|
|
|
|
|
/* Now actually set the field in struct_val. */
|
|
|
|
|
|
|
|
|
|
/* Assign val to field fieldno. */
|
2023-01-31 22:52:09 +08:00
|
|
|
|
if (val->type () != field_type)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
val = value_cast (field_type, val);
|
|
|
|
|
|
2023-08-31 23:46:27 +08:00
|
|
|
|
bitsize = struct_type->field (fieldno).bitsize ();
|
2021-09-27 04:36:15 +08:00
|
|
|
|
bitpos = struct_type->field (fieldno).loc_bitpos ();
|
2023-02-01 04:45:40 +08:00
|
|
|
|
addr = struct_val->contents_writeable ().data () + bitpos / 8;
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (bitsize)
|
|
|
|
|
modify_field (struct_type, addr,
|
|
|
|
|
value_as_long (val), bitpos % 8, bitsize);
|
|
|
|
|
else
|
2023-02-01 05:38:30 +08:00
|
|
|
|
memcpy (addr, val->contents ().data (),
|
2023-01-31 22:52:09 +08:00
|
|
|
|
val->type ()->length ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return struct_val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
array_operation::evaluate (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
2023-08-29 23:18:42 +08:00
|
|
|
|
const int provided_low_bound = std::get<0> (m_storage);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
const std::vector<operation_up> &in_args = std::get<2> (m_storage);
|
2023-08-29 23:18:42 +08:00
|
|
|
|
const int nargs = std::get<1> (m_storage) - provided_low_bound + 1;
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct type *type = expect_type ? check_typedef (expect_type) : nullptr;
|
|
|
|
|
|
Remove EVAL_SKIP
EVAL_SKIP was needed in the old expression implementation due to its
linearized tree structure. This is not needed in the new
implementation, because it is trivial to not evaluate a subexpression.
This patch removes the last vestiges of EVAL_SKIP.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (eval_skip_value): Don't declare.
* opencl-lang.c (eval_opencl_assign): Update.
* m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): Update.
* f-lang.c (eval_op_f_abs, eval_op_f_mod, eval_op_f_ceil)
(eval_op_f_floor, eval_op_f_modulo, eval_op_f_cmplx): Remove.
* expression.h (enum noside) <EVAL_SKIP>: Remove.
* expop.h (typeof_operation::evaluate)
(decltype_operation::evaluate, unop_addr_operation::evaluate)
(unop_sizeof_operation::evaluate, assign_operation::evaluate)
(cxx_cast_operation::evaluate): Update.
* eval.c (eval_skip_value): Remove.
(eval_op_scope, eval_op_var_entry_value)
(eval_op_func_static_var, eval_op_string, eval_op_objc_selector)
(eval_op_concat, eval_op_ternop, eval_op_structop_struct)
(eval_op_structop_ptr, eval_op_member, eval_op_add, eval_op_sub)
(eval_op_binary, eval_op_subscript, eval_op_equal)
(eval_op_notequal, eval_op_less, eval_op_gtr, eval_op_geq)
(eval_op_leq, eval_op_repeat, eval_op_plus, eval_op_neg)
(eval_op_complement, eval_op_lognot, eval_op_ind)
(eval_op_memval, eval_op_preinc, eval_op_predec)
(eval_op_postinc, eval_op_postdec, eval_op_type)
(eval_binop_assign_modify, eval_op_objc_msgcall)
(eval_multi_subscript, logical_and_operation::evaluate)
(logical_or_operation::evaluate, array_operation::evaluate)
(operation::evaluate_for_cast)
(var_msym_value_operation::evaluate_for_cast)
(var_value_operation::evaluate_for_cast): Update.
* c-lang.c (c_string_operation::evaluate): Update.
* c-exp.h (objc_nsstring_operation::evaluate)
(objc_selector_operation::evaluate): Update.
* ada-lang.c (ada_assign_operation::evaluate)
(eval_ternop_in_range, ada_unop_neg, ada_unop_in_range)
(ada_atr_size): Update.
2021-03-08 22:27:57 +08:00
|
|
|
|
if (expect_type != nullptr
|
2021-03-08 22:27:57 +08:00
|
|
|
|
&& type->code () == TYPE_CODE_STRUCT)
|
|
|
|
|
{
|
2023-02-01 04:25:17 +08:00
|
|
|
|
struct value *rec = value::allocate (expect_type);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
2023-02-01 04:45:40 +08:00
|
|
|
|
memset (rec->contents_raw ().data (), '\0', type->length ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return evaluate_struct_tuple (rec, exp, noside, nargs);
|
|
|
|
|
}
|
|
|
|
|
|
Remove EVAL_SKIP
EVAL_SKIP was needed in the old expression implementation due to its
linearized tree structure. This is not needed in the new
implementation, because it is trivial to not evaluate a subexpression.
This patch removes the last vestiges of EVAL_SKIP.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (eval_skip_value): Don't declare.
* opencl-lang.c (eval_opencl_assign): Update.
* m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): Update.
* f-lang.c (eval_op_f_abs, eval_op_f_mod, eval_op_f_ceil)
(eval_op_f_floor, eval_op_f_modulo, eval_op_f_cmplx): Remove.
* expression.h (enum noside) <EVAL_SKIP>: Remove.
* expop.h (typeof_operation::evaluate)
(decltype_operation::evaluate, unop_addr_operation::evaluate)
(unop_sizeof_operation::evaluate, assign_operation::evaluate)
(cxx_cast_operation::evaluate): Update.
* eval.c (eval_skip_value): Remove.
(eval_op_scope, eval_op_var_entry_value)
(eval_op_func_static_var, eval_op_string, eval_op_objc_selector)
(eval_op_concat, eval_op_ternop, eval_op_structop_struct)
(eval_op_structop_ptr, eval_op_member, eval_op_add, eval_op_sub)
(eval_op_binary, eval_op_subscript, eval_op_equal)
(eval_op_notequal, eval_op_less, eval_op_gtr, eval_op_geq)
(eval_op_leq, eval_op_repeat, eval_op_plus, eval_op_neg)
(eval_op_complement, eval_op_lognot, eval_op_ind)
(eval_op_memval, eval_op_preinc, eval_op_predec)
(eval_op_postinc, eval_op_postdec, eval_op_type)
(eval_binop_assign_modify, eval_op_objc_msgcall)
(eval_multi_subscript, logical_and_operation::evaluate)
(logical_or_operation::evaluate, array_operation::evaluate)
(operation::evaluate_for_cast)
(var_msym_value_operation::evaluate_for_cast)
(var_value_operation::evaluate_for_cast): Update.
* c-lang.c (c_string_operation::evaluate): Update.
* c-exp.h (objc_nsstring_operation::evaluate)
(objc_selector_operation::evaluate): Update.
* ada-lang.c (ada_assign_operation::evaluate)
(eval_ternop_in_range, ada_unop_neg, ada_unop_in_range)
(ada_atr_size): Update.
2021-03-08 22:27:57 +08:00
|
|
|
|
if (expect_type != nullptr
|
2021-03-08 22:27:57 +08:00
|
|
|
|
&& type->code () == TYPE_CODE_ARRAY)
|
|
|
|
|
{
|
|
|
|
|
struct type *range_type = type->index_type ();
|
2022-07-31 10:43:54 +08:00
|
|
|
|
struct type *element_type = type->target_type ();
|
2023-02-01 04:25:17 +08:00
|
|
|
|
struct value *array = value::allocate (expect_type);
|
2022-09-21 23:05:21 +08:00
|
|
|
|
int element_size = check_typedef (element_type)->length ();
|
2023-08-29 02:52:54 +08:00
|
|
|
|
LONGEST low_bound, high_bound;
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
if (!get_discrete_bounds (range_type, &low_bound, &high_bound))
|
|
|
|
|
{
|
|
|
|
|
low_bound = 0;
|
2022-09-21 23:05:21 +08:00
|
|
|
|
high_bound = (type->length () / element_size) - 1;
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
2023-08-29 03:39:33 +08:00
|
|
|
|
if (low_bound + nargs - 1 > high_bound)
|
|
|
|
|
error (_("Too many array elements"));
|
2023-02-01 04:45:40 +08:00
|
|
|
|
memset (array->contents_raw ().data (), 0, expect_type->length ());
|
2023-08-29 02:52:54 +08:00
|
|
|
|
for (int idx = 0; idx < nargs; ++idx)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
{
|
|
|
|
|
struct value *element;
|
|
|
|
|
|
2023-08-29 02:52:54 +08:00
|
|
|
|
element = in_args[idx]->evaluate (element_type, exp, noside);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
if (element->type () != element_type)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
element = value_cast (element_type, element);
|
2023-08-29 02:52:54 +08:00
|
|
|
|
memcpy (array->contents_raw ().data () + idx * element_size,
|
2023-02-01 05:38:30 +08:00
|
|
|
|
element->contents ().data (),
|
2021-03-08 22:27:57 +08:00
|
|
|
|
element_size);
|
|
|
|
|
}
|
|
|
|
|
return array;
|
|
|
|
|
}
|
|
|
|
|
|
Remove EVAL_SKIP
EVAL_SKIP was needed in the old expression implementation due to its
linearized tree structure. This is not needed in the new
implementation, because it is trivial to not evaluate a subexpression.
This patch removes the last vestiges of EVAL_SKIP.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (eval_skip_value): Don't declare.
* opencl-lang.c (eval_opencl_assign): Update.
* m2-lang.c (eval_op_m2_high, eval_op_m2_subscript): Update.
* f-lang.c (eval_op_f_abs, eval_op_f_mod, eval_op_f_ceil)
(eval_op_f_floor, eval_op_f_modulo, eval_op_f_cmplx): Remove.
* expression.h (enum noside) <EVAL_SKIP>: Remove.
* expop.h (typeof_operation::evaluate)
(decltype_operation::evaluate, unop_addr_operation::evaluate)
(unop_sizeof_operation::evaluate, assign_operation::evaluate)
(cxx_cast_operation::evaluate): Update.
* eval.c (eval_skip_value): Remove.
(eval_op_scope, eval_op_var_entry_value)
(eval_op_func_static_var, eval_op_string, eval_op_objc_selector)
(eval_op_concat, eval_op_ternop, eval_op_structop_struct)
(eval_op_structop_ptr, eval_op_member, eval_op_add, eval_op_sub)
(eval_op_binary, eval_op_subscript, eval_op_equal)
(eval_op_notequal, eval_op_less, eval_op_gtr, eval_op_geq)
(eval_op_leq, eval_op_repeat, eval_op_plus, eval_op_neg)
(eval_op_complement, eval_op_lognot, eval_op_ind)
(eval_op_memval, eval_op_preinc, eval_op_predec)
(eval_op_postinc, eval_op_postdec, eval_op_type)
(eval_binop_assign_modify, eval_op_objc_msgcall)
(eval_multi_subscript, logical_and_operation::evaluate)
(logical_or_operation::evaluate, array_operation::evaluate)
(operation::evaluate_for_cast)
(var_msym_value_operation::evaluate_for_cast)
(var_value_operation::evaluate_for_cast): Update.
* c-lang.c (c_string_operation::evaluate): Update.
* c-exp.h (objc_nsstring_operation::evaluate)
(objc_selector_operation::evaluate): Update.
* ada-lang.c (ada_assign_operation::evaluate)
(eval_ternop_in_range, ada_unop_neg, ada_unop_in_range)
(ada_atr_size): Update.
2021-03-08 22:27:57 +08:00
|
|
|
|
if (expect_type != nullptr
|
2021-03-08 22:27:57 +08:00
|
|
|
|
&& type->code () == TYPE_CODE_SET)
|
|
|
|
|
{
|
2023-02-01 04:25:17 +08:00
|
|
|
|
struct value *set = value::allocate (expect_type);
|
2023-02-01 04:45:40 +08:00
|
|
|
|
gdb_byte *valaddr = set->contents_raw ().data ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
struct type *element_type = type->index_type ();
|
|
|
|
|
struct type *check_type = element_type;
|
|
|
|
|
LONGEST low_bound, high_bound;
|
|
|
|
|
|
|
|
|
|
/* Get targettype of elementtype. */
|
|
|
|
|
while (check_type->code () == TYPE_CODE_RANGE
|
|
|
|
|
|| check_type->code () == TYPE_CODE_TYPEDEF)
|
2022-07-31 10:43:54 +08:00
|
|
|
|
check_type = check_type->target_type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
if (!get_discrete_bounds (element_type, &low_bound, &high_bound))
|
|
|
|
|
error (_("(power)set type with unknown size"));
|
2022-09-21 23:05:21 +08:00
|
|
|
|
memset (valaddr, '\0', type->length ());
|
2023-08-29 02:43:35 +08:00
|
|
|
|
for (int idx = 0; idx < nargs; idx++)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
{
|
|
|
|
|
LONGEST range_low, range_high;
|
|
|
|
|
struct type *range_low_type, *range_high_type;
|
|
|
|
|
struct value *elem_val;
|
|
|
|
|
|
2023-08-29 02:43:35 +08:00
|
|
|
|
elem_val = in_args[idx]->evaluate (element_type, exp, noside);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
range_low_type = range_high_type = elem_val->type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
range_low = range_high = value_as_long (elem_val);
|
|
|
|
|
|
|
|
|
|
/* Check types of elements to avoid mixture of elements from
|
|
|
|
|
different types. Also check if type of element is "compatible"
|
|
|
|
|
with element type of powerset. */
|
|
|
|
|
if (range_low_type->code () == TYPE_CODE_RANGE)
|
2022-07-31 10:43:54 +08:00
|
|
|
|
range_low_type = range_low_type->target_type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (range_high_type->code () == TYPE_CODE_RANGE)
|
2022-07-31 10:43:54 +08:00
|
|
|
|
range_high_type = range_high_type->target_type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if ((range_low_type->code () != range_high_type->code ())
|
|
|
|
|
|| (range_low_type->code () == TYPE_CODE_ENUM
|
|
|
|
|
&& (range_low_type != range_high_type)))
|
|
|
|
|
/* different element modes. */
|
|
|
|
|
error (_("POWERSET tuple elements of different mode"));
|
|
|
|
|
if ((check_type->code () != range_low_type->code ())
|
|
|
|
|
|| (check_type->code () == TYPE_CODE_ENUM
|
|
|
|
|
&& range_low_type != check_type))
|
|
|
|
|
error (_("incompatible POWERSET tuple elements"));
|
|
|
|
|
if (range_low > range_high)
|
|
|
|
|
{
|
|
|
|
|
warning (_("empty POWERSET tuple range"));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (range_low < low_bound || range_high > high_bound)
|
|
|
|
|
error (_("POWERSET tuple element out of range"));
|
|
|
|
|
range_low -= low_bound;
|
|
|
|
|
range_high -= low_bound;
|
|
|
|
|
for (; range_low <= range_high; range_low++)
|
|
|
|
|
{
|
|
|
|
|
int bit_index = (unsigned) range_low % TARGET_CHAR_BIT;
|
|
|
|
|
|
|
|
|
|
if (gdbarch_byte_order (exp->gdbarch) == BFD_ENDIAN_BIG)
|
|
|
|
|
bit_index = TARGET_CHAR_BIT - 1 - bit_index;
|
|
|
|
|
valaddr[(unsigned) range_low / TARGET_CHAR_BIT]
|
|
|
|
|
|= 1 << bit_index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return set;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-29 02:40:35 +08:00
|
|
|
|
std::vector<value *> argvec (nargs);
|
2023-08-29 02:42:51 +08:00
|
|
|
|
for (int tem = 0; tem < nargs; tem++)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
{
|
|
|
|
|
/* Ensure that array expressions are coerced into pointer
|
|
|
|
|
objects. */
|
|
|
|
|
argvec[tem] = in_args[tem]->evaluate_with_coercion (exp, noside);
|
|
|
|
|
}
|
2023-08-29 23:18:42 +08:00
|
|
|
|
return value_array (provided_low_bound, argvec);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
gdb/x86: handle stap probe arguments in xmm registers
On x86 machines with xmm register, and with recent versions of
systemtap (and gcc?), it can occur that stap probe arguments will be
placed into xmm registers.
I notice this happening on a current Fedora Rawhide install with the
following package versions installed:
$ rpm -q glibc systemtap gcc
glibc-2.35.9000-10.fc37.x86_64
systemtap-4.7~pre16468670g9f253544-1.fc37.x86_64
gcc-12.0.1-0.12.fc37.x86_64
If I check the probe data in libc, I see this:
$ readelf -n /lib64/libc.so.6
...
stapsdt 0x0000004d NT_STAPSDT (SystemTap probe descriptors)
Provider: libc
Name: pthread_start
Location: 0x0000000000090ac3, Base: 0x00000000001c65c4, Semaphore: 0x0000000000000000
Arguments: 8@%xmm1 8@1600(%rbx) 8@1608(%rbx)
stapsdt 0x00000050 NT_STAPSDT (SystemTap probe descriptors)
Provider: libc
Name: pthread_create
Location: 0x00000000000912f1, Base: 0x00000000001c65c4, Semaphore: 0x0000000000000000
Arguments: 8@%xmm1 8@%r13 8@8(%rsp) 8@16(%rsp)
...
Notice that for both of these probes, the first argument is a uint64_t
stored in the xmm1 register.
Unfortunately, if I try to use this probe within GDB, then I can't
view the first argument. Here's an example session:
$ gdb $(which gdb)
(gdb) start
...
(gdb) info probes stap libc pthread_create
...
(gdb) break *0x00007ffff729e2f1 # Use address of probe.
(gdb) continue
...
(gdb) p $_probe_arg0
Invalid cast.
What's going wrong? If I re-run my session, but this time use 'set
debug stap-expression 1', this is what I see:
(gdb) set debug stap-expression 1
(gdb) p $_probe_arg0
Operation: UNOP_CAST
Operation: OP_REGISTER
String: xmm1
Type: uint64_t
Operation: UNOP_CAST
Operation: OP_REGISTER
String: r13
Type: uint64_t
Operation: UNOP_CAST
Operation: UNOP_IND
Operation: UNOP_CAST
Operation: BINOP_ADD
Operation: OP_LONG
Type: long
Constant: 0x0000000000000008
Operation: OP_REGISTER
String: rsp
Type: uint64_t *
Type: uint64_t
Operation: UNOP_CAST
Operation: UNOP_IND
Operation: UNOP_CAST
Operation: BINOP_ADD
Operation: OP_LONG
Type: long
Constant: 0x0000000000000010
Operation: OP_REGISTER
String: rsp
Type: uint64_t *
Type: uint64_t
Invalid cast.
(gdb)
The important bit is this:
Operation: UNOP_CAST
Operation: OP_REGISTER
String: xmm1
Type: uint64_t
Which is where we cast the xmm1 register to uint64_t. And the final
piece of the puzzle is:
(gdb) ptype $xmm1
type = union vec128 {
v8bf16 v8_bfloat16;
v4f v4_float;
v2d v2_double;
v16i8 v16_int8;
v8i16 v8_int16;
v4i32 v4_int32;
v2i64 v2_int64;
uint128_t uint128;
}
So, we are attempting to cast a union type to a scalar type, which is
not supporting in C/C++, and as a consequence GDB's expression
evaluator throws an error when we attempt to do this.
The first approach I considered for solving this problem was to try
and make use of gdbarch_stap_adjust_register. We already have a
gdbarch method (gdbarch_stap_adjust_register) that allows us to tweak
the name of the register that we access. Currently only x86
architectures use this to transform things like ax to eax in some
cases.
I wondered, what if we change gdbarch_stap_adjust_register to do more
than just change the register names? What if this method instead
became gdbarch_stap_read_register. This new method would return a
operation_up, and would take the register name, and the type we are
trying to read from the register, and return the operation that
actually reads the register.
The default implementation of this method would just use
user_reg_map_name_to_regnum, and then create a register_operation,
like we already do in stap_parse_register_operand. But, for x86
architectures this method would fist possibly adjust the register
name, then do the default action to read the register. Finally, for
x86 this method would spot when we were accessing an xmm register,
and, based on the type being pulled from the register, would extract
the correct field from the union.
The benefit of this approach is that it would work with the expression
types that GDB currently supports. The draw back would be that this
approach would not be very generic. We'd need code to handle each
sub-field size with an xmm register. If other architectures started
using vector registers for probe arguments, those architectures would
have to create their own gdbarch_stap_read_register method. And
finally, the type of the xmm registers comes from the type defined in
the target description, there's a risk that GDB might end up
hard-coding the names of type sub-fields, then if a target uses a
different target description, with different field names for xmm
registers, the stap probes would stop working.
And so, based on all the above draw backs, I rejected this first
approach.
My second plan involves adding a new expression type to GDB called
unop_extract_operation. This new expression takes a value and a type,
during evaluation the value contents are fetched, and then a new value
is extracted from the value contents (based on type). This is similar
to the following C expression:
result_value = *((output_type *) &input_value);
Obviously we can't actually build this expression in this case, as the
input_value is in a register, but hopefully the above makes it clearer
what I'm trying to do.
The benefit of the new expression approach is that this code can be
shared across all architectures, and it doesn't care about sub-field
names within the union type.
The draw-backs that I see are potential future problems if arguments
are not stored within the least significant bytes of the register.
However if/when that becomes an issue we can adapt the
gdbarch_stap_read_register approach to allow architectures to control
how a value is extracted.
For testing, I've extended the existing gdb.base/stap-probe.exp test
to include a function that tries to force an argument into an xmm
register. Obviously, that will only work on a x86 target, so I've
guarded the new function with an appropriate GCC define. In the exp
script we use readelf to check if the probe exists, and is using the
xmm register.
If the probe doesn't exist then the associated tests are skipped.
If the probe exists, put isn't using the xmm register (which will
depend on systemtap/gcc versions), then again, the tests are skipped.
Otherwise, we can run the test. I think the cost of running readelf
is pretty low, so I don't feel too bad making all the non-xmm targets
running this step.
I found that on a Fedora 35 install, with these packages installed, I
was able to run this test and have the probe argument be placed in an
xmm register:
$ rpm -q systemtap gcc glibc
systemtap-4.6-4.fc35.x86_64
gcc-11.2.1-9.fc35.x86_64
glibc-2.34-7.fc35.x86_64
Finally, as this patch adds a new operation type, then I need to
consider how to generate an agent expression for the new operation
type.
I have kicked the can down the road a bit on this. In the function
stap_parse_register_operand, I only create a unop_extract_operation in
the case where the register type is non-scalar, this means that in
most cases I don't need to worry about generating an agent expression
at all.
In the xmm register case, when an unop_extract_operation will be
created, I have sketched out how the agent expression could be
handled, however, this code is currently not reached. When we try to
generate the agent expression to place the xmm register on the stack,
GDB hits this error:
(gdb) trace -probe-stap test:xmmreg
Tracepoint 1 at 0x401166
(gdb) actions
Enter actions for tracepoint 1, one per line.
End with a line saying just "end".
>collect $_probe_arg0
Value not scalar: cannot be an rvalue.
This is because GDB doesn't currently support placing non-scalar types
on the agent expression evaluation stack. Solving this is clearly
related to the original problem, but feels a bit like a second
problem. I'd like to get feedback on whether my approach to solving
the original problem is acceptable or not before I start looking at
how to handle xmm registers within agent expressions.
2022-03-11 00:57:18 +08:00
|
|
|
|
value *
|
|
|
|
|
unop_extract_operation::evaluate (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *old_value = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
struct type *type = get_type ();
|
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
if (type->length () > old_value->type ()->length ())
|
gdb/x86: handle stap probe arguments in xmm registers
On x86 machines with xmm register, and with recent versions of
systemtap (and gcc?), it can occur that stap probe arguments will be
placed into xmm registers.
I notice this happening on a current Fedora Rawhide install with the
following package versions installed:
$ rpm -q glibc systemtap gcc
glibc-2.35.9000-10.fc37.x86_64
systemtap-4.7~pre16468670g9f253544-1.fc37.x86_64
gcc-12.0.1-0.12.fc37.x86_64
If I check the probe data in libc, I see this:
$ readelf -n /lib64/libc.so.6
...
stapsdt 0x0000004d NT_STAPSDT (SystemTap probe descriptors)
Provider: libc
Name: pthread_start
Location: 0x0000000000090ac3, Base: 0x00000000001c65c4, Semaphore: 0x0000000000000000
Arguments: 8@%xmm1 8@1600(%rbx) 8@1608(%rbx)
stapsdt 0x00000050 NT_STAPSDT (SystemTap probe descriptors)
Provider: libc
Name: pthread_create
Location: 0x00000000000912f1, Base: 0x00000000001c65c4, Semaphore: 0x0000000000000000
Arguments: 8@%xmm1 8@%r13 8@8(%rsp) 8@16(%rsp)
...
Notice that for both of these probes, the first argument is a uint64_t
stored in the xmm1 register.
Unfortunately, if I try to use this probe within GDB, then I can't
view the first argument. Here's an example session:
$ gdb $(which gdb)
(gdb) start
...
(gdb) info probes stap libc pthread_create
...
(gdb) break *0x00007ffff729e2f1 # Use address of probe.
(gdb) continue
...
(gdb) p $_probe_arg0
Invalid cast.
What's going wrong? If I re-run my session, but this time use 'set
debug stap-expression 1', this is what I see:
(gdb) set debug stap-expression 1
(gdb) p $_probe_arg0
Operation: UNOP_CAST
Operation: OP_REGISTER
String: xmm1
Type: uint64_t
Operation: UNOP_CAST
Operation: OP_REGISTER
String: r13
Type: uint64_t
Operation: UNOP_CAST
Operation: UNOP_IND
Operation: UNOP_CAST
Operation: BINOP_ADD
Operation: OP_LONG
Type: long
Constant: 0x0000000000000008
Operation: OP_REGISTER
String: rsp
Type: uint64_t *
Type: uint64_t
Operation: UNOP_CAST
Operation: UNOP_IND
Operation: UNOP_CAST
Operation: BINOP_ADD
Operation: OP_LONG
Type: long
Constant: 0x0000000000000010
Operation: OP_REGISTER
String: rsp
Type: uint64_t *
Type: uint64_t
Invalid cast.
(gdb)
The important bit is this:
Operation: UNOP_CAST
Operation: OP_REGISTER
String: xmm1
Type: uint64_t
Which is where we cast the xmm1 register to uint64_t. And the final
piece of the puzzle is:
(gdb) ptype $xmm1
type = union vec128 {
v8bf16 v8_bfloat16;
v4f v4_float;
v2d v2_double;
v16i8 v16_int8;
v8i16 v8_int16;
v4i32 v4_int32;
v2i64 v2_int64;
uint128_t uint128;
}
So, we are attempting to cast a union type to a scalar type, which is
not supporting in C/C++, and as a consequence GDB's expression
evaluator throws an error when we attempt to do this.
The first approach I considered for solving this problem was to try
and make use of gdbarch_stap_adjust_register. We already have a
gdbarch method (gdbarch_stap_adjust_register) that allows us to tweak
the name of the register that we access. Currently only x86
architectures use this to transform things like ax to eax in some
cases.
I wondered, what if we change gdbarch_stap_adjust_register to do more
than just change the register names? What if this method instead
became gdbarch_stap_read_register. This new method would return a
operation_up, and would take the register name, and the type we are
trying to read from the register, and return the operation that
actually reads the register.
The default implementation of this method would just use
user_reg_map_name_to_regnum, and then create a register_operation,
like we already do in stap_parse_register_operand. But, for x86
architectures this method would fist possibly adjust the register
name, then do the default action to read the register. Finally, for
x86 this method would spot when we were accessing an xmm register,
and, based on the type being pulled from the register, would extract
the correct field from the union.
The benefit of this approach is that it would work with the expression
types that GDB currently supports. The draw back would be that this
approach would not be very generic. We'd need code to handle each
sub-field size with an xmm register. If other architectures started
using vector registers for probe arguments, those architectures would
have to create their own gdbarch_stap_read_register method. And
finally, the type of the xmm registers comes from the type defined in
the target description, there's a risk that GDB might end up
hard-coding the names of type sub-fields, then if a target uses a
different target description, with different field names for xmm
registers, the stap probes would stop working.
And so, based on all the above draw backs, I rejected this first
approach.
My second plan involves adding a new expression type to GDB called
unop_extract_operation. This new expression takes a value and a type,
during evaluation the value contents are fetched, and then a new value
is extracted from the value contents (based on type). This is similar
to the following C expression:
result_value = *((output_type *) &input_value);
Obviously we can't actually build this expression in this case, as the
input_value is in a register, but hopefully the above makes it clearer
what I'm trying to do.
The benefit of the new expression approach is that this code can be
shared across all architectures, and it doesn't care about sub-field
names within the union type.
The draw-backs that I see are potential future problems if arguments
are not stored within the least significant bytes of the register.
However if/when that becomes an issue we can adapt the
gdbarch_stap_read_register approach to allow architectures to control
how a value is extracted.
For testing, I've extended the existing gdb.base/stap-probe.exp test
to include a function that tries to force an argument into an xmm
register. Obviously, that will only work on a x86 target, so I've
guarded the new function with an appropriate GCC define. In the exp
script we use readelf to check if the probe exists, and is using the
xmm register.
If the probe doesn't exist then the associated tests are skipped.
If the probe exists, put isn't using the xmm register (which will
depend on systemtap/gcc versions), then again, the tests are skipped.
Otherwise, we can run the test. I think the cost of running readelf
is pretty low, so I don't feel too bad making all the non-xmm targets
running this step.
I found that on a Fedora 35 install, with these packages installed, I
was able to run this test and have the probe argument be placed in an
xmm register:
$ rpm -q systemtap gcc glibc
systemtap-4.6-4.fc35.x86_64
gcc-11.2.1-9.fc35.x86_64
glibc-2.34-7.fc35.x86_64
Finally, as this patch adds a new operation type, then I need to
consider how to generate an agent expression for the new operation
type.
I have kicked the can down the road a bit on this. In the function
stap_parse_register_operand, I only create a unop_extract_operation in
the case where the register type is non-scalar, this means that in
most cases I don't need to worry about generating an agent expression
at all.
In the xmm register case, when an unop_extract_operation will be
created, I have sketched out how the agent expression could be
handled, however, this code is currently not reached. When we try to
generate the agent expression to place the xmm register on the stack,
GDB hits this error:
(gdb) trace -probe-stap test:xmmreg
Tracepoint 1 at 0x401166
(gdb) actions
Enter actions for tracepoint 1, one per line.
End with a line saying just "end".
>collect $_probe_arg0
Value not scalar: cannot be an rvalue.
This is because GDB doesn't currently support placing non-scalar types
on the agent expression evaluation stack. Solving this is clearly
related to the original problem, but feels a bit like a second
problem. I'd like to get feedback on whether my approach to solving
the original problem is acceptable or not before I start looking at
how to handle xmm registers within agent expressions.
2022-03-11 00:57:18 +08:00
|
|
|
|
error (_("length type is larger than the value type"));
|
|
|
|
|
|
2023-02-01 04:25:17 +08:00
|
|
|
|
struct value *result = value::allocate (type);
|
2023-02-01 22:27:50 +08:00
|
|
|
|
old_value->contents_copy (result, 0, 0, type->length ());
|
gdb/x86: handle stap probe arguments in xmm registers
On x86 machines with xmm register, and with recent versions of
systemtap (and gcc?), it can occur that stap probe arguments will be
placed into xmm registers.
I notice this happening on a current Fedora Rawhide install with the
following package versions installed:
$ rpm -q glibc systemtap gcc
glibc-2.35.9000-10.fc37.x86_64
systemtap-4.7~pre16468670g9f253544-1.fc37.x86_64
gcc-12.0.1-0.12.fc37.x86_64
If I check the probe data in libc, I see this:
$ readelf -n /lib64/libc.so.6
...
stapsdt 0x0000004d NT_STAPSDT (SystemTap probe descriptors)
Provider: libc
Name: pthread_start
Location: 0x0000000000090ac3, Base: 0x00000000001c65c4, Semaphore: 0x0000000000000000
Arguments: 8@%xmm1 8@1600(%rbx) 8@1608(%rbx)
stapsdt 0x00000050 NT_STAPSDT (SystemTap probe descriptors)
Provider: libc
Name: pthread_create
Location: 0x00000000000912f1, Base: 0x00000000001c65c4, Semaphore: 0x0000000000000000
Arguments: 8@%xmm1 8@%r13 8@8(%rsp) 8@16(%rsp)
...
Notice that for both of these probes, the first argument is a uint64_t
stored in the xmm1 register.
Unfortunately, if I try to use this probe within GDB, then I can't
view the first argument. Here's an example session:
$ gdb $(which gdb)
(gdb) start
...
(gdb) info probes stap libc pthread_create
...
(gdb) break *0x00007ffff729e2f1 # Use address of probe.
(gdb) continue
...
(gdb) p $_probe_arg0
Invalid cast.
What's going wrong? If I re-run my session, but this time use 'set
debug stap-expression 1', this is what I see:
(gdb) set debug stap-expression 1
(gdb) p $_probe_arg0
Operation: UNOP_CAST
Operation: OP_REGISTER
String: xmm1
Type: uint64_t
Operation: UNOP_CAST
Operation: OP_REGISTER
String: r13
Type: uint64_t
Operation: UNOP_CAST
Operation: UNOP_IND
Operation: UNOP_CAST
Operation: BINOP_ADD
Operation: OP_LONG
Type: long
Constant: 0x0000000000000008
Operation: OP_REGISTER
String: rsp
Type: uint64_t *
Type: uint64_t
Operation: UNOP_CAST
Operation: UNOP_IND
Operation: UNOP_CAST
Operation: BINOP_ADD
Operation: OP_LONG
Type: long
Constant: 0x0000000000000010
Operation: OP_REGISTER
String: rsp
Type: uint64_t *
Type: uint64_t
Invalid cast.
(gdb)
The important bit is this:
Operation: UNOP_CAST
Operation: OP_REGISTER
String: xmm1
Type: uint64_t
Which is where we cast the xmm1 register to uint64_t. And the final
piece of the puzzle is:
(gdb) ptype $xmm1
type = union vec128 {
v8bf16 v8_bfloat16;
v4f v4_float;
v2d v2_double;
v16i8 v16_int8;
v8i16 v8_int16;
v4i32 v4_int32;
v2i64 v2_int64;
uint128_t uint128;
}
So, we are attempting to cast a union type to a scalar type, which is
not supporting in C/C++, and as a consequence GDB's expression
evaluator throws an error when we attempt to do this.
The first approach I considered for solving this problem was to try
and make use of gdbarch_stap_adjust_register. We already have a
gdbarch method (gdbarch_stap_adjust_register) that allows us to tweak
the name of the register that we access. Currently only x86
architectures use this to transform things like ax to eax in some
cases.
I wondered, what if we change gdbarch_stap_adjust_register to do more
than just change the register names? What if this method instead
became gdbarch_stap_read_register. This new method would return a
operation_up, and would take the register name, and the type we are
trying to read from the register, and return the operation that
actually reads the register.
The default implementation of this method would just use
user_reg_map_name_to_regnum, and then create a register_operation,
like we already do in stap_parse_register_operand. But, for x86
architectures this method would fist possibly adjust the register
name, then do the default action to read the register. Finally, for
x86 this method would spot when we were accessing an xmm register,
and, based on the type being pulled from the register, would extract
the correct field from the union.
The benefit of this approach is that it would work with the expression
types that GDB currently supports. The draw back would be that this
approach would not be very generic. We'd need code to handle each
sub-field size with an xmm register. If other architectures started
using vector registers for probe arguments, those architectures would
have to create their own gdbarch_stap_read_register method. And
finally, the type of the xmm registers comes from the type defined in
the target description, there's a risk that GDB might end up
hard-coding the names of type sub-fields, then if a target uses a
different target description, with different field names for xmm
registers, the stap probes would stop working.
And so, based on all the above draw backs, I rejected this first
approach.
My second plan involves adding a new expression type to GDB called
unop_extract_operation. This new expression takes a value and a type,
during evaluation the value contents are fetched, and then a new value
is extracted from the value contents (based on type). This is similar
to the following C expression:
result_value = *((output_type *) &input_value);
Obviously we can't actually build this expression in this case, as the
input_value is in a register, but hopefully the above makes it clearer
what I'm trying to do.
The benefit of the new expression approach is that this code can be
shared across all architectures, and it doesn't care about sub-field
names within the union type.
The draw-backs that I see are potential future problems if arguments
are not stored within the least significant bytes of the register.
However if/when that becomes an issue we can adapt the
gdbarch_stap_read_register approach to allow architectures to control
how a value is extracted.
For testing, I've extended the existing gdb.base/stap-probe.exp test
to include a function that tries to force an argument into an xmm
register. Obviously, that will only work on a x86 target, so I've
guarded the new function with an appropriate GCC define. In the exp
script we use readelf to check if the probe exists, and is using the
xmm register.
If the probe doesn't exist then the associated tests are skipped.
If the probe exists, put isn't using the xmm register (which will
depend on systemtap/gcc versions), then again, the tests are skipped.
Otherwise, we can run the test. I think the cost of running readelf
is pretty low, so I don't feel too bad making all the non-xmm targets
running this step.
I found that on a Fedora 35 install, with these packages installed, I
was able to run this test and have the probe argument be placed in an
xmm register:
$ rpm -q systemtap gcc glibc
systemtap-4.6-4.fc35.x86_64
gcc-11.2.1-9.fc35.x86_64
glibc-2.34-7.fc35.x86_64
Finally, as this patch adds a new operation type, then I need to
consider how to generate an agent expression for the new operation
type.
I have kicked the can down the road a bit on this. In the function
stap_parse_register_operand, I only create a unop_extract_operation in
the case where the register type is non-scalar, this means that in
most cases I don't need to worry about generating an agent expression
at all.
In the xmm register case, when an unop_extract_operation will be
created, I have sketched out how the agent expression could be
handled, however, this code is currently not reached. When we try to
generate the agent expression to place the xmm register on the stack,
GDB hits this error:
(gdb) trace -probe-stap test:xmmreg
Tracepoint 1 at 0x401166
(gdb) actions
Enter actions for tracepoint 1, one per line.
End with a line saying just "end".
>collect $_probe_arg0
Value not scalar: cannot be an rvalue.
This is because GDB doesn't currently support placing non-scalar types
on the agent expression evaluation stack. Solving this is clearly
related to the original problem, but feels a bit like a second
problem. I'd like to get feedback on whether my approach to solving
the original problem is acceptable or not before I start looking at
how to handle xmm registers within agent expressions.
2022-03-11 00:57:18 +08:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
1999-04-16 09:35:26 +08:00
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* Helper for evaluate_subexp_for_address. */
|
|
|
|
|
|
|
|
|
|
static value *
|
|
|
|
|
evaluate_subexp_for_address_base (struct expression *exp, enum noside noside,
|
|
|
|
|
value *x)
|
|
|
|
|
{
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
{
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = check_typedef (x->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
if (TYPE_IS_REFERENCE (type))
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (lookup_pointer_type (type->target_type ()),
|
2021-03-08 22:27:57 +08:00
|
|
|
|
not_lval);
|
2023-02-09 21:55:48 +08:00
|
|
|
|
else if (x->lval () == lval_memory || value_must_coerce_to_target (x))
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (lookup_pointer_type (x->type ()),
|
2021-03-08 22:27:57 +08:00
|
|
|
|
not_lval);
|
|
|
|
|
else
|
|
|
|
|
error (_("Attempt to take address of "
|
|
|
|
|
"value not located in memory."));
|
|
|
|
|
}
|
|
|
|
|
return value_addr (x);
|
|
|
|
|
}
|
|
|
|
|
|
Introduce class operation
This patch introduces class operation, the new base class for all
expression operations.
In the new approach, an operation is simply a class that presents a
certain interface. Operations own their operands, and management is
done via unique_ptr.
The operation interface is largely ad hoc, based on the evolution of
expression handling in GDB. Parts (for example,
evaluate_with_coercion) are probably redundant; however I took this
approach to try to avoid mixing different kinds of refactorings.
In some specific situations, rather than add a generic method across
the entire operation class hierarchy, I chose instead to use
dynamic_cast and specialized methods on certain concrete subclasses.
This will appear in some subsequent patches.
One goal of this work is to avoid the kinds of easy-to-make errors
that affected the old implementation. To this end, some helper
subclasses are also added here. These helpers automate the
implementation of the 'dump', 'uses_objfile', and 'constant_p'
methods. Nearly every concrete operation that is subsequently added
will use these facilities. (Note that the 'dump' implementation is
only outlined here, the body appears in the next patch.)
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* expression.h (expr::operation): New class.
(expr::make_operation): New function.
(expr::operation_up): New typedef.
* expop.h: New file.
* eval.c (operation::evaluate_for_cast)
(operation::evaluate_for_address, operation::evaluate_for_sizeof):
New methods.
* ax-gdb.c (operation::generate_ax): New method.
2021-03-08 22:27:57 +08:00
|
|
|
|
namespace expr
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
operation::evaluate_for_cast (struct type *expect_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *val = evaluate (expect_type, exp, noside);
|
|
|
|
|
return value_cast (expect_type, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
operation::evaluate_for_address (struct expression *exp, enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *val = evaluate (nullptr, exp, noside);
|
|
|
|
|
return evaluate_subexp_for_address_base (exp, noside, val);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
scope_operation::evaluate_for_address (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *x = value_aggregate_elt (std::get<0> (m_storage),
|
|
|
|
|
std::get<1> (m_storage).c_str (),
|
|
|
|
|
NULL, 1, noside);
|
|
|
|
|
if (x == NULL)
|
|
|
|
|
error (_("There is no field named %s"), std::get<1> (m_storage).c_str ());
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
unop_ind_base_operation::evaluate_for_address (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *x = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
|
|
|
|
|
|
|
|
|
|
/* We can't optimize out "&*" if there's a user-defined operator*. */
|
|
|
|
|
if (unop_user_defined_p (UNOP_IND, x))
|
|
|
|
|
{
|
|
|
|
|
x = value_x_unop (x, UNOP_IND, noside);
|
|
|
|
|
return evaluate_subexp_for_address_base (exp, noside, x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return coerce_array (x);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
var_msym_value_operation::evaluate_for_address (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
2021-03-08 22:27:57 +08:00
|
|
|
|
const bound_minimal_symbol &b = std::get<0> (m_storage);
|
|
|
|
|
value *val = evaluate_var_msym_value (noside, b.objfile, b.minsym);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
{
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = lookup_pointer_type (val->type ());
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (type, not_lval);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return value_addr (val);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
unop_memval_operation::evaluate_for_address (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
return value_cast (lookup_pointer_type (std::get<1> (m_storage)),
|
|
|
|
|
std::get<0> (m_storage)->evaluate (nullptr, exp, noside));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
unop_memval_type_operation::evaluate_for_address (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *typeval = std::get<0> (m_storage)->evaluate (nullptr, exp,
|
|
|
|
|
EVAL_AVOID_SIDE_EFFECTS);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = typeval->type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return value_cast (lookup_pointer_type (type),
|
|
|
|
|
std::get<1> (m_storage)->evaluate (nullptr, exp, noside));
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
var_value_operation::evaluate_for_address (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
2021-04-16 00:05:00 +08:00
|
|
|
|
symbol *var = std::get<0> (m_storage).symbol;
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
/* C++: The "address" of a reference should yield the address
|
|
|
|
|
* of the object pointed to. Let value_addr() deal with it. */
|
2022-01-28 11:16:41 +08:00
|
|
|
|
if (TYPE_IS_REFERENCE (var->type ()))
|
2021-03-08 22:27:57 +08:00
|
|
|
|
return operation::evaluate_for_address (exp, noside);
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
{
|
2022-01-28 11:16:41 +08:00
|
|
|
|
struct type *type = lookup_pointer_type (var->type ());
|
2021-11-22 11:26:24 +08:00
|
|
|
|
enum address_class sym_class = var->aclass ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
if (sym_class == LOC_CONST
|
|
|
|
|
|| sym_class == LOC_CONST_BYTES
|
|
|
|
|
|| sym_class == LOC_REGISTER)
|
|
|
|
|
error (_("Attempt to take address of register or constant."));
|
|
|
|
|
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (type, not_lval);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
2021-04-16 00:05:00 +08:00
|
|
|
|
return address_of_variable (var, std::get<0> (m_storage).block);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
var_value_operation::evaluate_with_coercion (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
2021-04-16 00:05:00 +08:00
|
|
|
|
struct symbol *var = std::get<0> (m_storage).symbol;
|
2022-01-28 11:16:41 +08:00
|
|
|
|
struct type *type = check_typedef (var->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (type->code () == TYPE_CODE_ARRAY
|
|
|
|
|
&& !type->is_vector ()
|
|
|
|
|
&& CAST_IS_CONVERSION (exp->language_defn))
|
|
|
|
|
{
|
2021-04-16 00:05:00 +08:00
|
|
|
|
struct value *val = address_of_variable (var,
|
|
|
|
|
std::get<0> (m_storage).block);
|
2022-07-31 10:43:54 +08:00
|
|
|
|
return value_cast (lookup_pointer_type (type->target_type ()), val);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
return evaluate (nullptr, exp, noside);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* Helper function for evaluating the size of a type. */
|
|
|
|
|
|
|
|
|
|
static value *
|
|
|
|
|
evaluate_subexp_for_sizeof_base (struct expression *exp, struct type *type)
|
|
|
|
|
{
|
|
|
|
|
/* FIXME: This should be size_t. */
|
|
|
|
|
struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
|
|
|
|
|
/* $5.3.3/2 of the C++ Standard (n3290 draft) says of sizeof:
|
|
|
|
|
"When applied to a reference or a reference type, the result is
|
|
|
|
|
the size of the referenced type." */
|
|
|
|
|
type = check_typedef (type);
|
|
|
|
|
if (exp->language_defn->la_language == language_cplus
|
|
|
|
|
&& (TYPE_IS_REFERENCE (type)))
|
2022-07-31 10:43:54 +08:00
|
|
|
|
type = check_typedef (type->target_type ());
|
2022-10-13 21:17:24 +08:00
|
|
|
|
else if (exp->language_defn->la_language == language_fortran
|
|
|
|
|
&& type->code () == TYPE_CODE_PTR)
|
|
|
|
|
{
|
|
|
|
|
/* Dereference Fortran pointer types to allow them for the Fortran
|
|
|
|
|
sizeof intrinsic. */
|
|
|
|
|
type = check_typedef (type->target_type ());
|
|
|
|
|
}
|
2022-09-21 23:05:21 +08:00
|
|
|
|
return value_from_longest (size_type, (LONGEST) type->length ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
Introduce class operation
This patch introduces class operation, the new base class for all
expression operations.
In the new approach, an operation is simply a class that presents a
certain interface. Operations own their operands, and management is
done via unique_ptr.
The operation interface is largely ad hoc, based on the evolution of
expression handling in GDB. Parts (for example,
evaluate_with_coercion) are probably redundant; however I took this
approach to try to avoid mixing different kinds of refactorings.
In some specific situations, rather than add a generic method across
the entire operation class hierarchy, I chose instead to use
dynamic_cast and specialized methods on certain concrete subclasses.
This will appear in some subsequent patches.
One goal of this work is to avoid the kinds of easy-to-make errors
that affected the old implementation. To this end, some helper
subclasses are also added here. These helpers automate the
implementation of the 'dump', 'uses_objfile', and 'constant_p'
methods. Nearly every concrete operation that is subsequently added
will use these facilities. (Note that the 'dump' implementation is
only outlined here, the body appears in the next patch.)
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* expression.h (expr::operation): New class.
(expr::make_operation): New function.
(expr::operation_up): New typedef.
* expop.h: New file.
* eval.c (operation::evaluate_for_cast)
(operation::evaluate_for_address, operation::evaluate_for_sizeof):
New methods.
* ax-gdb.c (operation::generate_ax): New method.
2021-03-08 22:27:57 +08:00
|
|
|
|
namespace expr
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
operation::evaluate_for_sizeof (struct expression *exp, enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *val = evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
return evaluate_subexp_for_sizeof_base (exp, val->type ());
|
Introduce class operation
This patch introduces class operation, the new base class for all
expression operations.
In the new approach, an operation is simply a class that presents a
certain interface. Operations own their operands, and management is
done via unique_ptr.
The operation interface is largely ad hoc, based on the evolution of
expression handling in GDB. Parts (for example,
evaluate_with_coercion) are probably redundant; however I took this
approach to try to avoid mixing different kinds of refactorings.
In some specific situations, rather than add a generic method across
the entire operation class hierarchy, I chose instead to use
dynamic_cast and specialized methods on certain concrete subclasses.
This will appear in some subsequent patches.
One goal of this work is to avoid the kinds of easy-to-make errors
that affected the old implementation. To this end, some helper
subclasses are also added here. These helpers automate the
implementation of the 'dump', 'uses_objfile', and 'constant_p'
methods. Nearly every concrete operation that is subsequently added
will use these facilities. (Note that the 'dump' implementation is
only outlined here, the body appears in the next patch.)
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* expression.h (expr::operation): New class.
(expr::make_operation): New function.
(expr::operation_up): New typedef.
* expop.h: New file.
* eval.c (operation::evaluate_for_cast)
(operation::evaluate_for_address, operation::evaluate_for_sizeof):
New methods.
* ax-gdb.c (operation::generate_ax): New method.
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
var_msym_value_operation::evaluate_for_sizeof (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
|
|
|
|
|
{
|
2021-03-08 22:27:57 +08:00
|
|
|
|
const bound_minimal_symbol &b = std::get<0> (m_storage);
|
|
|
|
|
value *mval = evaluate_var_msym_value (noside, b.objfile, b.minsym);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = mval->type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (type->code () == TYPE_CODE_ERROR)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
error_unknown_type (b.minsym->print_name ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
/* FIXME: This should be size_t. */
|
|
|
|
|
struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
|
2022-09-21 23:05:21 +08:00
|
|
|
|
return value_from_longest (size_type, type->length ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
subscript_operation::evaluate_for_sizeof (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
if (noside == EVAL_NORMAL)
|
|
|
|
|
{
|
|
|
|
|
value *val = std::get<0> (m_storage)->evaluate (nullptr, exp,
|
|
|
|
|
EVAL_AVOID_SIDE_EFFECTS);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = check_typedef (val->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (type->code () == TYPE_CODE_ARRAY)
|
|
|
|
|
{
|
2022-07-31 10:43:54 +08:00
|
|
|
|
type = check_typedef (type->target_type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (type->code () == TYPE_CODE_ARRAY)
|
|
|
|
|
{
|
|
|
|
|
type = type->index_type ();
|
|
|
|
|
/* Only re-evaluate the right hand side if the resulting type
|
|
|
|
|
is a variable length type. */
|
|
|
|
|
if (type->bounds ()->flag_bound_evaluated)
|
|
|
|
|
{
|
|
|
|
|
val = evaluate (nullptr, exp, EVAL_NORMAL);
|
|
|
|
|
/* FIXME: This should be size_t. */
|
|
|
|
|
struct type *size_type
|
|
|
|
|
= builtin_type (exp->gdbarch)->builtin_int;
|
|
|
|
|
return value_from_longest
|
2023-01-31 22:52:09 +08:00
|
|
|
|
(size_type, (LONGEST) val->type ()->length ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return operation::evaluate_for_sizeof (exp, noside);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
unop_ind_base_operation::evaluate_for_sizeof (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *val = std::get<0> (m_storage)->evaluate (nullptr, exp,
|
|
|
|
|
EVAL_AVOID_SIDE_EFFECTS);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
struct type *type = check_typedef (val->type ());
|
2021-09-12 03:58:04 +08:00
|
|
|
|
if (!type->is_pointer_or_reference ()
|
2021-03-08 22:27:57 +08:00
|
|
|
|
&& type->code () != TYPE_CODE_ARRAY)
|
|
|
|
|
error (_("Attempt to take contents of a non-pointer value."));
|
2022-07-31 10:43:54 +08:00
|
|
|
|
type = type->target_type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (is_dynamic_type (type))
|
2023-01-31 22:52:09 +08:00
|
|
|
|
type = value_ind (val)->type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
/* FIXME: This should be size_t. */
|
|
|
|
|
struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
|
2022-09-21 23:05:21 +08:00
|
|
|
|
return value_from_longest (size_type, (LONGEST) type->length ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
unop_memval_operation::evaluate_for_sizeof (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
return evaluate_subexp_for_sizeof_base (exp, std::get<1> (m_storage));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value *
|
|
|
|
|
unop_memval_type_operation::evaluate_for_sizeof (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *typeval = std::get<0> (m_storage)->evaluate (nullptr, exp,
|
|
|
|
|
EVAL_AVOID_SIDE_EFFECTS);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
return evaluate_subexp_for_sizeof_base (exp, typeval->type ());
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
var_value_operation::evaluate_for_sizeof (struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
2022-01-28 11:16:41 +08:00
|
|
|
|
struct type *type = std::get<0> (m_storage).symbol->type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (is_dynamic_type (type))
|
|
|
|
|
{
|
|
|
|
|
value *val = evaluate (nullptr, exp, EVAL_NORMAL);
|
2023-01-31 22:52:09 +08:00
|
|
|
|
type = val->type ();
|
2021-03-08 22:27:57 +08:00
|
|
|
|
if (type->code () == TYPE_CODE_ARRAY)
|
|
|
|
|
{
|
|
|
|
|
/* FIXME: This should be size_t. */
|
|
|
|
|
struct type *size_type = builtin_type (exp->gdbarch)->builtin_int;
|
|
|
|
|
if (type_not_allocated (type) || type_not_associated (type))
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (size_type, not_lval);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
else if (is_dynamic_type (type->index_type ())
|
Handling of arrays with optimized-out bounds
In Ada, sometimes the compiler must emit array bounds by referencing
an artificial variable that's created for this purpose. However, with
optimization enabled, these variables can be optimized away.
Currently this can result in displays like:
(gdb) print mumble
$1 = (warning: unable to get bounds of array, assuming null array
)
This patch changes this to report that the array is optimized-out,
instead, which is closer to the truth, and more generally useful. For
example, Python pretty-printers can now recognize this situation.
In order to accomplish this, I introduced a new PROP_OPTIMIZED_OUT
enumerator and changed one place to use it. Reusing the "unknown"
state wouldn't work properly, because in C it is normal for array
bounds to be unknown.
2023-12-21 23:24:18 +08:00
|
|
|
|
&& !type->bounds ()->high.is_available ())
|
2023-02-01 04:30:54 +08:00
|
|
|
|
return value::allocate_optimized_out (size_type);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return evaluate_subexp_for_sizeof_base (exp, type);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
var_msym_value_operation::evaluate_for_cast (struct type *to_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
2023-02-01 04:41:35 +08:00
|
|
|
|
return value::zero (to_type, not_lval);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
const bound_minimal_symbol &b = std::get<0> (m_storage);
|
|
|
|
|
value *val = evaluate_var_msym_value (noside, b.objfile, b.minsym);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
val = value_cast (to_type, val);
|
|
|
|
|
|
|
|
|
|
/* Don't allow e.g. '&(int)var_with_no_debug_info'. */
|
2023-02-09 21:55:48 +08:00
|
|
|
|
if (val->lval () == lval_memory)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
{
|
2023-02-01 01:52:04 +08:00
|
|
|
|
if (val->lazy ())
|
2023-02-01 04:53:55 +08:00
|
|
|
|
val->fetch_lazy ();
|
2023-02-09 21:35:33 +08:00
|
|
|
|
val->set_lval (not_lval);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
value *
|
|
|
|
|
var_value_operation::evaluate_for_cast (struct type *to_type,
|
|
|
|
|
struct expression *exp,
|
|
|
|
|
enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
value *val = evaluate_var_value (noside,
|
2021-04-16 00:05:00 +08:00
|
|
|
|
std::get<0> (m_storage).block,
|
|
|
|
|
std::get<0> (m_storage).symbol);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
|
|
|
|
|
val = value_cast (to_type, val);
|
|
|
|
|
|
|
|
|
|
/* Don't allow e.g. '&(int)var_with_no_debug_info'. */
|
2023-02-09 21:55:48 +08:00
|
|
|
|
if (val->lval () == lval_memory)
|
2021-03-08 22:27:57 +08:00
|
|
|
|
{
|
2023-02-01 01:52:04 +08:00
|
|
|
|
if (val->lazy ())
|
2023-02-01 04:53:55 +08:00
|
|
|
|
val->fetch_lazy ();
|
2023-02-09 21:35:33 +08:00
|
|
|
|
val->set_lval (not_lval);
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 22:27:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2011-01-08 03:36:19 +08:00
|
|
|
|
/* Parse a type expression in the string [P..P+LENGTH). */
|
1999-04-16 09:35:26 +08:00
|
|
|
|
|
|
|
|
|
struct type *
|
2020-12-14 00:51:42 +08:00
|
|
|
|
parse_and_eval_type (const char *p, int length)
|
1999-04-16 09:35:26 +08:00
|
|
|
|
{
|
1999-07-08 04:19:36 +08:00
|
|
|
|
char *tmp = (char *) alloca (length + 4);
|
2010-05-15 02:35:11 +08:00
|
|
|
|
|
1999-07-08 04:19:36 +08:00
|
|
|
|
tmp[0] = '(';
|
|
|
|
|
memcpy (tmp + 1, p, length);
|
|
|
|
|
tmp[length + 1] = ')';
|
|
|
|
|
tmp[length + 2] = '0';
|
|
|
|
|
tmp[length + 3] = '\0';
|
'struct expression *' -> gdb::unique_xmalloc_ptr<expression>
This patch makes parse_expression and friends return a unique_ptr
instead of raw pointer [1]:
typedef gdb::unique_malloc_ptr<expression> expression_up;
and then adjusts the codebase throughout to stop using cleanups to
manage lifetime of expression pointers.
Whenever I found a structure owning an expression pointer, I made it
store a unique_ptr instead of a raw pointer, which then requires using
new/delete of the holding structure, instead of XNEW/xfree.
[1] - I'd like to set the rule that types named with an "_up" suffix
are unique_ptr typedefs.
Note I used gdb::unique_xmalloc_ptr instead of gdb::unique_ptr, simply
because we still use xmalloc instead of new to allocate expression
objects. Once that's changed, all we need to do is change the
expression_up typedef and the smart pointer will then call delete
instead of xfree.
gdb/ChangeLog:
2016-11-08 Pedro Alves <palves@redhat.com>
* ada-lang.c (ada_read_renaming_var_value): Use expression_up.
(struct ada_catchpoint_location) <excep_cond_expr>: Now an
expression_up.
(ada_catchpoint_location_dtor): Reset excep_cond_expr instead of
using xfree.
(create_excep_cond_exprs): Use expression_up and gdb::move.
(allocate_location_exception): Use new instead of XNEW.
(should_stop_exception): Likewise. Adjust to use expression_up.
(create_ada_exception_catchpoint): Use new instead of XNEW.
* ax-gdb.c (agent_eval_command_one): Use expression_up instead of
cleanups.
(maint_agent_printf_command): Use expression_up.
* break-catch-sig.c (create_signal_catchpoint): Use new instead of
XNEW.
* break-catch-syscall.c (create_syscall_event_catchpoint):
Likewise.
* break-catch-throw.c (handle_gnu_v3_exceptions): Use new instead
of XCNEW. Use gdb::unique_ptr instead of cleanups.
* breakpoint.c (set_breakpoint_condition, update_watchpoint)
(parse_cmd_to_aexpr, watchpoint_check)
(bpstat_check_breakpoint_conditions, watchpoint_locations_match):
Adjust to use expression_up.
(init_bp_location): Adjust.
(free_bp_location): Use delete instead of xfree.
(set_raw_breakpoint_without_location, set_raw_breakpoint)
(add_solib_catchpoint, create_fork_vfork_event_catchpoint)
(new_single_step_breakpoint, create_breakpoint_sal): Use new
instead of XNEW.
(find_condition_and_thread): Adjust to use expression_up.
(create_breakpoint): Use new instead of XNEW.
(dtor_watchpoint): Don't xfree expression pointers, they're
unique_ptr's now.
(insert_watchpoint, remove_watchpoint): Adjust.
(watch_command_1): Use expression_up. Use new instead of XCNEW.
(catch_exec_command_1): Use new instead of XNEW.
(bp_location_dtor): Don't xfree expression pointers, they're
unique_ptr's now.
(base_breakpoint_allocate_location)
(strace_marker_create_breakpoints_sal): Use new instead of XNEW.
(delete_breakpoint): Use delete instead of xfree.
* breakpoint.h (struct bp_location) <cond>: Now an
unique_ptr<expression> instead of a raw pointer.
(struct watchpoint) <exp, cond_exp>: Likewise.
* cli/cli-script.c (execute_control_command): Use expression_up
instead of cleanups.
* dtrace-probe.c (dtrace_process_dof_probe): Use expression_up.
* eval.c (parse_and_eval_address, parse_and_eval_long)
(parse_and_eval, parse_to_comma_and_eval, parse_and_eval_type):
Use expression_up instead of cleanups.
* expression.h (expression_up): New typedef.
(parse_expression, parse_expression_with_language, parse_exp_1):
Change return type to expression_up.
* mi/mi-main.c (mi_cmd_data_evaluate_expression)
(print_variable_or_computed): Use expression_up.
* objc-lang.c (print_object_command): Use expression_up instead of
cleanups.
* parse.c (parse_exp_1, parse_exp_in_context)
(parse_exp_in_context_1, parse_expression)
(parse_expression_with_language): Return an expression_up instead
of a raw pointer.
(parse_expression_for_completion): Use expression_up.
* printcmd.c (struct display) <exp>: Now an expression_up instead
of a raw pointer.
(print_command_1, output_command_const, set_command, x_command):
Use expression_up instead of cleanups.
(display_command): Likewise. Use new instead of XNEW.
(free_display): Use delete instead of xfree.
(do_one_display): Adjust to use expression_up.
* remote.c (remote_download_tracepoint): Likewise.
* stack.c (return_command): Likewise.
* tracepoint.c (validate_actionline, encode_actions_1): Use
expression_up instead of cleanups.
* typeprint.c (whatis_exp, maintenance_print_type): Likewise.
* value.c (init_if_undefined_command): Likewise.
* varobj.c (struct varobj_root) <exp>: Now an expression_up
instead of a raw pointer.
(varobj_create): Adjust.
(varobj_set_value): Use an expression_up instead of cleanups.
(new_root_variable): Use new instead of XNEW.
(free_variable): Use delete instead of xfree.
(value_of_root_1): Use std::swap.
2016-11-08 23:26:43 +08:00
|
|
|
|
expression_up expr = parse_expression (tmp);
|
Remove union exp_element
This removes union exp_element functions that either create such
elements or walk them. struct expression no longer holds
exp_elements. A couple of language_defn methods are also removed, as
they are obsolete.
Note that this patch also removes the print_expression code. The only
in-tree caller of this was from dump_prefix_expression, which is only
called when expression debugging is enabled. Implementing this would
involve a fair amount of code, and it seems to me that prefix dumping
is preferable anyway, as it is unambiguous. So, I have not
reimplemented this feature.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (evaluate_subexp_with_coercion): Don't declare.
* parse.c (exp_descriptor_standard): Remove.
(expr_builder::expr_builder, expr_builder::release): Update.
(expression::expression): Remove size_t parameter.
(expression::~expression): Simplify.
(expression::resize): Remove.
(write_exp_elt, write_exp_elt_opcode, write_exp_elt_sym)
(write_exp_elt_msym, write_exp_elt_block, write_exp_elt_objfile)
(write_exp_elt_longcst, write_exp_elt_floatcst)
(write_exp_elt_type, write_exp_elt_intern, write_exp_string)
(write_exp_string_vector, write_exp_bitstring): Remove.
* p-lang.h (class pascal_language) <opcode_print_table,
op_print_tab>: Remove.
* p-lang.c (pascal_language::op_print_tab): Remove.
* opencl-lang.c (class opencl_language) <opcode_print_table>:
Remove.
* objc-lang.c (objc_op_print_tab): Remove.
(class objc_language) <opcode_print_table>: Remove.
* m2-lang.h (class m2_language) <opcode_print_table,
op_print_tab>: Remove.
* m2-lang.c (m2_language::op_print_tab): Remove.
* language.h (struct language_defn) <post_parser, expression_ops,
opcode_print_table>: Remove.
* language.c (language_defn::expression_ops)
(auto_or_unknown_language::opcode_print_table): Remove.
* go-lang.h (class go_language) <opcode_print_table,
op_print_tab>: Remove.
* go-lang.c (go_language::op_print_tab): Remove.
* f-lang.h (class f_language) <opcode_print_table>: Remove
<op_print_tab>: Remove.
* f-lang.c (f_language::op_print_tab): Remove.
* expression.h (union exp_element): Remove.
(struct expression): Remove size_t parameter from constructor.
<resize>: Remove.
<first_opcode>: Update.
<nelts, elts>: Remove.
(EXP_ELEM_TO_BYTES, BYTES_TO_EXP_ELEM): Remove.
(evaluate_subexp_standard, print_expression, op_string)
(dump_raw_expression): Don't declare.
* expprint.c (print_expression, print_subexp)
(print_subexp_funcall, print_subexp_standard, op_string)
(dump_raw_expression, dump_subexp, dump_subexp_body)
(dump_subexp_body_funcall, dump_subexp_body_standard): Remove.
(dump_prefix_expression): Update.
* eval.c (evaluate_subexp): Remove.
(evaluate_expression, evaluate_type): Update.
(evaluate_subexpression_type): Remove.
(fetch_subexp_value): Remove "pc" parameter. Update.
(extract_field_op, evaluate_struct_tuple, evaluate_funcall)
(evaluate_subexp_standard, evaluate_subexp_for_address)
(evaluate_subexp_with_coercion, evaluate_subexp_for_sizeof)
(evaluate_subexp_for_cast): Remove.
(parse_and_eval_type): Update.
* dtrace-probe.c (dtrace_probe::compile_to_ax): Update.
* d-lang.c (d_op_print_tab): Remove.
(class d_language) <opcode_print_table>: Remove.
* c-lang.h (c_op_print_tab): Don't declare.
* c-lang.c (c_op_print_tab): Remove.
(class c_language, class cplus_language, class asm_language, class
minimal_language) <opcode_print_table>: Remove.
* breakpoint.c (update_watchpoint, watchpoint_check)
(watchpoint_exp_is_const, watch_command_1): Update.
* ax-gdb.h (union exp_element): Don't declare.
* ax-gdb.c (const_var_ref, const_expr, maybe_const_expr)
(gen_repeat, gen_sizeof, gen_expr_for_cast, gen_expr)
(gen_expr_binop_rest): Remove.
(gen_trace_for_expr, gen_eval_for_expr, gen_printf): Update.
* ada-lang.c (ada_op_print_tab): Remove.
(class ada_language) <post_parser, opcode_print_table>: Remove.
2021-03-08 22:27:57 +08:00
|
|
|
|
expr::unop_cast_operation *op
|
|
|
|
|
= dynamic_cast<expr::unop_cast_operation *> (expr->op.get ());
|
|
|
|
|
if (op == nullptr)
|
2005-02-10 Andrew Cagney <cagney@gnu.org>
Mark up all error and warning messages.
* ada-lang.c, amd64-tdep.c, arch-utils.c, breakpoint.c: Update.
* bsd-kvm.c, bsd-uthread.c, coff-solib.h, coffread.c: Update.
* core-aout.c, core-regset.c, corefile.c, corelow.c: Update.
* cp-abi.c, cp-support.c, cp-valprint.c, cris-tdep.c: Update.
* dbxread.c, demangle.c, doublest.c, dsrec.c: Update.
* dve3900-rom.c, dwarf2expr.c, dwarf2loc.c: Update.
* dwarf2read.c, dwarfread.c, elfread.c, eval.c: Update.
* event-top.c, exec.c, expprint.c, f-lang.c: Update.
* f-typeprint.c, f-valprint.c, fbsd-nat.c, findvar.c: Update.
* frame.c, frv-linux-tdep.c, gcore.c, gdbtypes.c: Update.
* gnu-nat.c, gnu-v2-abi.c, gnu-v3-abi.c, go32-nat.c: Update.
* hpacc-abi.c, hppa-hpux-nat.c, hppa-hpux-tdep.c: Update.
* hppa-linux-nat.c, hppa-linux-tdep.c, hppa-tdep.c: Update.
* hpread.c, hpux-thread.c, i386-linux-nat.c: Update.
* i386-linux-tdep.c, i386-tdep.c, i386bsd-nat.c: Update.
* i386gnu-nat.c, i387-tdep.c, ia64-linux-nat.c: Update.
* ia64-tdep.c, inf-child.c, inf-ptrace.c, inf-ttrace.c: Update.
* infcall.c, infcmd.c, inflow.c, infptrace.c, infrun.c: Update.
* inftarg.c, interps.c, irix5-nat.c, jv-lang.c: Update.
* kod-cisco.c, kod.c, language.c, libunwind-frame.c: Update.
* linespec.c, linux-nat.c, linux-thread-db.c, m2-lang.c: Update.
* m32r-rom.c, m68hc11-tdep.c, m68k-tdep.c: Update.
* m68klinux-nat.c, macrocmd.c, macroexp.c, main.c: Update.
* maint.c, mdebugread.c, mem-break.c, memattr.c: Update.
* mips-linux-tdep.c, mips-tdep.c, mipsread.c, monitor.c: Update.
* nlmread.c, nto-procfs.c, objc-lang.c, objfiles.c: Update.
* observer.c, ocd.c, p-lang.c, p-typeprint.c: Update.
* p-valprint.c, pa64solib.c, parse.c, ppc-linux-tdep.c: Update.
* ppcnbsd-tdep.c, printcmd.c, procfs.c, remote-e7000.c: Update.
* remote-fileio.c, remote-m32r-sdi.c, remote-rdi.c: Update.
* remote-rdp.c, remote-sim.c, remote-st.c: Update.
* remote-utils.c, remote-utils.h, remote.c: Update.
* rom68k-rom.c, rs6000-nat.c, s390-tdep.c, scm-lang.c: Update.
* ser-e7kpc.c, ser-tcp.c, ser-unix.c, sh-tdep.c: Update.
* sh3-rom.c, shnbsd-tdep.c, sol-thread.c, solib-aix5.c: Update.
* solib-frv.c, solib-irix.c, solib-osf.c, solib-pa64.c: Update.
* solib-som.c, solib-sunos.c, solib-svr4.c, solib.c: Update.
* somread.c, somsolib.c, source.c, stabsread.c: Update.
* stack.c, std-regs.c, symfile-mem.c, symfile.c: Update.
* symmisc.c, symtab.c, target.c, thread.c, top.c: Update.
* tracepoint.c, trad-frame.c, typeprint.c, utils.c: Update.
* uw-thread.c, valarith.c, valops.c, valprint.c: Update.
* value.c, varobj.c, version.in, win32-nat.c, wince.c: Update.
* xcoffread.c, xcoffsolib.c, cli/cli-cmds.c: Update.
* cli/cli-decode.c, cli/cli-dump.c, cli/cli-logging.c: Update.
* cli/cli-script.c, cli/cli-setshow.c, mi/mi-cmd-break.c: Update.
* mi/mi-cmd-disas.c, mi/mi-cmd-env.c, mi/mi-cmd-file.c: Update.
* mi/mi-cmd-stack.c, mi/mi-cmd-var.c, mi/mi-getopt.c: Update.
* mi/mi-symbol-cmds.c, tui/tui-layout.c, tui/tui-stack.c: Update.
* tui/tui-win.c: Update.
2005-02-11 12:06:14 +08:00
|
|
|
|
error (_("Internal error in eval_type."));
|
Remove union exp_element
This removes union exp_element functions that either create such
elements or walk them. struct expression no longer holds
exp_elements. A couple of language_defn methods are also removed, as
they are obsolete.
Note that this patch also removes the print_expression code. The only
in-tree caller of this was from dump_prefix_expression, which is only
called when expression debugging is enabled. Implementing this would
involve a fair amount of code, and it seems to me that prefix dumping
is preferable anyway, as it is unambiguous. So, I have not
reimplemented this feature.
gdb/ChangeLog
2021-03-08 Tom Tromey <tom@tromey.com>
* value.h (evaluate_subexp_with_coercion): Don't declare.
* parse.c (exp_descriptor_standard): Remove.
(expr_builder::expr_builder, expr_builder::release): Update.
(expression::expression): Remove size_t parameter.
(expression::~expression): Simplify.
(expression::resize): Remove.
(write_exp_elt, write_exp_elt_opcode, write_exp_elt_sym)
(write_exp_elt_msym, write_exp_elt_block, write_exp_elt_objfile)
(write_exp_elt_longcst, write_exp_elt_floatcst)
(write_exp_elt_type, write_exp_elt_intern, write_exp_string)
(write_exp_string_vector, write_exp_bitstring): Remove.
* p-lang.h (class pascal_language) <opcode_print_table,
op_print_tab>: Remove.
* p-lang.c (pascal_language::op_print_tab): Remove.
* opencl-lang.c (class opencl_language) <opcode_print_table>:
Remove.
* objc-lang.c (objc_op_print_tab): Remove.
(class objc_language) <opcode_print_table>: Remove.
* m2-lang.h (class m2_language) <opcode_print_table,
op_print_tab>: Remove.
* m2-lang.c (m2_language::op_print_tab): Remove.
* language.h (struct language_defn) <post_parser, expression_ops,
opcode_print_table>: Remove.
* language.c (language_defn::expression_ops)
(auto_or_unknown_language::opcode_print_table): Remove.
* go-lang.h (class go_language) <opcode_print_table,
op_print_tab>: Remove.
* go-lang.c (go_language::op_print_tab): Remove.
* f-lang.h (class f_language) <opcode_print_table>: Remove
<op_print_tab>: Remove.
* f-lang.c (f_language::op_print_tab): Remove.
* expression.h (union exp_element): Remove.
(struct expression): Remove size_t parameter from constructor.
<resize>: Remove.
<first_opcode>: Update.
<nelts, elts>: Remove.
(EXP_ELEM_TO_BYTES, BYTES_TO_EXP_ELEM): Remove.
(evaluate_subexp_standard, print_expression, op_string)
(dump_raw_expression): Don't declare.
* expprint.c (print_expression, print_subexp)
(print_subexp_funcall, print_subexp_standard, op_string)
(dump_raw_expression, dump_subexp, dump_subexp_body)
(dump_subexp_body_funcall, dump_subexp_body_standard): Remove.
(dump_prefix_expression): Update.
* eval.c (evaluate_subexp): Remove.
(evaluate_expression, evaluate_type): Update.
(evaluate_subexpression_type): Remove.
(fetch_subexp_value): Remove "pc" parameter. Update.
(extract_field_op, evaluate_struct_tuple, evaluate_funcall)
(evaluate_subexp_standard, evaluate_subexp_for_address)
(evaluate_subexp_with_coercion, evaluate_subexp_for_sizeof)
(evaluate_subexp_for_cast): Remove.
(parse_and_eval_type): Update.
* dtrace-probe.c (dtrace_probe::compile_to_ax): Update.
* d-lang.c (d_op_print_tab): Remove.
(class d_language) <opcode_print_table>: Remove.
* c-lang.h (c_op_print_tab): Don't declare.
* c-lang.c (c_op_print_tab): Remove.
(class c_language, class cplus_language, class asm_language, class
minimal_language) <opcode_print_table>: Remove.
* breakpoint.c (update_watchpoint, watchpoint_check)
(watchpoint_exp_is_const, watch_command_1): Update.
* ax-gdb.h (union exp_element): Don't declare.
* ax-gdb.c (const_var_ref, const_expr, maybe_const_expr)
(gen_repeat, gen_sizeof, gen_expr_for_cast, gen_expr)
(gen_expr_binop_rest): Remove.
(gen_trace_for_expr, gen_eval_for_expr, gen_printf): Update.
* ada-lang.c (ada_op_print_tab): Remove.
(class ada_language) <post_parser, opcode_print_table>: Remove.
2021-03-08 22:27:57 +08:00
|
|
|
|
return op->get_type ();
|
1999-04-16 09:35:26 +08:00
|
|
|
|
}
|