From c12b925f78ae5ae9ea22ec360d15c12559c292d8 Mon Sep 17 00:00:00 2001 From: Zoran Zaric Date: Mon, 7 Dec 2020 19:00:23 +0000 Subject: [PATCH] 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_eval_exp 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_eval_exp): New function. (struct dwarf_expr_context): Move from expr.h. (dwarf_expr_context::push_address): Remove function. * dwarf2/expr.h (struct dwarf_expr_context): Move to expr.c. * dwarf2/frame.c (execute_stack_op): Now calls dwarf2_eval_exp. * dwarf2/loc.c (dwarf2_evaluate_loc_desc_full): Now calls dwarf2_eval_exp. (dwarf2_locexpr_baton_eval): Now calls dwarf2_eval_exp. Change-Id: I5b2cce5424546d48fd00fb95d53681e41478cd09 --- gdb/dwarf2/expr.c | 226 ++++++++++++++++++++++++++++++++++++--------- gdb/dwarf2/expr.h | 181 ++++-------------------------------- gdb/dwarf2/frame.c | 14 ++- gdb/dwarf2/loc.c | 23 +++-- 4 files changed, 227 insertions(+), 217 deletions(-) diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c index aefbeb3dad9..9ed0ad8baf6 100644 --- a/gdb/dwarf2/expr.c +++ b/gdb/dwarf2/expr.c @@ -1820,7 +1820,165 @@ sect_variable_value (sect_offset sect_off, type, true); } -/* See expr.h. */ +/* 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 (struct dwarf2_per_objfile *per_objfile, + int addr_size); + + /* Destroy dwarf entry factory object. */ + virtual ~dwarf_expr_context (); + + /* 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 *eval_exp (const gdb_byte *addr, size_t len, bool as_lval, + struct dwarf2_per_cu_data *per_cu, + struct frame_info *frame, + std::vector *init_values, + const struct property_addr_info *addr_info, + struct type *type, struct type *subobj_type, + LONGEST subobj_offset); + +private: + /* The stack of values. */ + std::vector stack; + + /* Target architecture to use for address operations. */ + struct gdbarch *gdbarch; + + /* Target address size in bytes. */ + int addr_size; + + /* DW_FORM_ref_addr size in bytes. If -1 DWARF is executed + from a frame context and operations depending on DW_FORM_ref_addr + are not allowed. */ + int ref_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 recursion_depth, max_recursion_depth; + + /* We evaluate the expression in the context of this objfile. */ + dwarf2_per_objfile *per_objfile; + + /* Frame information used for the evaluation. */ + struct frame_info *frame; + + /* Compilation unit used for the evaluation. */ + struct dwarf2_per_cu_data *per_cu; + + /* Property address info used for the evaluation. */ + const struct property_addr_info *addr_info; + + /* Factory in charge of the dwarf entry's life cycle. */ + dwarf_entry_factory *entry_factory; + + /* 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 *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. + + If the fallowing 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 and + the piece will be added to that composite. */ + dwarf_entry *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. */ + void 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. */ + struct 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. SIZE is non-zero if this function should + verify that the resulting type has the correct size. */ + struct type *get_base_type (cu_offset die_cu_off, int size); + + /* 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 (enum call_site_parameter_kind kind, + union call_site_parameter_u kind_u, + int deref_size); + + /* Apply dereference operation on the DWARF ENTRY. In the case of a + value entry, the entry will be implicitly converted to the + appropriate location description before the operation is applied. + If the SIZE is specified, it must be equal or smaller then the + TYPE type size. If SIZE is smaller then the type size, the value + will be zero extended to the difference. */ + dwarf_entry* dwarf_entry_deref (dwarf_entry *entry, struct type *type, + size_t size = 0); + + /* Convert struct value to the matching DWARF entry representation. + Used for non-standard DW_OP_GNU_variable_value operation + support. */ + dwarf_entry *gdb_value_to_dwarf_entry (struct value *value); + + /* Convert DWARF entry to the matching struct value representation + of the given TYPE type. SUBOBJ_TYPE information if specified, will + be used for more precise description of the source variable type + information. Where SUBOBJ_OFFSET defines an offset into the DWARF + entry contents. */ + struct value *dwarf_entry_to_gdb_value (dwarf_entry *entry, + struct type *type, + struct type *subobj_type = nullptr, + LONGEST subobj_offset = 0); +}; struct type * address_type (struct gdbarch *gdbarch, int addr_size) @@ -1875,31 +2033,17 @@ dwarf_expr_context::dwarf_expr_context (dwarf2_per_objfile *per_objfile, entry_factory = new dwarf_entry_factory (); } -/* See expr.h. */ - dwarf_expr_context::~dwarf_expr_context () { delete entry_factory; } -/* See expr.h. */ - void dwarf_expr_context::push (dwarf_entry *entry) { stack.emplace_back (entry); } -/* See expr.h. */ - -void -dwarf_expr_context::push_address (CORE_ADDR addr, bool in_stack_memory) -{ - stack.emplace_back (entry_factory->create_memory (addr, 0, in_stack_memory)); -} - -/* See expr.h. */ - void dwarf_expr_context::pop () { @@ -1909,8 +2053,6 @@ dwarf_expr_context::pop () stack.pop_back (); } -/* See expr.h. */ - dwarf_entry * dwarf_expr_context::fetch (int n) { @@ -1921,8 +2063,6 @@ dwarf_expr_context::fetch (int n) return stack[stack.size () - (1 + n)]; } -/* See expr.h. */ - void dwarf_expr_context::get_frame_base (const gdb_byte **start, size_t * length) @@ -1949,8 +2089,6 @@ dwarf_expr_context::get_frame_base (const gdb_byte **start, start, length); } -/* See expr.h. */ - struct type * dwarf_expr_context::get_base_type (cu_offset die_cu_off, int size) { @@ -1968,8 +2106,6 @@ dwarf_expr_context::get_base_type (cu_offset die_cu_off, int size) return result; } -/* See expr.h. */ - void dwarf_expr_context::dwarf_call (cu_offset die_cu_off) { @@ -1993,8 +2129,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 (enum call_site_parameter_kind kind, @@ -2044,8 +2178,6 @@ dwarf_expr_context::push_dwarf_reg_entry_value this->eval (data_src, size); } -/* See expr.h. */ - struct value * dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type, @@ -2068,12 +2200,11 @@ dwarf_expr_context::fetch_result (struct type *type, return dwarf_entry_to_gdb_value (entry, type, subobj_type, subobj_offset); } -/* See expr.h. */ - struct value * dwarf_expr_context::eval_exp (const gdb_byte *addr, size_t len, bool as_lval, struct dwarf2_per_cu_data *per_cu, struct frame_info *frame, + std::vector *init_values, const struct property_addr_info *addr_info, struct type *type, struct type *subobj_type, @@ -2086,12 +2217,14 @@ dwarf_expr_context::eval_exp (const gdb_byte *addr, size_t len, bool as_lval, if (per_cu != nullptr) this->ref_addr_size = per_cu->ref_addr_size (); + if (init_values != nullptr) + for (unsigned int i = 0; i < init_values->size (); i++) + push (gdb_value_to_dwarf_entry ((*init_values)[i])); + eval (addr, len); return fetch_result (type, subobj_type, subobj_offset, as_lval); } -/* See expr.h. */ - dwarf_entry * dwarf_expr_context::dwarf_entry_deref (dwarf_entry *entry, struct type *type, size_t size) @@ -2167,8 +2300,6 @@ dwarf_expr_context::dwarf_entry_deref (dwarf_entry *entry, return entry_factory->create_value (read_buf.data (), type); } -/* See expr.h. */ - dwarf_entry * dwarf_expr_context::gdb_value_to_dwarf_entry (struct value *value) { @@ -2215,8 +2346,6 @@ dwarf_expr_context::gdb_value_to_dwarf_entry (struct value *value) } } -/* See expr.h. */ - struct value * dwarf_expr_context::dwarf_entry_to_gdb_value (dwarf_entry *entry, struct type *type, @@ -2387,16 +2516,12 @@ get_signed_type (struct gdbarch *gdbarch, struct type *type) } } -/* See expr.h. */ - bool dwarf_expr_context::stack_empty_p () const { return stack.empty (); } -/* See expr.h. */ - dwarf_entry * dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset) { @@ -2429,8 +2554,6 @@ dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset) return composite_entry; } -/* See expr.h. */ - void dwarf_expr_context::eval (const gdb_byte *addr, size_t len) { @@ -2667,8 +2790,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) @@ -3584,6 +3705,25 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr, gdb_assert (this->recursion_depth >= 0); } +/* See expr.h. */ + +struct value * +dwarf2_eval_exp (const gdb_byte *addr, size_t len, bool as_lval, + struct dwarf2_per_objfile *per_objfile, + struct dwarf2_per_cu_data *per_cu, + struct frame_info *frame, int addr_size, + std::vector *init_values, + const struct 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.eval_exp (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 19c28754bb5..5fb4b0857e9 100644 --- a/gdb/dwarf2/expr.h +++ b/gdb/dwarf2/expr.h @@ -25,170 +25,27 @@ #include "leb128.h" #include "gdbtypes.h" -class dwarf_entry; -class dwarf_entry_factory; 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 (struct dwarf2_per_objfile *per_objfile, - int addr_size); - - /* Destroy dwarf entry factory object. */ - virtual ~dwarf_expr_context (); - - /* 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 - FRAME context. 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 *eval_exp (const gdb_byte *addr, size_t len, bool as_lval, - struct dwarf2_per_cu_data *per_cu, - struct 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 values. */ - std::vector stack; - - /* Target architecture to use for address operations. */ - struct gdbarch *gdbarch; - - /* Target address size in bytes. */ - int addr_size; - - /* DW_FORM_ref_addr size in bytes. If -1 DWARF is executed - from a frame context and operations depending on DW_FORM_ref_addr - are not allowed. */ - int ref_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 recursion_depth, max_recursion_depth; - - /* We evaluate the expression in the context of this objfile. */ - dwarf2_per_objfile *per_objfile; - - /* Frame information used for the evaluation. */ - struct frame_info *frame; - - /* Compilation unit used for the evaluation. */ - struct dwarf2_per_cu_data *per_cu; - - /* Property address info used for the evaluation. */ - const struct property_addr_info *addr_info; - - /* Factory in charge of the dwarf entry's life cycle. */ - dwarf_entry_factory *entry_factory; - - /* 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 *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. - - If the fallowing 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 and - the piece will be added to that composite. */ - dwarf_entry *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. */ - void 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. */ - struct 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. SIZE is non-zero if this function should - verify that the resulting type has the correct size. */ - struct type *get_base_type (cu_offset die_cu_off, int size); - - /* 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 (enum call_site_parameter_kind kind, - union call_site_parameter_u kind_u, - int deref_size); - - /* Apply dereference operation on the DWARF ENTRY. In the case of a - value entry, the entry will be implicitly converted to the - appropriate location description before the operation is applied. - If the SIZE is specified, it must be equal or smaller then the - TYPE type size. If SIZE is smaller then the type size, the value - will be zero extended to the difference. */ - dwarf_entry* dwarf_entry_deref (dwarf_entry *entry, struct type *type, - size_t size = 0); - - /* Convert struct value to the matching DWARF entry representation. - Used for non-standard DW_OP_GNU_variable_value operation - support. */ - dwarf_entry *gdb_value_to_dwarf_entry (struct value *value); - - /* Convert DWARF entry to the matching struct value representation - of the given TYPE type. SUBOBJ_TYPE information if specified, will - be used for more precise description of the source variable type - information. Where SUBOBJ_OFFSET defines an offset into the DWARF - entry contents. */ - struct value *dwarf_entry_to_gdb_value (dwarf_entry *entry, - struct type *type, - struct type *subobj_type = nullptr, - LONGEST subobj_offset = 0); -}; +/* 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. */ +struct value *dwarf2_eval_exp (const gdb_byte *addr, size_t len, bool as_lval, + struct dwarf2_per_objfile *per_objfile, + struct dwarf2_per_cu_data *per_cu, + struct 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 GDBARCH architecture and ADDR_SIZE is expected size of the type. */ diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c index 40376531067..dd4eca9aac6 100644 --- a/gdb/dwarf2/frame.c +++ b/gdb/dwarf2/frame.c @@ -228,11 +228,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); - struct value *result_val = ctx.eval_exp (exp, len, true, nullptr, this_frame); + struct 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); + + struct value *result_val + = dwarf2_eval_exp (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 1a23e0b2da3..d2aa1eddc97 100644 --- a/gdb/dwarf2/loc.c +++ b/gdb/dwarf2/loc.c @@ -1434,15 +1434,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 ()); - struct value *retval; scoped_value_mark free_values; try { - retval = ctx.eval_exp (data, size, as_lval, per_cu, frame, nullptr, - type, subobj_type, subobj_byte_offset); + retval + = dwarf2_eval_exp (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) { @@ -1513,23 +1513,28 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton, dwarf2_per_objfile *per_objfile = dlbaton->per_objfile; struct dwarf2_per_cu_data *per_cu = dlbaton->per_cu; - dwarf_expr_context ctx (per_objfile, per_cu->addr_size ()); struct 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.eval_exp (dlbaton->data, dlbaton->size, - true, per_cu, frame, addr_stack); + result + = dwarf2_eval_exp (dlbaton->data, dlbaton->size, true, per_objfile, + per_cu, frame, per_cu->addr_size (), &init_values, + addr_stack); } catch (const gdb_exception_error &ex) { -- 2.47.2