From: Zoran Zaric Date: Wed, 18 Nov 2020 10:42:39 +0000 (+0000) Subject: Remove dwarf_expr_context from expr.h interface X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=54ecae43a304bc9421e09d96c08c030ff3ef4244;p=thirdparty%2Fbinutils-gdb.git Remove dwarf_expr_context from expr.h interface After the switch to the new evaluator implementation, it is now possible to completely remove the dwarf_expr_context class from the expr.h interface and encapsulate it inside the expr.c file. The new interface consists of a new function called dwarf2_evaluate that takes a DWARF expression stream, initial DWARF stack elements (in a form of a vector of a struct value objects), evaluation context and expected result type information. Function returns an evaluation result in a form of a struct value object. Currently, there is ever only one initial stack element provided to the evaluator and that element is always a memory address, so having a vector of struct value object might seems like an overkill. In reality this new flexibility allows implementation of a new DWARF attribute extensions that could provide any number of initial stack elements to describe any location description or value. gdb/ChangeLog: * dwarf2/expr.c (dwarf2_evaluate): New function. (struct dwarf_expr_context): Move from expr.h. (class dwarf_entry): Move from expr.h (dwarf_expr_context::push_address): Remove function. * dwarf2/expr.h (struct dwarf_expr_context): Move to expr.c. (class dwarf_entry): Move to expr.c. (address_type): Expose function. * dwarf2/frame.c (execute_stack_op): Now calls dwarf2_evaluate. * dwarf2/loc.c (dwarf2_evaluate_loc_desc_full): Now calls dwarf2_evaluate. (dwarf2_locexpr_baton_eval): Now calls dwarf2_evaluate. --- diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c index ec7a8d13dc8..8ebc1dfdfe4 100644 --- a/gdb/dwarf2/expr.c +++ b/gdb/dwarf2/expr.c @@ -285,12 +285,7 @@ write_to_memory (CORE_ADDR address, const gdb_byte *buffer, length, buffer); } -/* Return the type used for DWARF operations where the type is - generic in the DWARF spec, the ARCH is a target architecture - of the type and ADDR_SIZE is expected size of the address. - Only certain sizes are supported. */ - -static type * +type * address_type (gdbarch *arch, int addr_size) { dwarf_gdbarch_types *types @@ -408,6 +403,23 @@ private: frame_info *m_frame = nullptr; }; +/* Base class that describes entries found on a DWARF expression + evaluation stack. */ + +class dwarf_entry +{ +protected: + /* Not expected to be called on it's own. */ + dwarf_entry () = default; + +public: + virtual ~dwarf_entry () = default; + + virtual std::unique_ptr clone () const = 0; +}; + +using dwarf_entry_up = std::unique_ptr; + /* Location description entry found on a DWARF expression evaluation stack. @@ -2400,11 +2412,130 @@ sect_variable_value (sect_offset sect_off, type, true); } +/* The expression evaluator works with a dwarf_expr_context, describing + its current state and its callbacks. */ +struct dwarf_expr_context +{ + /* Create a new context for the expression evaluator. + + We should ever only pass in the PER_OBJFILE and the ADDR_SIZE + information should be retrievable from there. The PER_OBJFILE + contains a pointer to the PER_BFD information anyway and the + address size information must be the same for the whole BFD. */ + dwarf_expr_context (dwarf2_per_objfile *per_objfile, + int addr_size); + + /* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU + FRAME context. INIT_VALUES vector contains values that are + expected to be pushed on a DWARF expression stack before the + evaluation. AS_LVAL defines if the returned struct value is + expected to be a value or a location description. Where TYPE, + SUBOBJ_TYPE and SUBOBJ_OFFSET describe expected struct value + representation of the evaluation result. The ADDR_INFO property + can be specified to override the range of memory addresses with + the passed in buffer. */ + struct value *evaluate (const gdb_byte *addr, size_t len, bool as_lval, + dwarf2_per_cu_data *per_cu, frame_info *frame, + std::vector *init_values, + const property_addr_info *addr_info, + struct type *type, struct type *subobj_type, + LONGEST subobj_offset); + +private: + /* The stack of DWARF entries. */ + std::vector m_stack; + + /* Target address size in bytes. */ + int m_addr_size; + + /* The current depth of dwarf expression recursion, via DW_OP_call*, + DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum + depth we'll tolerate before raising an error. */ + int m_recursion_depth = 0, m_max_recursion_depth = 0x100; + + /* We evaluate the expression in the context of this objfile. */ + dwarf2_per_objfile *m_per_objfile; + + /* Frame information used for the evaluation. */ + frame_info *m_frame = nullptr; + + /* Compilation unit used for the evaluation. */ + dwarf2_per_cu_data *m_per_cu = nullptr; + + /* Property address info used for the evaluation. */ + const property_addr_info *m_addr_info = nullptr; + + /* Evaluate the expression at ADDR (LEN bytes long). */ + void eval (const gdb_byte *addr, size_t len); + + /* Return the type used for DWARF operations where the type is + unspecified in the DWARF spec. Only certain sizes are + supported. */ + type *address_type () const; + + /* Push ENTRY onto the stack. */ + void push (dwarf_entry_up value); + + /* Return true if the expression stack is empty. */ + bool stack_empty_p () const; + + /* Pop a top element of the stack and add as a composite piece + with an BIT_OFFSET offset and of a BIT_SIZE size. + + If the following top element of the stack is a composite + location description, the piece will be added to it. Otherwise + a new composite location description will be created, pushed on + the stack and the piece will be added to that composite. */ + void add_piece (ULONGEST bit_size, ULONGEST bit_offset); + + /* The engine for the expression evaluator. Using the context in this + object, evaluate the expression between OP_PTR and OP_END. */ + void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end); + + /* Pop the top item off of the stack. */ + dwarf_entry_up pop (); + + /* Retrieve the N'th item on the stack. */ + dwarf_entry &fetch (int n); + + /* Fetch the result of the expression evaluation in a form of + a struct value, where TYPE, SUBOBJ_TYPE and SUBOBJ_OFFSET + describe the source level representation of that result. + AS_LVAL defines if the fetched struct value is expected to + be a value or a location description. */ + value *fetch_result (struct type *type, struct type *subobj_type, + LONGEST subobj_offset, bool as_lval); + + /* Return the location expression for the frame base attribute, in + START and LENGTH. The result must be live until the current + expression evaluation is complete. */ + void get_frame_base (const gdb_byte **start, size_t *length); + + /* Return the base type given by the indicated DIE at DIE_CU_OFF. + This can throw an exception if the DIE is invalid or does not + represent a base type. */ + type *get_base_type (cu_offset die_cu_off); + + /* Execute DW_AT_location expression for the DWARF expression + subroutine in the DIE at DIE_CU_OFF in the CU. Do not touch + STACK while it being passed to and returned from the called DWARF + subroutine. */ + void dwarf_call (cu_offset die_cu_off); + + /* Push on DWARF stack an entry evaluated for DW_TAG_call_site's + parameter matching KIND and KIND_U at the caller of specified + BATON. If DEREF_SIZE is not -1 then use DW_AT_call_data_value + instead of DW_AT_call_value. */ + void push_dwarf_reg_entry_value (call_site_parameter_kind kind, + call_site_parameter_u kind_u, + int deref_size); +}; + /* Return the type used for DWARF operations where the type is unspecified in the DWARF spec. Only certain sizes are supported. */ -struct type * +type * dwarf_expr_context::address_type () const { return ::address_type (this->m_per_objfile->objfile->arch (), @@ -2420,26 +2551,12 @@ dwarf_expr_context::dwarf_expr_context (dwarf2_per_objfile *per_objfile, { } -/* See expr.h. */ - void dwarf_expr_context::push (dwarf_entry_up entry) { this->m_stack.emplace_back (std::move (entry)); } -/* See expr.h. */ - -void -dwarf_expr_context::push_address (CORE_ADDR addr, bool in_stack_memory) -{ - this->m_stack.emplace_back (std::make_unique - (this->m_per_objfile->objfile->arch (), addr, in_stack_memory)); -} - - -/* See expr.h. */ - dwarf_entry_up dwarf_expr_context::pop () { @@ -2451,8 +2568,6 @@ dwarf_expr_context::pop () return entry; } -/* See expr.h. */ - dwarf_entry & dwarf_expr_context::fetch (int n) { @@ -2463,8 +2578,6 @@ dwarf_expr_context::fetch (int n) return *this->m_stack[this->m_stack.size () - (1 + n)]; } -/* See expr.h. */ - void dwarf_expr_context::get_frame_base (const gdb_byte **start, size_t * length) @@ -2491,24 +2604,20 @@ dwarf_expr_context::get_frame_base (const gdb_byte **start, start, length); } -/* See expr.h. */ - -struct type * +type * dwarf_expr_context::get_base_type (cu_offset die_cu_off) { if (this->m_per_cu == nullptr) return builtin_type (this->m_per_objfile->objfile->arch ())->builtin_int; - struct type *result = dwarf2_get_die_type (die_cu_off, this->m_per_cu, - this->m_per_objfile); + type *result = dwarf2_get_die_type (die_cu_off, this->m_per_cu, + this->m_per_objfile); if (result == nullptr) error (_("Could not find type for operation")); return result; } -/* See expr.h. */ - void dwarf_expr_context::dwarf_call (cu_offset die_cu_off) { @@ -2532,8 +2641,6 @@ dwarf_expr_context::dwarf_call (cu_offset die_cu_off) this->eval (block.data, block.size); } -/* See expr.h. */ - void dwarf_expr_context::push_dwarf_reg_entry_value (call_site_parameter_kind kind, call_site_parameter_u kind_u, @@ -2580,8 +2687,6 @@ dwarf_expr_context::push_dwarf_reg_entry_value (call_site_parameter_kind kind, this->eval (data_src, size); } -/* See expr.h. */ - value * dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type, LONGEST subobj_offset, bool as_lval) @@ -2607,18 +2712,22 @@ dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type, } } -/* See expr.h. */ - value * dwarf_expr_context::evaluate (const gdb_byte *addr, size_t len, bool as_lval, dwarf2_per_cu_data *per_cu, frame_info *frame, - const struct property_addr_info *addr_info, + std::vector *init_values, + const property_addr_info *addr_info, struct type *type, struct type *subobj_type, LONGEST subobj_offset) { this->m_per_cu = per_cu; this->m_frame = frame; this->m_addr_info = addr_info; + gdbarch *arch = this->m_per_objfile->objfile->arch (); + + if (init_values != nullptr) + for (value *val : *init_values) + push (gdb_value_to_dwarf_entry (arch, val)); eval (addr, len); return fetch_result (type, subobj_type, subobj_offset, as_lval); @@ -2679,16 +2788,12 @@ get_signed_type (struct gdbarch *gdbarch, struct type *type) } } -/* See expr.h. */ - bool dwarf_expr_context::stack_empty_p () const { return this->m_stack.empty (); } -/* See expr.h. */ - void dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset) { @@ -2740,9 +2845,6 @@ dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset) composite->add_piece (std::move (piece), bit_size); } - -/* See expr.h. */ - void dwarf_expr_context::eval (const gdb_byte *addr, size_t len) { @@ -2981,8 +3083,6 @@ dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf, return 1; } -/* See expr.h. */ - void dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end) @@ -3940,6 +4040,24 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr, gdb_assert (this->m_recursion_depth >= 0); } +/* See expr.h. */ + +value * +dwarf2_evaluate (const gdb_byte *addr, size_t len, bool as_lval, + dwarf2_per_objfile *per_objfile, dwarf2_per_cu_data *per_cu, + frame_info *frame, int addr_size, + std::vector *init_values, + const property_addr_info *addr_info, + struct type *type, struct type *subobj_type, + LONGEST subobj_offset) +{ + dwarf_expr_context ctx (per_objfile, addr_size); + + return ctx.evaluate (addr, len, as_lval, per_cu, + frame, init_values, addr_info, + type, subobj_type, subobj_offset); +} + void _initialize_dwarf2expr (); void _initialize_dwarf2expr () diff --git a/gdb/dwarf2/expr.h b/gdb/dwarf2/expr.h index aa371e4bda6..df097f8867d 100644 --- a/gdb/dwarf2/expr.h +++ b/gdb/dwarf2/expr.h @@ -25,150 +25,31 @@ #include "leb128.h" #include "gdbtypes.h" -/* Base class that describes entries found on a DWARF expression - evaluation stack. */ - -class dwarf_entry -{ -protected: - /* Not expected to be called on it's own. */ - dwarf_entry () = default; - -public: - virtual ~dwarf_entry () = default; - - virtual std::unique_ptr clone () const = 0; -}; - -using dwarf_entry_up = std::unique_ptr; - struct dwarf2_per_objfile; -/* The expression evaluator works with a dwarf_expr_context, describing - its current state and its callbacks. */ -struct dwarf_expr_context -{ - /* Create a new context for the expression evaluator. - - We should ever only pass in the PER_OBJFILE and the ADDR_SIZE - information should be retrievable from there. The PER_OBJFILE - contains a pointer to the PER_BFD information anyway and the - address size information must be the same for the whole BFD. */ - dwarf_expr_context (dwarf2_per_objfile *per_objfile, int addr_size); - - virtual ~dwarf_expr_context () = default; - - /* Push ADDR onto the stack. */ - void push_address (CORE_ADDR addr, bool in_stack_memory); - - /* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU - and FRAME context. - - AS_LVAL defines if the returned struct value is expected to be a - value (false) or a location description (true). - - TYPE, SUBOBJ_TYPE and SUBOBJ_OFFSET describe the expected struct - value representation of the evaluation result. - - The ADDR_INFO property can be specified to override the range of - memory addresses with the passed in buffer. */ - value *evaluate (const gdb_byte *addr, size_t len, bool as_lval, - dwarf2_per_cu_data *per_cu, frame_info *frame, - const struct property_addr_info *addr_info = nullptr, - struct type *type = nullptr, - struct type *subobj_type = nullptr, - LONGEST subobj_offset = 0); - -private: - /* The stack of DWARF entries. */ - std::vector m_stack; - - /* Target address size in bytes. */ - int m_addr_size = 0; - - /* The current depth of dwarf expression recursion, via DW_OP_call*, - DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum - depth we'll tolerate before raising an error. */ - int m_recursion_depth = 0, m_max_recursion_depth = 0x100; - - /* We evaluate the expression in the context of this objfile. */ - dwarf2_per_objfile *m_per_objfile; - - /* Frame information used for the evaluation. */ - frame_info *m_frame = nullptr; - - /* Compilation unit used for the evaluation. */ - dwarf2_per_cu_data *m_per_cu = nullptr; - - /* Property address info used for the evaluation. */ - const struct property_addr_info *m_addr_info = nullptr; - - /* Evaluate the expression at ADDR (LEN bytes long). */ - void eval (const gdb_byte *addr, size_t len); - - /* Return the type used for DWARF operations where the type is - unspecified in the DWARF spec. Only certain sizes are - supported. */ - struct type *address_type () const; - - /* Push ENTRY onto the stack. */ - void push (dwarf_entry_up entry); - - /* Return true if the expression stack is empty. */ - bool stack_empty_p () const; - - /* Pop a top element of the stack and add as a composite piece - with an BIT_OFFSET offset and of a BIT_SIZE size. - - If the following top element of the stack is a composite - location description, the piece will be added to it. Otherwise - a new composite location description will be created, pushed on - the stack and the piece will be added to that composite. */ - void add_piece (ULONGEST bit_size, ULONGEST bit_offset); - - /* The engine for the expression evaluator. Using the context in - this object, evaluate the expression between OP_PTR and - OP_END. */ - void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end); - - /* Pop the top item off of the stack. */ - dwarf_entry_up pop (); - - /* Retrieve the N'th item on the stack. */ - dwarf_entry &fetch (int n); - - /* Fetch the result of the expression evaluation in a form of - a struct value, where TYPE, SUBOBJ_TYPE and SUBOBJ_OFFSET - describe the source level representation of that result. - AS_LVAL defines if the fetched struct value is expected to - be a value or a location description. */ - value *fetch_result (struct type *type, struct type *subobj_type, - LONGEST subobj_offset, bool as_lval); - - /* Return the location expression for the frame base attribute, in - START and LENGTH. The result must be live until the current - expression evaluation is complete. */ - void get_frame_base (const gdb_byte **start, size_t *length); - - /* Return the base type given by the indicated DIE at DIE_CU_OFF. - This can throw an exception if the DIE is invalid or does not - represent a base type. */ - struct type *get_base_type (cu_offset die_cu_off); - - /* Execute DW_AT_location expression for the DWARF expression - subroutine in the DIE at DIE_CU_OFF in the CU. Do not touch - STACK while it being passed to and returned from the called DWARF - subroutine. */ - void dwarf_call (cu_offset die_cu_off); - - /* Push on DWARF stack an entry evaluated for DW_TAG_call_site's - parameter matching KIND and KIND_U at the caller of specified BATON. - If DEREF_SIZE is not -1 then use DW_AT_call_data_value instead of - DW_AT_call_value. */ - void push_dwarf_reg_entry_value (call_site_parameter_kind kind, - call_site_parameter_u kind_u, - int deref_size); -}; +/* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU + FRAME context. The PER_OBJFILE contains a pointer to the PER_BFD + information. ADDR_SIZE defines a size of the DWARF generic type. + INIT_VALUES vector contains values that are expected to be pushed + on a DWARF expression stack before the evaluation. AS_LVAL defines + if the returned struct value is expected to be a value or a location + description. Where TYPE, SUBOBJ_TYPE and SUBOBJ_OFFSET describe + expected struct value representation of the evaluation result. The + ADDR_INFO property can be specified to override the range of memory + addresses with the passed in buffer. */ +value *dwarf2_evaluate (const gdb_byte *addr, size_t len, bool as_lval, + dwarf2_per_objfile *per_objfile, + dwarf2_per_cu_data *per_cu, + frame_info *frame, int addr_size, + std::vector *init_values, + const struct property_addr_info *addr_info, + struct type *type = nullptr, + struct type *subobj_type = nullptr, + LONGEST subobj_offset = 0); + +/* Return the address type used of the ARCH architecture and + ADDR_SIZE is expected size of the type. */ +type *address_type (gdbarch *arch, int addr_size); /* Return the value of register number REG (a DWARF register number), read as an address in a given FRAME. */ diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c index f3d38771708..f97387a9d71 100644 --- a/gdb/dwarf2/frame.c +++ b/gdb/dwarf2/frame.c @@ -229,11 +229,19 @@ execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size, struct frame_info *this_frame, CORE_ADDR initial, int initial_in_stack_memory, dwarf2_per_objfile *per_objfile) { - dwarf_expr_context ctx (per_objfile, addr_size); scoped_value_mark free_values; + struct type *type = address_type (per_objfile->objfile->arch (), + addr_size); - ctx.push_address (initial, initial_in_stack_memory); - value *result_val = ctx.evaluate (exp, len, true, nullptr, this_frame); + value *init_value = value_at_lazy (type, initial); + std::vector init_values; + + set_value_stack (init_value, initial_in_stack_memory); + init_values.push_back (init_value); + + value *result_val + = dwarf2_evaluate (exp, len, true, per_objfile, nullptr, + this_frame, addr_size, &init_values, nullptr); if (VALUE_LVAL (result_val) == lval_memory) return value_address (result_val); diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c index eb128fa5fc6..753ebbbae6c 100644 --- a/gdb/dwarf2/loc.c +++ b/gdb/dwarf2/loc.c @@ -1474,15 +1474,15 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, if (size == 0) return allocate_optimized_out_value (subobj_type); - dwarf_expr_context ctx (per_objfile, per_cu->addr_size ()); - value *retval; scoped_value_mark free_values; try { - retval = ctx.evaluate (data, size, as_lval, per_cu, frame, nullptr, - type, subobj_type, subobj_byte_offset); + retval + = dwarf2_evaluate (data, size, as_lval, per_objfile, per_cu, + frame, per_cu->addr_size (), nullptr, nullptr, + type, subobj_type, subobj_byte_offset); } catch (const gdb_exception_error &ex) { @@ -1553,23 +1553,28 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton, dwarf2_per_objfile *per_objfile = dlbaton->per_objfile; dwarf2_per_cu_data *per_cu = dlbaton->per_cu; - dwarf_expr_context ctx (per_objfile, per_cu->addr_size ()); value *result; scoped_value_mark free_values; + std::vector init_values; if (push_initial_value) { + struct type *type = address_type (per_objfile->objfile->arch (), + per_cu->addr_size ()); + if (addr_stack != nullptr) - ctx.push_address (addr_stack->addr, false); + init_values.push_back (value_at_lazy (type, addr_stack->addr)); else - ctx.push_address (0, false); + init_values.push_back (value_at_lazy (type, 0)); } try { - result = ctx.evaluate (dlbaton->data, dlbaton->size, - true, per_cu, frame, addr_stack); + result + = dwarf2_evaluate (dlbaton->data, dlbaton->size, true, per_objfile, + per_cu, frame, per_cu->addr_size (), &init_values, + addr_stack); } catch (const gdb_exception_error &ex) {