forked from Imagelibrary/binutils-gdb
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.
This commit is contained in:
@@ -285,12 +285,7 @@ write_to_memory (CORE_ADDR address, const gdb_byte *buffer,
|
|||||||
length, buffer);
|
length, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the type used for DWARF operations where the type is
|
type *
|
||||||
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 *
|
|
||||||
address_type (gdbarch *arch, int addr_size)
|
address_type (gdbarch *arch, int addr_size)
|
||||||
{
|
{
|
||||||
dwarf_gdbarch_types *types
|
dwarf_gdbarch_types *types
|
||||||
@@ -408,6 +403,23 @@ private:
|
|||||||
frame_info *m_frame = nullptr;
|
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<dwarf_entry> clone () const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
using dwarf_entry_up = std::unique_ptr<dwarf_entry>;
|
||||||
|
|
||||||
/* Location description entry found on a DWARF expression evaluation
|
/* Location description entry found on a DWARF expression evaluation
|
||||||
stack.
|
stack.
|
||||||
|
|
||||||
@@ -2400,11 +2412,130 @@ sect_variable_value (sect_offset sect_off,
|
|||||||
type, true);
|
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<value *> *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<dwarf_entry_up> 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
|
/* Return the type used for DWARF operations where the type is
|
||||||
unspecified in the DWARF spec. Only certain sizes are
|
unspecified in the DWARF spec. Only certain sizes are
|
||||||
supported. */
|
supported. */
|
||||||
|
|
||||||
struct type *
|
type *
|
||||||
dwarf_expr_context::address_type () const
|
dwarf_expr_context::address_type () const
|
||||||
{
|
{
|
||||||
return ::address_type (this->m_per_objfile->objfile->arch (),
|
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
|
void
|
||||||
dwarf_expr_context::push (dwarf_entry_up entry)
|
dwarf_expr_context::push (dwarf_entry_up entry)
|
||||||
{
|
{
|
||||||
this->m_stack.emplace_back (std::move (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<dwarf_memory>
|
|
||||||
(this->m_per_objfile->objfile->arch (), addr, in_stack_memory));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* See expr.h. */
|
|
||||||
|
|
||||||
dwarf_entry_up
|
dwarf_entry_up
|
||||||
dwarf_expr_context::pop ()
|
dwarf_expr_context::pop ()
|
||||||
{
|
{
|
||||||
@@ -2451,8 +2568,6 @@ dwarf_expr_context::pop ()
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See expr.h. */
|
|
||||||
|
|
||||||
dwarf_entry &
|
dwarf_entry &
|
||||||
dwarf_expr_context::fetch (int n)
|
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)];
|
return *this->m_stack[this->m_stack.size () - (1 + n)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See expr.h. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dwarf_expr_context::get_frame_base (const gdb_byte **start,
|
dwarf_expr_context::get_frame_base (const gdb_byte **start,
|
||||||
size_t * length)
|
size_t * length)
|
||||||
@@ -2491,24 +2604,20 @@ dwarf_expr_context::get_frame_base (const gdb_byte **start,
|
|||||||
start, length);
|
start, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See expr.h. */
|
type *
|
||||||
|
|
||||||
struct type *
|
|
||||||
dwarf_expr_context::get_base_type (cu_offset die_cu_off)
|
dwarf_expr_context::get_base_type (cu_offset die_cu_off)
|
||||||
{
|
{
|
||||||
if (this->m_per_cu == nullptr)
|
if (this->m_per_cu == nullptr)
|
||||||
return builtin_type (this->m_per_objfile->objfile->arch ())->builtin_int;
|
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,
|
type *result = dwarf2_get_die_type (die_cu_off, this->m_per_cu,
|
||||||
this->m_per_objfile);
|
this->m_per_objfile);
|
||||||
|
|
||||||
if (result == nullptr)
|
if (result == nullptr)
|
||||||
error (_("Could not find type for operation"));
|
error (_("Could not find type for operation"));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See expr.h. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dwarf_expr_context::dwarf_call (cu_offset die_cu_off)
|
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);
|
this->eval (block.data, block.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See expr.h. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dwarf_expr_context::push_dwarf_reg_entry_value (call_site_parameter_kind kind,
|
dwarf_expr_context::push_dwarf_reg_entry_value (call_site_parameter_kind kind,
|
||||||
call_site_parameter_u kind_u,
|
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);
|
this->eval (data_src, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See expr.h. */
|
|
||||||
|
|
||||||
value *
|
value *
|
||||||
dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
|
dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
|
||||||
LONGEST subobj_offset, bool as_lval)
|
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 *
|
value *
|
||||||
dwarf_expr_context::evaluate (const gdb_byte *addr, size_t len, bool as_lval,
|
dwarf_expr_context::evaluate (const gdb_byte *addr, size_t len, bool as_lval,
|
||||||
dwarf2_per_cu_data *per_cu, frame_info *frame,
|
dwarf2_per_cu_data *per_cu, frame_info *frame,
|
||||||
const struct property_addr_info *addr_info,
|
std::vector<value *> *init_values,
|
||||||
|
const property_addr_info *addr_info,
|
||||||
struct type *type, struct type *subobj_type,
|
struct type *type, struct type *subobj_type,
|
||||||
LONGEST subobj_offset)
|
LONGEST subobj_offset)
|
||||||
{
|
{
|
||||||
this->m_per_cu = per_cu;
|
this->m_per_cu = per_cu;
|
||||||
this->m_frame = frame;
|
this->m_frame = frame;
|
||||||
this->m_addr_info = addr_info;
|
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);
|
eval (addr, len);
|
||||||
return fetch_result (type, subobj_type, subobj_offset, as_lval);
|
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
|
bool
|
||||||
dwarf_expr_context::stack_empty_p () const
|
dwarf_expr_context::stack_empty_p () const
|
||||||
{
|
{
|
||||||
return this->m_stack.empty ();
|
return this->m_stack.empty ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See expr.h. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset)
|
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);
|
composite->add_piece (std::move (piece), bit_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* See expr.h. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dwarf_expr_context::eval (const gdb_byte *addr, size_t len)
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See expr.h. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
|
dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
|
||||||
const gdb_byte *op_end)
|
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);
|
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<value *> *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 ();
|
||||||
void
|
void
|
||||||
_initialize_dwarf2expr ()
|
_initialize_dwarf2expr ()
|
||||||
|
|||||||
@@ -25,150 +25,31 @@
|
|||||||
#include "leb128.h"
|
#include "leb128.h"
|
||||||
#include "gdbtypes.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<dwarf_entry> clone () const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
using dwarf_entry_up = std::unique_ptr<dwarf_entry>;
|
|
||||||
|
|
||||||
struct dwarf2_per_objfile;
|
struct dwarf2_per_objfile;
|
||||||
|
|
||||||
/* The expression evaluator works with a dwarf_expr_context, describing
|
/* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU
|
||||||
its current state and its callbacks. */
|
FRAME context. The PER_OBJFILE contains a pointer to the PER_BFD
|
||||||
struct dwarf_expr_context
|
information. ADDR_SIZE defines a size of the DWARF generic type.
|
||||||
{
|
INIT_VALUES vector contains values that are expected to be pushed
|
||||||
/* Create a new context for the expression evaluator.
|
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<value *> *init_values,
|
||||||
|
const struct property_addr_info *addr_info,
|
||||||
|
struct type *type = nullptr,
|
||||||
|
struct type *subobj_type = nullptr,
|
||||||
|
LONGEST subobj_offset = 0);
|
||||||
|
|
||||||
We should ever only pass in the PER_OBJFILE and the ADDR_SIZE
|
/* Return the address type used of the ARCH architecture and
|
||||||
information should be retrievable from there. The PER_OBJFILE
|
ADDR_SIZE is expected size of the type. */
|
||||||
contains a pointer to the PER_BFD information anyway and the
|
type *address_type (gdbarch *arch, int addr_size);
|
||||||
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<dwarf_entry_up> 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);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Return the value of register number REG (a DWARF register number),
|
/* Return the value of register number REG (a DWARF register number),
|
||||||
read as an address in a given FRAME. */
|
read as an address in a given FRAME. */
|
||||||
|
|||||||
@@ -229,11 +229,19 @@ execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size,
|
|||||||
struct frame_info *this_frame, CORE_ADDR initial,
|
struct frame_info *this_frame, CORE_ADDR initial,
|
||||||
int initial_in_stack_memory, dwarf2_per_objfile *per_objfile)
|
int initial_in_stack_memory, dwarf2_per_objfile *per_objfile)
|
||||||
{
|
{
|
||||||
dwarf_expr_context ctx (per_objfile, addr_size);
|
|
||||||
scoped_value_mark free_values;
|
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 *init_value = value_at_lazy (type, initial);
|
||||||
value *result_val = ctx.evaluate (exp, len, true, nullptr, this_frame);
|
std::vector<value *> 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)
|
if (VALUE_LVAL (result_val) == lval_memory)
|
||||||
return value_address (result_val);
|
return value_address (result_val);
|
||||||
|
|||||||
@@ -1474,15 +1474,15 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
|
|||||||
if (size == 0)
|
if (size == 0)
|
||||||
return allocate_optimized_out_value (subobj_type);
|
return allocate_optimized_out_value (subobj_type);
|
||||||
|
|
||||||
dwarf_expr_context ctx (per_objfile, per_cu->addr_size ());
|
|
||||||
|
|
||||||
value *retval;
|
value *retval;
|
||||||
scoped_value_mark free_values;
|
scoped_value_mark free_values;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
retval = ctx.evaluate (data, size, as_lval, per_cu, frame, nullptr,
|
retval
|
||||||
type, subobj_type, subobj_byte_offset);
|
= 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)
|
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_objfile *per_objfile = dlbaton->per_objfile;
|
||||||
dwarf2_per_cu_data *per_cu = dlbaton->per_cu;
|
dwarf2_per_cu_data *per_cu = dlbaton->per_cu;
|
||||||
dwarf_expr_context ctx (per_objfile, per_cu->addr_size ());
|
|
||||||
|
|
||||||
value *result;
|
value *result;
|
||||||
scoped_value_mark free_values;
|
scoped_value_mark free_values;
|
||||||
|
std::vector<value *> init_values;
|
||||||
|
|
||||||
if (push_initial_value)
|
if (push_initial_value)
|
||||||
{
|
{
|
||||||
|
struct type *type = address_type (per_objfile->objfile->arch (),
|
||||||
|
per_cu->addr_size ());
|
||||||
|
|
||||||
if (addr_stack != nullptr)
|
if (addr_stack != nullptr)
|
||||||
ctx.push_address (addr_stack->addr, false);
|
init_values.push_back (value_at_lazy (type, addr_stack->addr));
|
||||||
else
|
else
|
||||||
ctx.push_address (0, false);
|
init_values.push_back (value_at_lazy (type, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = ctx.evaluate (dlbaton->data, dlbaton->size,
|
result
|
||||||
true, per_cu, frame, addr_stack);
|
= 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)
|
catch (const gdb_exception_error &ex)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user