Files
binutils-gdb/gdb/dwarf2/expr.h
Zoran Zaric bedecfcbea Change DWARF stack to use new dwarf_entry classes
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
2020-12-08 11:16:20 -05:00

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 */