mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-05 15:15:42 +00:00
To replace existing DWARF stack element (dwarf_stack_value) with dwarf_entry class based objects, a support for conversion between struct value and the new classes is needed. The reason for this is that dwarf_entry based classes are not designed to be visible outside the expr.c file. This makes the DWARF expression evaluator more self contained. This can be beneficial if there is ever a need to have a DWARF support in gdbserver. Once the conversion support is added, the current DWARF stack element can easily be swapped out. gdb/ChangeLog: * dwarf2/expr.c (dwarf_value_equal_op): New function. (dwarf_value_less_op): New function. (struct piece_closure): Change to use dwarf_entry based classes. (allocate_piece_closure): Change to use dwarf_entry based classes. (rw_pieced_value): Change to use dwarf_entry based classes. (check_pieced_synthetic_pointer): Change to use dwarf_entry based classes. (check_synthetic_pointer_location): New function. (indirect_pieced_value): Change to use dwarf_entry based classes. (indirect_from_location): New function. (coerce_pieced_ref): Change to use dwarf_entry based classes. (free_pieced_value_closure): Change to use dwarf_entry based classes. (dwarf_expr_context::~dwarf_expr_context): Instantiate dwarf_entry_factory object. (dwarf_expr_context::push): Change to use dwarf_entry based classes. (dwarf_expr_context::push_address): Change to use dwarf_entry based classes. (dwarf_expr_context::fetch): Change to use dwarf_entry based classes. (dwarf_expr_context::read_mem): Remove method. (dwarf_expr_context::fetch_result): Change to use dwarf_entry based classes. (dwarf_expr_context::dwarf_entry_deref): New method. (dwarf_expr_context::gdb_value_to_dwarf_entry): New method. (dwarf_expr_context::dwarf_entry_to_gdb_value): New method. (dwarf_expr_context::fetch_address): Change to use dwarf_entry based classes. (dwarf_expr_context::fetch_in_stack_memory): Change to use dwarf_entry based classes. (dwarf_expr_context::add_piece): Change to use dwarf_entry based classes. (dwarf_expr_context::execute_stack_op): Change to use dwarf_entry based classes. * dwarf2/expr.h (class dwarf_entry): New declaration. (class dwarf_entry_factory): New declaration. (enum dwarf_value_location): Remove enumeration. (struct dwarf_expr_piece): Remove structure. (struct dwarf_stack_value): Remove structure. (struct dwarf_expr_context): Change to use dwarf_entry based classes. Add dwarf_entry_factory object. Change-Id: I828c9b087c8ab3f57d9b208b360bcf5688810586
281 lines
11 KiB
C++
281 lines
11 KiB
C++
/* DWARF 2 Expression Evaluator.
|
|
|
|
Copyright (C) 2001-2020 Free Software Foundation, Inc.
|
|
|
|
Contributed by Daniel Berlin <dan@dberlin.org>.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#if !defined (DWARF2EXPR_H)
|
|
#define DWARF2EXPR_H
|
|
|
|
#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<dwarf_entry *> 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);
|
|
};
|
|
|
|
/* Return the address type used of the GDBARCH architecture and
|
|
ADDR_SIZE is expected size of the type. */
|
|
struct type *address_type (struct gdbarch *gdbarch, int addr_size);
|
|
|
|
/* Return the value of register number REG (a DWARF register number),
|
|
read as an address in a given FRAME. */
|
|
CORE_ADDR read_addr_from_reg (struct frame_info *, int);
|
|
|
|
/* Check that the current operator is either at the end of an
|
|
expression, or that it is followed by a composition operator or by
|
|
DW_OP_GNU_uninit (which should terminate the expression). */
|
|
void dwarf_expr_require_composition (const gdb_byte *, const gdb_byte *,
|
|
const char *);
|
|
|
|
/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_reg* return the
|
|
DWARF register number. Otherwise return -1. */
|
|
int dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end);
|
|
|
|
/* If <BUF..BUF_END] contains DW_FORM_block* with just DW_OP_breg*(0) and
|
|
DW_OP_deref* return the DWARF register number. Otherwise return -1.
|
|
DEREF_SIZE_RETURN contains -1 for DW_OP_deref; otherwise it contains the
|
|
size from DW_OP_deref_size. */
|
|
int dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf,
|
|
const gdb_byte *buf_end,
|
|
CORE_ADDR *deref_size_return);
|
|
|
|
/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_fbreg(X) fill
|
|
in FB_OFFSET_RETURN with the X offset and return 1. Otherwise return 0. */
|
|
int dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
|
|
CORE_ADDR *fb_offset_return);
|
|
|
|
/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_bregSP(X) fill
|
|
in SP_OFFSET_RETURN with the X offset and return 1. Otherwise return 0.
|
|
The matched SP register number depends on GDBARCH. */
|
|
int dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
|
|
const gdb_byte *buf_end,
|
|
CORE_ADDR *sp_offset_return);
|
|
|
|
/* Wrappers around the leb128 reader routines to simplify them for our
|
|
purposes. */
|
|
|
|
static inline const gdb_byte *
|
|
gdb_read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end,
|
|
uint64_t *r)
|
|
{
|
|
size_t bytes_read = read_uleb128_to_uint64 (buf, buf_end, r);
|
|
|
|
if (bytes_read == 0)
|
|
return NULL;
|
|
return buf + bytes_read;
|
|
}
|
|
|
|
static inline const gdb_byte *
|
|
gdb_read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end,
|
|
int64_t *r)
|
|
{
|
|
size_t bytes_read = read_sleb128_to_int64 (buf, buf_end, r);
|
|
|
|
if (bytes_read == 0)
|
|
return NULL;
|
|
return buf + bytes_read;
|
|
}
|
|
|
|
static inline const gdb_byte *
|
|
gdb_skip_leb128 (const gdb_byte *buf, const gdb_byte *buf_end)
|
|
{
|
|
size_t bytes_read = skip_leb128 (buf, buf_end);
|
|
|
|
if (bytes_read == 0)
|
|
return NULL;
|
|
return buf + bytes_read;
|
|
}
|
|
|
|
/* Helper to read a uleb128 value or throw an error. */
|
|
extern const gdb_byte *safe_read_uleb128 (const gdb_byte *buf,
|
|
const gdb_byte *buf_end,
|
|
uint64_t *r);
|
|
|
|
/* Helper to read a sleb128 value or throw an error. */
|
|
extern const gdb_byte *safe_read_sleb128 (const gdb_byte *buf,
|
|
const gdb_byte *buf_end,
|
|
int64_t *r);
|
|
|
|
/* Helper to skip a leb128 value or throw an error. */
|
|
extern const gdb_byte *safe_skip_leb128 (const gdb_byte *buf,
|
|
const gdb_byte *buf_end);
|
|
|
|
#endif /* dwarf2expr.h */
|