mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
Compare commits
30 Commits
gdb-16-bra
...
users/zora
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1127a49b32 | ||
|
|
dab5aee6dc | ||
|
|
a85f75281a | ||
|
|
a6491910ec | ||
|
|
07089eff99 | ||
|
|
b96b71276e | ||
|
|
0a014570ff | ||
|
|
f7bc3a13f2 | ||
|
|
c12b925f78 | ||
|
|
bedecfcbea | ||
|
|
7200429a72 | ||
|
|
4a11d48735 | ||
|
|
fda7ca2701 | ||
|
|
0ead7f247c | ||
|
|
b9b1a8273b | ||
|
|
0dc32c82c3 | ||
|
|
e6bada58eb | ||
|
|
5e8cb1a0bb | ||
|
|
17ac2b0a7e | ||
|
|
467ee74161 | ||
|
|
754848f25e | ||
|
|
c5ce968925 | ||
|
|
c729602de0 | ||
|
|
abcb8a73df | ||
|
|
de00629fea | ||
|
|
0440f23844 | ||
|
|
3b3ac5a5fe | ||
|
|
528991c044 | ||
|
|
da7e10b674 | ||
|
|
a358e4f261 |
@@ -606,7 +606,7 @@ coerce_unspec_val_to_type (struct value *val, struct type *type)
|
||||
else
|
||||
{
|
||||
result = allocate_value (type);
|
||||
value_contents_copy_raw (result, 0, val, 0, TYPE_LENGTH (type));
|
||||
value_contents_copy_raw (result, 0, val, 0, 0, TYPE_LENGTH (type));
|
||||
}
|
||||
set_value_component_location (result, val);
|
||||
set_value_bitsize (result, value_bitsize (val));
|
||||
|
||||
@@ -356,6 +356,17 @@ compute_stack_depth_worker (int start, int *need_tempvar,
|
||||
(*info)[offset].label = 1;
|
||||
break;
|
||||
|
||||
case DW_OP_LLVM_offset:
|
||||
case DW_OP_LLVM_bit_offset:
|
||||
--stack_depth;
|
||||
break;
|
||||
|
||||
case DW_OP_LLVM_undefined:
|
||||
++stack_depth;
|
||||
break;
|
||||
|
||||
case DW_OP_LLVM_piece_end:
|
||||
case DW_OP_LLVM_offset_constu:
|
||||
case DW_OP_nop:
|
||||
break;
|
||||
|
||||
|
||||
3400
gdb/dwarf2/expr.c
3400
gdb/dwarf2/expr.c
File diff suppressed because it is too large
Load Diff
@@ -27,252 +27,56 @@
|
||||
|
||||
struct dwarf2_per_objfile;
|
||||
|
||||
/* The location of a value. */
|
||||
enum dwarf_value_location
|
||||
{
|
||||
/* The piece is in memory.
|
||||
The value on the dwarf stack is its address. */
|
||||
DWARF_VALUE_MEMORY,
|
||||
/* 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<struct value *> *init_values,
|
||||
const struct property_addr_info *addr_info,
|
||||
struct type *type = nullptr,
|
||||
struct type *subobj_type = nullptr,
|
||||
LONGEST subobj_offset = 0);
|
||||
|
||||
/* The piece is in a register.
|
||||
The value on the dwarf stack is the register number. */
|
||||
DWARF_VALUE_REGISTER,
|
||||
|
||||
/* The piece is on the dwarf stack. */
|
||||
DWARF_VALUE_STACK,
|
||||
|
||||
/* The piece is a literal. */
|
||||
DWARF_VALUE_LITERAL,
|
||||
|
||||
/* The piece was optimized out. */
|
||||
DWARF_VALUE_OPTIMIZED_OUT,
|
||||
|
||||
/* The piece is an implicit pointer. */
|
||||
DWARF_VALUE_IMPLICIT_POINTER
|
||||
};
|
||||
|
||||
/* A piece of an object, as recorded by DW_OP_piece or DW_OP_bit_piece. */
|
||||
struct dwarf_expr_piece
|
||||
{
|
||||
enum dwarf_value_location location;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/* This piece's address, for DWARF_VALUE_MEMORY pieces. */
|
||||
CORE_ADDR addr;
|
||||
/* Non-zero if the piece is known to be in memory and on
|
||||
the program's stack. */
|
||||
bool in_stack_memory;
|
||||
} mem;
|
||||
|
||||
/* The piece's register number, for DWARF_VALUE_REGISTER pieces. */
|
||||
int regno;
|
||||
|
||||
/* The piece's literal value, for DWARF_VALUE_STACK pieces. */
|
||||
struct value *value;
|
||||
|
||||
struct
|
||||
{
|
||||
/* A pointer to the data making up this piece,
|
||||
for DWARF_VALUE_LITERAL pieces. */
|
||||
const gdb_byte *data;
|
||||
/* The length of the available data. */
|
||||
ULONGEST length;
|
||||
} literal;
|
||||
|
||||
/* Used for DWARF_VALUE_IMPLICIT_POINTER. */
|
||||
struct
|
||||
{
|
||||
/* The referent DIE from DW_OP_implicit_pointer. */
|
||||
sect_offset die_sect_off;
|
||||
/* The byte offset into the resulting data. */
|
||||
LONGEST offset;
|
||||
} ptr;
|
||||
} v;
|
||||
|
||||
/* The length of the piece, in bits. */
|
||||
ULONGEST size;
|
||||
/* The piece offset, in bits. */
|
||||
ULONGEST offset;
|
||||
};
|
||||
|
||||
/* The dwarf expression stack. */
|
||||
|
||||
struct dwarf_stack_value
|
||||
{
|
||||
dwarf_stack_value (struct value *value_, int in_stack_memory_)
|
||||
: value (value_), in_stack_memory (in_stack_memory_)
|
||||
{}
|
||||
|
||||
struct value *value;
|
||||
|
||||
/* True if the piece is in memory and is known to be on the program's stack.
|
||||
It is always ok to set this to zero. This is used, for example, to
|
||||
optimize memory access from the target. It can vastly speed up backtraces
|
||||
on long latency connections when "set stack-cache on". */
|
||||
bool in_stack_memory;
|
||||
};
|
||||
|
||||
/* The expression evaluator works with a dwarf_expr_context, describing
|
||||
its current state and its callbacks. */
|
||||
struct dwarf_expr_context
|
||||
{
|
||||
dwarf_expr_context (dwarf2_per_objfile *per_objfile);
|
||||
virtual ~dwarf_expr_context () = default;
|
||||
|
||||
void push_address (CORE_ADDR value, bool in_stack_memory);
|
||||
void eval (const gdb_byte *addr, size_t len);
|
||||
struct value *fetch (int n);
|
||||
CORE_ADDR fetch_address (int n);
|
||||
bool fetch_in_stack_memory (int n);
|
||||
|
||||
/* The stack of values. */
|
||||
std::vector<dwarf_stack_value> 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;
|
||||
|
||||
/* Location of the value. */
|
||||
enum dwarf_value_location location;
|
||||
|
||||
/* For DWARF_VALUE_LITERAL, the current literal value's length and
|
||||
data. For DWARF_VALUE_IMPLICIT_POINTER, LEN is the offset of the
|
||||
target DIE of sect_offset kind. */
|
||||
ULONGEST len;
|
||||
const gdb_byte *data;
|
||||
|
||||
/* Initialization status of variable: Non-zero if variable has been
|
||||
initialized; zero otherwise. */
|
||||
int initialized;
|
||||
|
||||
/* A vector of pieces.
|
||||
|
||||
Each time DW_OP_piece is executed, we add a new element to the
|
||||
end of this array, recording the current top of the stack, the
|
||||
current location, and the size given as the operand to
|
||||
DW_OP_piece. We then pop the top value from the stack, reset the
|
||||
location, and resume evaluation.
|
||||
|
||||
The Dwarf spec doesn't say whether DW_OP_piece pops the top value
|
||||
from the stack. We do, ensuring that clients of this interface
|
||||
expecting to see a value left on the top of the stack (say, code
|
||||
evaluating frame base expressions or CFA's specified with
|
||||
DW_CFA_def_cfa_expression) will get an error if the expression
|
||||
actually marks all the values it computes as pieces.
|
||||
|
||||
If an expression never uses DW_OP_piece, num_pieces will be zero.
|
||||
(It would be nice to present these cases as expressions yielding
|
||||
a single piece, so that callers need not distinguish between the
|
||||
no-DW_OP_piece and one-DW_OP_piece cases. But expressions with
|
||||
no DW_OP_piece operations have no value to place in a piece's
|
||||
'size' field; the size comes from the surrounding data. So the
|
||||
two cases need to be handled separately.) */
|
||||
std::vector<dwarf_expr_piece> pieces;
|
||||
|
||||
/* We evaluate the expression in the context of this objfile. */
|
||||
dwarf2_per_objfile *per_objfile;
|
||||
|
||||
/* Return the value of register number REGNUM (a DWARF register number),
|
||||
read as an address. */
|
||||
virtual CORE_ADDR read_addr_from_reg (int regnum) = 0;
|
||||
|
||||
/* Return a value of type TYPE, stored in register number REGNUM
|
||||
of the frame associated to the given BATON.
|
||||
|
||||
REGNUM is a DWARF register number. */
|
||||
virtual struct value *get_reg_value (struct type *type, int regnum) = 0;
|
||||
|
||||
/* Read LENGTH bytes at ADDR into BUF. */
|
||||
virtual void read_mem (gdb_byte *buf, CORE_ADDR addr, size_t length) = 0;
|
||||
|
||||
/* 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. */
|
||||
virtual void get_frame_base (const gdb_byte **start, size_t *length) = 0;
|
||||
|
||||
/* Return the CFA for the frame. */
|
||||
virtual CORE_ADDR get_frame_cfa () = 0;
|
||||
|
||||
/* Return the PC for the frame. */
|
||||
virtual CORE_ADDR get_frame_pc ()
|
||||
{
|
||||
error (_("%s is invalid in this context"), "DW_OP_implicit_pointer");
|
||||
}
|
||||
|
||||
/* Return the thread-local storage address for
|
||||
DW_OP_GNU_push_tls_address or DW_OP_form_tls_address. */
|
||||
virtual CORE_ADDR get_tls_address (CORE_ADDR offset) = 0;
|
||||
|
||||
/* 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. */
|
||||
virtual void dwarf_call (cu_offset die_cu_off) = 0;
|
||||
|
||||
/* Execute "variable value" operation on the DIE at SECT_OFF. */
|
||||
virtual struct value *dwarf_variable_value (sect_offset sect_off) = 0;
|
||||
|
||||
/* 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. */
|
||||
virtual struct type *get_base_type (cu_offset die_cu_off, int size)
|
||||
{
|
||||
/* Anything will do. */
|
||||
return builtin_type (this->gdbarch)->builtin_int;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
virtual void push_dwarf_reg_entry_value (enum call_site_parameter_kind kind,
|
||||
union call_site_parameter_u kind_u,
|
||||
int deref_size) = 0;
|
||||
|
||||
/* Return the address indexed by DW_OP_addrx or DW_OP_GNU_addr_index.
|
||||
This can throw an exception if the index is out of range. */
|
||||
virtual CORE_ADDR get_addr_index (unsigned int index) = 0;
|
||||
|
||||
/* Return the `object address' for DW_OP_push_object_address. */
|
||||
virtual CORE_ADDR get_object_address () = 0;
|
||||
|
||||
private:
|
||||
|
||||
struct type *address_type () const;
|
||||
void push (struct value *value, bool in_stack_memory);
|
||||
bool stack_empty_p () const;
|
||||
void add_piece (ULONGEST size, ULONGEST offset);
|
||||
void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end);
|
||||
void pop ();
|
||||
};
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
@@ -312,14 +116,17 @@ gdb_skip_leb128 (const gdb_byte *buf, const gdb_byte *buf_end)
|
||||
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);
|
||||
|
||||
|
||||
@@ -191,17 +191,17 @@ dwarf2_frame_state::dwarf2_frame_state (CORE_ADDR pc_, struct dwarf2_cie *cie)
|
||||
retaddr_column (cie->return_address_register)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* Helper functions for execute_stack_op. */
|
||||
/* Return the value of register number REG (a DWARF register number),
|
||||
read as an address in a given FRAME. */
|
||||
|
||||
static CORE_ADDR
|
||||
read_addr_from_reg (struct frame_info *this_frame, int reg)
|
||||
read_addr_from_reg (struct frame_info *frame, int reg)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_frame_arch (this_frame);
|
||||
struct gdbarch *gdbarch = get_frame_arch (frame);
|
||||
int regnum = dwarf_reg_to_regnum_or_error (gdbarch, reg);
|
||||
|
||||
return address_from_register (regnum, this_frame);
|
||||
return address_from_register (regnum, frame);
|
||||
}
|
||||
|
||||
/* Execute the required actions for both the DW_CFA_restore and
|
||||
@@ -235,116 +235,35 @@ register %s (#%d) at %s"),
|
||||
}
|
||||
}
|
||||
|
||||
class dwarf_expr_executor : public dwarf_expr_context
|
||||
{
|
||||
public:
|
||||
|
||||
dwarf_expr_executor (dwarf2_per_objfile *per_objfile)
|
||||
: dwarf_expr_context (per_objfile)
|
||||
{}
|
||||
|
||||
struct frame_info *this_frame;
|
||||
|
||||
CORE_ADDR read_addr_from_reg (int reg) override
|
||||
{
|
||||
return ::read_addr_from_reg (this_frame, reg);
|
||||
}
|
||||
|
||||
struct value *get_reg_value (struct type *type, int reg) override
|
||||
{
|
||||
struct gdbarch *gdbarch = get_frame_arch (this_frame);
|
||||
int regnum = dwarf_reg_to_regnum_or_error (gdbarch, reg);
|
||||
|
||||
return value_from_register (type, regnum, this_frame);
|
||||
}
|
||||
|
||||
void read_mem (gdb_byte *buf, CORE_ADDR addr, size_t len) override
|
||||
{
|
||||
read_memory (addr, buf, len);
|
||||
}
|
||||
|
||||
void get_frame_base (const gdb_byte **start, size_t *length) override
|
||||
{
|
||||
invalid ("DW_OP_fbreg");
|
||||
}
|
||||
|
||||
void push_dwarf_reg_entry_value (enum call_site_parameter_kind kind,
|
||||
union call_site_parameter_u kind_u,
|
||||
int deref_size) override
|
||||
{
|
||||
invalid ("DW_OP_entry_value");
|
||||
}
|
||||
|
||||
CORE_ADDR get_object_address () override
|
||||
{
|
||||
invalid ("DW_OP_push_object_address");
|
||||
}
|
||||
|
||||
CORE_ADDR get_frame_cfa () override
|
||||
{
|
||||
invalid ("DW_OP_call_frame_cfa");
|
||||
}
|
||||
|
||||
CORE_ADDR get_tls_address (CORE_ADDR offset) override
|
||||
{
|
||||
invalid ("DW_OP_form_tls_address");
|
||||
}
|
||||
|
||||
void dwarf_call (cu_offset die_offset) override
|
||||
{
|
||||
invalid ("DW_OP_call*");
|
||||
}
|
||||
|
||||
struct value *dwarf_variable_value (sect_offset sect_off) override
|
||||
{
|
||||
invalid ("DW_OP_GNU_variable_value");
|
||||
}
|
||||
|
||||
CORE_ADDR get_addr_index (unsigned int index) override
|
||||
{
|
||||
invalid ("DW_OP_addrx or DW_OP_GNU_addr_index");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void invalid (const char *op) ATTRIBUTE_NORETURN
|
||||
{
|
||||
error (_("%s is invalid in this context"), op);
|
||||
}
|
||||
};
|
||||
|
||||
static CORE_ADDR
|
||||
static value *
|
||||
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)
|
||||
int initial_in_stack_memory, dwarf2_per_objfile *per_objfile,
|
||||
struct type* type = nullptr, bool as_lval = true)
|
||||
{
|
||||
CORE_ADDR result;
|
||||
|
||||
dwarf_expr_executor ctx (per_objfile);
|
||||
scoped_value_mark free_values;
|
||||
struct type *init_type = address_type (per_objfile->objfile->arch (),
|
||||
addr_size);
|
||||
|
||||
ctx.this_frame = this_frame;
|
||||
ctx.gdbarch = get_frame_arch (this_frame);
|
||||
ctx.addr_size = addr_size;
|
||||
ctx.ref_addr_size = -1;
|
||||
struct value *init_value = value_at_lazy (init_type, initial);
|
||||
std::vector<struct value *> init_values;
|
||||
|
||||
ctx.push_address (initial, initial_in_stack_memory);
|
||||
ctx.eval (exp, len);
|
||||
set_value_stack (init_value, initial_in_stack_memory);
|
||||
init_values.push_back (init_value);
|
||||
|
||||
if (ctx.location == DWARF_VALUE_MEMORY)
|
||||
result = ctx.fetch_address (0);
|
||||
else if (ctx.location == DWARF_VALUE_REGISTER)
|
||||
result = ctx.read_addr_from_reg (value_as_long (ctx.fetch (0)));
|
||||
else
|
||||
{
|
||||
/* This is actually invalid DWARF, but if we ever do run across
|
||||
it somehow, we might as well support it. So, instead, report
|
||||
it as unimplemented. */
|
||||
error (_("\
|
||||
Not implemented: computing unwound register using explicit value operator"));
|
||||
}
|
||||
struct value *result_val
|
||||
= dwarf2_eval_exp (exp, len, true, per_objfile, nullptr,
|
||||
this_frame, addr_size, &init_values, nullptr);
|
||||
|
||||
return result;
|
||||
/* We need to clean up all the values that are not needed any more.
|
||||
The problem with a value_ref_ptr class is that it disconnects the
|
||||
RETVAL from the value garbage collection, so we need to make
|
||||
a copy of that value on the stack to keep everything consistent.
|
||||
The value_ref_ptr will clean up after itself at the end of this block. */
|
||||
value_ref_ptr value_holder = value_ref_ptr::new_reference (result_val);
|
||||
free_values.free_to_mark ();
|
||||
|
||||
return value_copy(result_val);
|
||||
}
|
||||
|
||||
|
||||
@@ -1075,10 +994,14 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
|
||||
break;
|
||||
|
||||
case CFA_EXP:
|
||||
cache->cfa =
|
||||
execute_stack_op (fs.regs.cfa_exp, fs.regs.cfa_exp_len,
|
||||
cache->addr_size, this_frame, 0, 0,
|
||||
cache->per_objfile);
|
||||
{
|
||||
struct value *value
|
||||
= execute_stack_op (fs.regs.cfa_exp, fs.regs.cfa_exp_len,
|
||||
cache->addr_size, this_frame, 0, 0,
|
||||
cache->per_objfile);
|
||||
cache->cfa = value_address (value);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1276,24 +1199,22 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache,
|
||||
return frame_unwind_got_register (this_frame, regnum, realnum);
|
||||
|
||||
case DWARF2_FRAME_REG_SAVED_EXP:
|
||||
addr = execute_stack_op (cache->reg[regnum].loc.exp.start,
|
||||
return execute_stack_op (cache->reg[regnum].loc.exp.start,
|
||||
cache->reg[regnum].loc.exp.len,
|
||||
cache->addr_size,
|
||||
this_frame, cache->cfa, 1,
|
||||
cache->per_objfile);
|
||||
return frame_unwind_got_memory (this_frame, regnum, addr);
|
||||
cache->addr_size, this_frame,
|
||||
cache->cfa, 1, cache->per_objfile,
|
||||
register_type (gdbarch, regnum));
|
||||
|
||||
case DWARF2_FRAME_REG_SAVED_VAL_OFFSET:
|
||||
addr = cache->cfa + cache->reg[regnum].loc.offset;
|
||||
return frame_unwind_got_constant (this_frame, regnum, addr);
|
||||
|
||||
case DWARF2_FRAME_REG_SAVED_VAL_EXP:
|
||||
addr = execute_stack_op (cache->reg[regnum].loc.exp.start,
|
||||
return execute_stack_op (cache->reg[regnum].loc.exp.start,
|
||||
cache->reg[regnum].loc.exp.len,
|
||||
cache->addr_size,
|
||||
this_frame, cache->cfa, 1,
|
||||
cache->per_objfile);
|
||||
return frame_unwind_got_constant (this_frame, regnum, addr);
|
||||
cache->addr_size, this_frame,
|
||||
cache->cfa, 1, cache->per_objfile,
|
||||
register_type (gdbarch, regnum), false);
|
||||
|
||||
case DWARF2_FRAME_REG_UNSPECIFIED:
|
||||
/* GCC, in its infinite wisdom decided to not provide unwind
|
||||
|
||||
1727
gdb/dwarf2/loc.c
1727
gdb/dwarf2/loc.c
File diff suppressed because it is too large
Load Diff
@@ -53,16 +53,32 @@ extern void func_get_frame_base_dwarf_block (struct symbol *framefunc,
|
||||
const gdb_byte **start,
|
||||
size_t *length);
|
||||
|
||||
/* Fetch call_site_parameter from caller matching KIND and KIND_U.
|
||||
FRAME is for callee.
|
||||
|
||||
Function always returns non-NULL, it throws NO_ENTRY_VALUE_ERROR
|
||||
otherwise. */
|
||||
|
||||
struct call_site_parameter *dwarf_expr_reg_to_entry_parameter
|
||||
(struct frame_info *frame,
|
||||
enum call_site_parameter_kind kind,
|
||||
union call_site_parameter_u kind_u,
|
||||
dwarf2_per_cu_data **per_cu_return,
|
||||
dwarf2_per_objfile **per_objfile_return);
|
||||
|
||||
|
||||
/* Evaluate a location description, starting at DATA and with length
|
||||
SIZE, to find the current location of variable of TYPE in the context
|
||||
of FRAME. */
|
||||
of FRAME. AS_LVAL defines if the resulting struct value is expected to
|
||||
be a value or a location description. */
|
||||
|
||||
struct value *dwarf2_evaluate_loc_desc (struct type *type,
|
||||
struct frame_info *frame,
|
||||
const gdb_byte *data,
|
||||
size_t size,
|
||||
dwarf2_per_cu_data *per_cu,
|
||||
dwarf2_per_objfile *per_objfile);
|
||||
dwarf2_per_objfile *per_objfile,
|
||||
bool as_lval = true);
|
||||
|
||||
/* A chain of addresses that might be needed to resolve a dynamic
|
||||
property. */
|
||||
@@ -264,4 +280,18 @@ extern int dwarf_reg_to_regnum (struct gdbarch *arch, int dwarf_reg);
|
||||
extern int dwarf_reg_to_regnum_or_error (struct gdbarch *arch,
|
||||
ULONGEST dwarf_reg);
|
||||
|
||||
/* Helper function which throws an error if a synthetic pointer is
|
||||
invalid. */
|
||||
|
||||
extern void invalid_synthetic_pointer (void);
|
||||
|
||||
/* Fetch the value pointed to by a synthetic pointer. */
|
||||
|
||||
extern struct value *indirect_synthetic_pointer
|
||||
(sect_offset die, LONGEST byte_offset,
|
||||
dwarf2_per_cu_data *per_cu,
|
||||
dwarf2_per_objfile *per_objfile,
|
||||
struct frame_info *frame,
|
||||
struct type *type, bool resolve_abstract_p = false);
|
||||
|
||||
#endif /* dwarf2loc.h */
|
||||
|
||||
@@ -196,7 +196,7 @@ protected:
|
||||
available offset. */
|
||||
void copy_element_to_dest (struct value *elt)
|
||||
{
|
||||
value_contents_copy (m_dest, m_dest_offset, elt, 0,
|
||||
value_contents_copy (m_dest, m_dest_offset, elt, 0, 0,
|
||||
TYPE_LENGTH (value_type (elt)));
|
||||
m_dest_offset += TYPE_LENGTH (value_type (elt));
|
||||
}
|
||||
|
||||
@@ -871,6 +871,7 @@ read_frame_register_value (struct value *value, struct frame_info *frame)
|
||||
struct gdbarch *gdbarch = get_frame_arch (frame);
|
||||
LONGEST offset = 0;
|
||||
LONGEST reg_offset = value_offset (value);
|
||||
LONGEST bit_offset = value_bitpos (value);
|
||||
int regnum = VALUE_REGNUM (value);
|
||||
int len = type_length_units (check_typedef (value_type (value)));
|
||||
|
||||
@@ -894,7 +895,8 @@ read_frame_register_value (struct value *value, struct frame_info *frame)
|
||||
if (reg_len > len)
|
||||
reg_len = len;
|
||||
|
||||
value_contents_copy (value, offset, regval, reg_offset, reg_len);
|
||||
value_contents_copy (value, offset, regval, reg_offset,
|
||||
bit_offset, reg_len);
|
||||
|
||||
offset += reg_len;
|
||||
len -= reg_len;
|
||||
|
||||
36
gdb/frame.c
36
gdb/frame.c
@@ -1567,25 +1567,49 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
|
||||
{
|
||||
int curr_len = register_size (gdbarch, regnum) - offset;
|
||||
|
||||
struct value *value = frame_unwind_register_value (frame->next,
|
||||
regnum);
|
||||
|
||||
if (curr_len > len)
|
||||
curr_len = len;
|
||||
|
||||
if (curr_len == register_size (gdbarch, regnum))
|
||||
/* Compute value is a special new case. The problem is that
|
||||
the computed callback mechanism only supports a struct
|
||||
value arguments, so we need to make one. */
|
||||
if (value != NULL && VALUE_LVAL (value) == lval_computed)
|
||||
{
|
||||
struct value *from_value;
|
||||
const struct lval_funcs *funcs = value_computed_funcs (value);
|
||||
struct type * reg_type = register_type (gdbarch, regnum);
|
||||
|
||||
if (funcs->write == NULL)
|
||||
error (_("Attempt to assign to an unmodifiable value."));
|
||||
|
||||
from_value = allocate_value (reg_type);
|
||||
memcpy (value_contents_raw (from_value), myaddr,
|
||||
TYPE_LENGTH (reg_type));
|
||||
|
||||
set_value_offset (value, offset);
|
||||
|
||||
funcs->write (value, from_value);
|
||||
release_value (from_value);
|
||||
}
|
||||
else if (curr_len == register_size (gdbarch, regnum))
|
||||
{
|
||||
put_frame_register (frame, regnum, myaddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct value *value = frame_unwind_register_value (frame->next,
|
||||
regnum);
|
||||
gdb_assert (value != NULL);
|
||||
|
||||
memcpy ((char *) value_contents_writeable (value) + offset, myaddr,
|
||||
curr_len);
|
||||
memcpy ((char *) value_contents_writeable (value) + offset,
|
||||
myaddr, curr_len);
|
||||
put_frame_register (frame, regnum, value_contents_raw (value));
|
||||
release_value (value);
|
||||
}
|
||||
|
||||
if (value != NULL)
|
||||
release_value (value);
|
||||
|
||||
myaddr += curr_len;
|
||||
len -= curr_len;
|
||||
offset = 0;
|
||||
|
||||
328
gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp
Normal file
328
gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp
Normal file
@@ -0,0 +1,328 @@
|
||||
# Copyright 2017-2020 Free Software Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
# Test DWARF operation that allow adding byte and bit offset to any
|
||||
# location description.
|
||||
#
|
||||
# In particular, the test uses memory and register location
|
||||
# descriptions (both as standalone and parts of the composite
|
||||
# location), and applies different byte and bit offsets to them.
|
||||
|
||||
load_lib dwarf.exp
|
||||
|
||||
# This test can only be run on targets which support DWARF-2 and use gas.
|
||||
if {![dwarf2_support]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Choose suitable integer registers for the test.
|
||||
|
||||
set dwarf_regnum 0
|
||||
|
||||
if { [is_aarch64_target] } {
|
||||
set regname x0
|
||||
} elseif { [is_aarch32_target]
|
||||
|| [istarget "s390*-*-*" ]
|
||||
|| [istarget "powerpc*-*-*"]
|
||||
|| [istarget "rs6000*-*-aix*"] } {
|
||||
set regname r0
|
||||
} elseif { [is_x86_like_target] } {
|
||||
set regname eax
|
||||
} elseif { [is_amd64_regs_target] } {
|
||||
set regname rax
|
||||
} else {
|
||||
verbose "Skipping ${gdb_test_file_name}."
|
||||
return
|
||||
}
|
||||
|
||||
standard_testfile var-access.c ${gdb_test_file_name}-dw.S
|
||||
|
||||
# Make some DWARF for the test.
|
||||
|
||||
set asm_file [standard_output_file $srcfile2]
|
||||
Dwarf::assemble $asm_file {
|
||||
global dwarf_regnum regname srcdir subdir srcfile
|
||||
set buf_var [gdb_target_symbol buf]
|
||||
|
||||
set main_result [function_range main ${srcdir}/${subdir}/${srcfile}]
|
||||
set main_start [lindex $main_result 0]
|
||||
set main_length [lindex $main_result 1]
|
||||
|
||||
cu {} {
|
||||
DW_TAG_compile_unit {
|
||||
{DW_AT_name var-access.c}
|
||||
{DW_AT_comp_dir /tmp}
|
||||
} {
|
||||
declare_labels char_type_label int_type_label
|
||||
declare_labels array_size_4_type_label array_size_8_type_label
|
||||
|
||||
# define char type.
|
||||
char_type_label: DW_TAG_base_type {
|
||||
{DW_AT_name "char"}
|
||||
{DW_AT_encoding @DW_ATE_signed}
|
||||
{DW_AT_byte_size 1 DW_FORM_sdata}
|
||||
}
|
||||
|
||||
# define int type.
|
||||
int_type_label: DW_TAG_base_type {
|
||||
{DW_AT_name "int"}
|
||||
{DW_AT_encoding @DW_ATE_signed}
|
||||
{DW_AT_byte_size 4 DW_FORM_sdata}
|
||||
}
|
||||
|
||||
# define 4 byte size array type.
|
||||
array_size_4_type_label: DW_TAG_array_type {
|
||||
{DW_AT_type :$char_type_label}
|
||||
} {
|
||||
DW_TAG_subrange_type {
|
||||
{DW_AT_type :$int_type_label}
|
||||
{DW_AT_upper_bound 3 DW_FORM_udata}
|
||||
}
|
||||
}
|
||||
|
||||
# define 8 byte size array type.
|
||||
array_size_8_type_label: DW_TAG_array_type {
|
||||
{DW_AT_type :$char_type_label}
|
||||
} {
|
||||
DW_TAG_subrange_type {
|
||||
{DW_AT_type :$int_type_label}
|
||||
{DW_AT_upper_bound 7 DW_FORM_udata}
|
||||
}
|
||||
}
|
||||
|
||||
DW_TAG_subprogram {
|
||||
{DW_AT_name main}
|
||||
{DW_AT_low_pc $main_start addr}
|
||||
{DW_AT_high_pc $main_length data8}
|
||||
} {
|
||||
# define original buf variable.
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name buf}
|
||||
{DW_AT_type :$array_size_4_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_addr $buf_var
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
|
||||
# defined a variable located in
|
||||
# a third byte of the buf variable.
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name buf_byte_3}
|
||||
{DW_AT_type :$char_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_addr $buf_var
|
||||
DW_OP_LLVM_offset_constu 2
|
||||
} SPECIAL_expr}
|
||||
{external 1 flag}
|
||||
}
|
||||
|
||||
# defined a variable located in a second byte
|
||||
# of the buf variable with a bit offset of one.
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name buf_byte_2_bit_1}
|
||||
{DW_AT_type :$char_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_addr $buf_var
|
||||
DW_OP_lit9
|
||||
DW_OP_LLVM_bit_offset
|
||||
} SPECIAL_expr}
|
||||
{external 1 flag}
|
||||
}
|
||||
|
||||
# defined a variable located in a
|
||||
# third byte of the REGNAME register.
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name reg_byte_3}
|
||||
{DW_AT_type :$char_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_regx $dwarf_regnum
|
||||
DW_OP_lit2
|
||||
DW_OP_LLVM_offset
|
||||
} SPECIAL_expr}
|
||||
{external 1 flag}
|
||||
}
|
||||
|
||||
# defined a variable located in a second byte of
|
||||
# the REGNAME register with a bit offset of one.
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name reg_byte_2_bit_1}
|
||||
{DW_AT_type :$char_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_regx $dwarf_regnum
|
||||
DW_OP_lit1
|
||||
DW_OP_LLVM_offset
|
||||
DW_OP_lit1
|
||||
DW_OP_LLVM_bit_offset
|
||||
} SPECIAL_expr}
|
||||
{external 1 flag}
|
||||
}
|
||||
|
||||
# Define an array variable spread in different
|
||||
# pieces of buf variable and REGNAME register.
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name mix_array}
|
||||
{DW_AT_type :$array_size_8_type_label}
|
||||
{DW_AT_location {
|
||||
|
||||
# a byte piece located in a
|
||||
# fourth byte of the buf variable.
|
||||
DW_OP_addr $buf_var
|
||||
DW_OP_LLVM_offset_constu 3
|
||||
DW_OP_piece 0x1
|
||||
|
||||
# a byte piece located in a
|
||||
# third byte of the buf variable.
|
||||
DW_OP_addr $buf_var
|
||||
DW_OP_lit2
|
||||
DW_OP_LLVM_offset
|
||||
DW_OP_piece 0x1
|
||||
|
||||
# a byte piece located in a second byte of
|
||||
# the buf variable with a bit offset of one.
|
||||
DW_OP_addr $buf_var
|
||||
DW_OP_lit1
|
||||
DW_OP_LLVM_offset
|
||||
DW_OP_lit1
|
||||
DW_OP_LLVM_bit_offset
|
||||
DW_OP_piece 0x1
|
||||
|
||||
# a four bit piece located in a first byte
|
||||
# of the buf variable with a bit offset of one.
|
||||
DW_OP_addr $buf_var
|
||||
DW_OP_LLVM_offset_constu 0
|
||||
DW_OP_bit_piece 0x4 0x1
|
||||
|
||||
# a four bit piece located in a first byte of
|
||||
# the buf variable with a bit offset of eight.
|
||||
DW_OP_addr $buf_var
|
||||
DW_OP_lit1
|
||||
DW_OP_LLVM_bit_offset
|
||||
DW_OP_LLVM_offset_constu 0
|
||||
DW_OP_bit_piece 0x4 0x7
|
||||
|
||||
# a byte piece located in a fourth
|
||||
# byte of the REGNAME register.
|
||||
DW_OP_regx $dwarf_regnum
|
||||
DW_OP_LLVM_offset_constu 3
|
||||
DW_OP_piece 0x1
|
||||
|
||||
# a byte piece located in a third
|
||||
# byte of the REGNAME register.
|
||||
DW_OP_regx $dwarf_regnum
|
||||
DW_OP_lit2
|
||||
DW_OP_LLVM_offset
|
||||
DW_OP_piece 0x1
|
||||
|
||||
# a byte piece located in a second byte of the
|
||||
# REGNAME register with a bit offset of one.
|
||||
DW_OP_regx $dwarf_regnum
|
||||
DW_OP_lit1
|
||||
DW_OP_LLVM_offset
|
||||
DW_OP_lit1
|
||||
DW_OP_LLVM_bit_offset
|
||||
DW_OP_piece 0x1
|
||||
|
||||
# a four bit piece located in a first byte of
|
||||
# the REGNAME register with a bit offset of one.
|
||||
DW_OP_regx $dwarf_regnum
|
||||
DW_OP_LLVM_offset_constu 0
|
||||
DW_OP_bit_piece 0x4 0x1
|
||||
|
||||
# a four bit piece located in a first byte of the
|
||||
# REGNAME register with a bit offset of eight.
|
||||
DW_OP_regx $dwarf_regnum
|
||||
DW_OP_lit1
|
||||
DW_OP_LLVM_bit_offset
|
||||
DW_OP_LLVM_offset_constu 0
|
||||
DW_OP_bit_piece 0x4 0x7
|
||||
|
||||
} SPECIAL_expr}
|
||||
{external 1 flag}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if { [prepare_for_testing ${testfile}.exp ${testfile} \
|
||||
[list $srcfile $asm_file] {nodebug}] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
# Determine byte order.
|
||||
set endian [get_endianness]
|
||||
|
||||
if { $endian != "little" } then {
|
||||
verbose "Skipping ${gdb_test_file_name}."
|
||||
return
|
||||
}
|
||||
|
||||
gdb_test_no_output "set var \$$regname = 0x04030201" "init reg"
|
||||
gdb_test_no_output "set var *\(\(unsigned int *\) buf\) = 0x04030201" \
|
||||
"init buf"
|
||||
|
||||
gdb_test "print/x buf_byte_3" " = 0x3" "buf_byte_3 == 0x3"
|
||||
gdb_test "print/x buf_byte_2_bit_1" " = 0x81" \
|
||||
"print buf_byte_2_bit_1"
|
||||
gdb_test "print/x reg_byte_3" " = 0x3" "reg_byte_3 == 0x3"
|
||||
gdb_test "print/x reg_byte_2_bit_1" " = 0x81" \
|
||||
"print reg_byte_2_bit_1"
|
||||
|
||||
gdb_test_no_output "set var buf_byte_3 = 0x4" "init buf_byte_3 to 0x4"
|
||||
gdb_test "print/x buf_byte_3" " = 0x4" "buf_byte_3 == 0x4"
|
||||
|
||||
gdb_test_no_output "set var buf_byte_2_bit_1 = 0x4" \
|
||||
"init buf_byte_2_bit_1 to 0x4"
|
||||
gdb_test "print/x buf_byte_2_bit_1" " = 0x4" "buf_byte_2_bit_1 == 0x4"
|
||||
|
||||
gdb_test "print/x buf" " = \\{0x1, 0x8, 0x4, 0x4\\}" "buf print"
|
||||
|
||||
gdb_test_no_output "set var reg_byte_3 = 0x4" "init reg_byte_3 to 0x4"
|
||||
gdb_test "print/x reg_byte_3" " = 0x4" "reg_byte_3 == 0x4"
|
||||
|
||||
gdb_test_no_output "set var reg_byte_2_bit_1 = 0x4" \
|
||||
"init reg_byte_2_bit_1 to 0x4"
|
||||
gdb_test "print/x reg_byte_2_bit_1" " = 0x4" "reg_byte_2_bit_1 == 0x4"
|
||||
|
||||
gdb_test "print/x \$$regname" " = 0x4040801" "\$$regname print"
|
||||
|
||||
gdb_test_no_output "set var \$$regname = 0x04030201" "reset reg"
|
||||
gdb_test_no_output "set var *\(\(unsigned int *\) buf\) = 0x04030201" \
|
||||
"reset buf"
|
||||
|
||||
gdb_test "print/x mix_array" \
|
||||
" = \\{0x4, 0x3, 0x81, 0x20, 0x4, 0x3, 0x81, 0x20\\}" \
|
||||
"mix_array print"
|
||||
|
||||
gdb_test_no_output "set var mix_array\[1\] = 0x4" \
|
||||
"set mix_array second byte"
|
||||
gdb_test_no_output "set var mix_array\[2\] = 0x4" \
|
||||
"set mix_array third byte"
|
||||
gdb_test_no_output "set var mix_array\[5\] = 0x4" \
|
||||
"set mix_array fifth byte"
|
||||
gdb_test_no_output "set var mix_array\[6\] = 0x4" \
|
||||
"set mix_array sixth byte"
|
||||
|
||||
gdb_test "print/x mix_array" \
|
||||
" = \\{0x4, 0x4, 0x4, 0x80, 0x4, 0x4, 0x4, 0x80\\}" \
|
||||
"mix_array second print"
|
||||
|
||||
gdb_test "print/x buf" " = \\{0x1, 0x8, 0x4, 0x4\\}" "buf second print"
|
||||
|
||||
gdb_test "print/x \$$regname" " = 0x4040801" "\$$regname second print"
|
||||
191
gdb/testsuite/gdb.dwarf2/dw2-llvm-piece-end.exp
Normal file
191
gdb/testsuite/gdb.dwarf2/dw2-llvm-piece-end.exp
Normal file
@@ -0,0 +1,191 @@
|
||||
# Copyright 2017-2020 Free Software Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
# Test the nested composition location description by using the new
|
||||
# DW_OP_LLVM_piece_end operation.
|
||||
#
|
||||
# The test uses three nested levels of composite location descriptions
|
||||
# to define a location of an array.
|
||||
|
||||
load_lib dwarf.exp
|
||||
|
||||
# This test can only be run on targets which support DWARF-2 and use gas.
|
||||
if {![dwarf2_support]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Choose suitable integer registers for the test.
|
||||
|
||||
set dwarf_regnum 0
|
||||
|
||||
if { [is_aarch64_target] } {
|
||||
set regname x0
|
||||
} elseif { [is_aarch32_target]
|
||||
|| [istarget "s390*-*-*" ]
|
||||
|| [istarget "powerpc*-*-*"]
|
||||
|| [istarget "rs6000*-*-aix*"] } {
|
||||
set regname r0
|
||||
} elseif { [is_x86_like_target] } {
|
||||
set regname eax
|
||||
} elseif { [is_amd64_regs_target] } {
|
||||
set regname rax
|
||||
} else {
|
||||
verbose "Skipping ${gdb_test_file_name}."
|
||||
return
|
||||
}
|
||||
|
||||
standard_testfile var-access.c ${gdb_test_file_name}-dw.S
|
||||
|
||||
# Make some DWARF for the test.
|
||||
|
||||
set asm_file [standard_output_file $srcfile2]
|
||||
Dwarf::assemble $asm_file {
|
||||
global dwarf_regnum regname srcdir subdir srcfile
|
||||
set buf_src [gdb_target_symbol buf]
|
||||
|
||||
set main_result [function_range main ${srcdir}/${subdir}/${srcfile}]
|
||||
set main_start [lindex $main_result 0]
|
||||
set main_length [lindex $main_result 1]
|
||||
|
||||
cu {} {
|
||||
DW_TAG_compile_unit {
|
||||
{DW_AT_name var-access.c}
|
||||
{DW_AT_comp_dir /tmp}
|
||||
} {
|
||||
declare_labels array_type_label int_type_label char_type_label
|
||||
|
||||
# define char type
|
||||
char_type_label: DW_TAG_base_type {
|
||||
{DW_AT_name "char"}
|
||||
{DW_AT_encoding @DW_ATE_signed}
|
||||
{DW_AT_byte_size 1 DW_FORM_sdata}
|
||||
}
|
||||
|
||||
int_type_label: DW_TAG_base_type {
|
||||
{DW_AT_name "int"}
|
||||
{DW_AT_encoding @DW_ATE_signed}
|
||||
{DW_AT_byte_size 4 DW_FORM_sdata}
|
||||
}
|
||||
|
||||
array_type_label: DW_TAG_array_type {
|
||||
{DW_AT_type :$char_type_label}
|
||||
} {
|
||||
DW_TAG_subrange_type {
|
||||
{DW_AT_type :$int_type_label}
|
||||
{DW_AT_upper_bound 7 DW_FORM_udata}
|
||||
}
|
||||
}
|
||||
|
||||
DW_TAG_subprogram {
|
||||
{DW_AT_name main}
|
||||
{DW_AT_low_pc $main_start addr}
|
||||
{DW_AT_high_pc $main_length data8}
|
||||
} {
|
||||
# Array spread in different pieces, of which some are
|
||||
# undefined (1st and sixth bytes) and some are either
|
||||
# in buf variable or REGNAME register.
|
||||
#
|
||||
# Location consists of three nested composite levels:
|
||||
# - Third level consists of a composite location
|
||||
# descriptions which hold a single simple location
|
||||
# description each.
|
||||
# - Second level consist of two more composite location
|
||||
# descriptions that hold two of the third level
|
||||
# composite location descriptions.
|
||||
# - First level holds two of the second level composite
|
||||
# location descriptions.
|
||||
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name var_array}
|
||||
{DW_AT_type :$array_type_label}
|
||||
{DW_AT_location {
|
||||
# First level composite start
|
||||
# Second level first composite start
|
||||
# Third level first composite start
|
||||
DW_OP_addr $buf_src
|
||||
DW_OP_piece 0x2
|
||||
DW_OP_LLVM_piece_end
|
||||
# Third level first composite end
|
||||
|
||||
# Third level second composite start
|
||||
DW_OP_LLVM_undefined
|
||||
DW_OP_piece 0x1
|
||||
DW_OP_LLVM_piece_end
|
||||
# Third level second composite end
|
||||
|
||||
DW_OP_piece 0x1
|
||||
DW_OP_swap
|
||||
DW_OP_piece 0x2
|
||||
DW_OP_LLVM_piece_end
|
||||
# Second level first composite end
|
||||
|
||||
# Second level second composite start
|
||||
# Third level third composite start
|
||||
DW_OP_regx $dwarf_regnum
|
||||
DW_OP_piece 0x4
|
||||
DW_OP_LLVM_piece_end
|
||||
# Third level third composite end
|
||||
|
||||
# Third level fourth composite start
|
||||
DW_OP_LLVM_undefined
|
||||
DW_OP_piece 0x1
|
||||
DW_OP_LLVM_piece_end
|
||||
# Third level fourth composite end
|
||||
|
||||
DW_OP_piece 0x1
|
||||
DW_OP_swap
|
||||
DW_OP_piece 0x4
|
||||
DW_OP_LLVM_piece_end
|
||||
# Second level second composite end
|
||||
|
||||
DW_OP_piece 0x5
|
||||
DW_OP_swap
|
||||
DW_OP_piece 0x3
|
||||
DW_OP_LLVM_piece_end
|
||||
# First level composite end
|
||||
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if { [prepare_for_testing ${testfile}.exp ${testfile} \
|
||||
[list $srcfile $asm_file] {nodebug}] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test_no_output "set var \$$regname = 0x4030201" "init reg"
|
||||
|
||||
# Determine byte order.
|
||||
set endian [get_endianness]
|
||||
set optimized "<optimized out>"
|
||||
|
||||
switch $endian {
|
||||
little {
|
||||
set val "$optimized, 0x1, 0x2, 0x3, 0x4, $optimized, 0x0, 0x1"
|
||||
}
|
||||
big {
|
||||
set val "$optimized, 0x4, 0x3, 0x2, 0x1, $optimized, 0x0, 0x1"
|
||||
}
|
||||
}
|
||||
|
||||
gdb_test "print/x var_array" " = \\{${val}\\}" "var_array print"
|
||||
|
||||
144
gdb/testsuite/gdb.dwarf2/dw2-llvm-undefined.exp
Normal file
144
gdb/testsuite/gdb.dwarf2/dw2-llvm-undefined.exp
Normal file
@@ -0,0 +1,144 @@
|
||||
# Copyright 2017-2020 Free Software Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
# Test the new DW_OP_LLVM_undefined operation.
|
||||
#
|
||||
# The test uses a composite location description, where some pieces
|
||||
# of that location description are undefined location description.
|
||||
|
||||
load_lib dwarf.exp
|
||||
|
||||
# This test can only be run on targets which support DWARF-2 and use gas.
|
||||
if {![dwarf2_support]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Choose suitable integer registers for the test.
|
||||
|
||||
set dwarf_regnum 0
|
||||
|
||||
if { [is_aarch64_target] } {
|
||||
set regname x0
|
||||
} elseif { [is_aarch32_target]
|
||||
|| [istarget "s390*-*-*" ]
|
||||
|| [istarget "powerpc*-*-*"]
|
||||
|| [istarget "rs6000*-*-aix*"] } {
|
||||
set regname r0
|
||||
} elseif { [is_x86_like_target] } {
|
||||
set regname eax
|
||||
} elseif { [is_amd64_regs_target] } {
|
||||
set regname rax
|
||||
} else {
|
||||
verbose "Skipping ${gdb_test_file_name}."
|
||||
return
|
||||
}
|
||||
|
||||
standard_testfile var-access.c ${gdb_test_file_name}-dw.S
|
||||
|
||||
# Make some DWARF for the test.
|
||||
|
||||
set asm_file [standard_output_file $srcfile2]
|
||||
Dwarf::assemble $asm_file {
|
||||
global dwarf_regnum regname srcdir subdir srcfile
|
||||
set buf_src [gdb_target_symbol buf]
|
||||
|
||||
set main_result [function_range main ${srcdir}/${subdir}/${srcfile}]
|
||||
set main_start [lindex $main_result 0]
|
||||
set main_length [lindex $main_result 1]
|
||||
|
||||
cu {} {
|
||||
DW_TAG_compile_unit {
|
||||
{DW_AT_name var-access.c}
|
||||
{DW_AT_comp_dir /tmp}
|
||||
} {
|
||||
declare_labels int_type_label char_type_label array_type_label
|
||||
|
||||
# define char type
|
||||
char_type_label: DW_TAG_base_type {
|
||||
{DW_AT_name "char"}
|
||||
{DW_AT_encoding @DW_ATE_signed}
|
||||
{DW_AT_byte_size 1 DW_FORM_sdata}
|
||||
}
|
||||
|
||||
int_type_label: DW_TAG_base_type {
|
||||
{DW_AT_name "int"}
|
||||
{DW_AT_encoding @DW_ATE_signed}
|
||||
{DW_AT_byte_size 4 DW_FORM_sdata}
|
||||
}
|
||||
|
||||
array_type_label: DW_TAG_array_type {
|
||||
{DW_AT_type :$char_type_label}
|
||||
} {
|
||||
DW_TAG_subrange_type {
|
||||
{DW_AT_type :$int_type_label}
|
||||
{DW_AT_upper_bound 5 DW_FORM_udata}
|
||||
}
|
||||
}
|
||||
|
||||
DW_TAG_subprogram {
|
||||
{DW_AT_name main}
|
||||
{DW_AT_low_pc $main_start addr}
|
||||
{DW_AT_high_pc $main_length data8}
|
||||
} {
|
||||
|
||||
# Array spread in different pieces of which some are
|
||||
# undefined (1st and sixth bytes) and some are in a
|
||||
# REGNAME register.
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name var_array}
|
||||
{DW_AT_type :$array_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_LLVM_undefined
|
||||
DW_OP_piece 0x1
|
||||
DW_OP_regx $dwarf_regnum
|
||||
DW_OP_piece 0x4
|
||||
DW_OP_LLVM_undefined
|
||||
DW_OP_piece 0x1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name var_int}
|
||||
{DW_AT_type :$int_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_LLVM_undefined
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if { [prepare_for_testing ${testfile}.exp ${testfile} \
|
||||
[list $srcfile $asm_file] {nodebug}] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test_no_output "set var \$$regname = 0x04030201" "init reg"
|
||||
|
||||
# Determine byte order.
|
||||
set endian [get_endianness]
|
||||
|
||||
switch $endian {
|
||||
little {set val "<optimized out>, 0x1, 0x2, 0x3, 0x4, <optimized out>"}
|
||||
big {set val "<optimized out>, 0x4, 0x3, 0x2, 0x1, <optimized out>"}
|
||||
}
|
||||
|
||||
gdb_test "print/x var_array" " = \\{${val}\\}" "var_array print"
|
||||
gdb_test "print/x var_int" " = <optimized out>" "var_int print"
|
||||
25
gdb/testsuite/gdb.dwarf2/symbol_needs_eval.c
Normal file
25
gdb/testsuite/gdb.dwarf2/symbol_needs_eval.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2017-2020 Free Software Foundation, Inc.
|
||||
|
||||
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/>. */
|
||||
|
||||
int exec_mask = 1;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
asm volatile ("main_label: .globl main_label");
|
||||
return 0;
|
||||
}
|
||||
108
gdb/testsuite/gdb.dwarf2/symbol_needs_eval_fail.exp
Normal file
108
gdb/testsuite/gdb.dwarf2/symbol_needs_eval_fail.exp
Normal file
@@ -0,0 +1,108 @@
|
||||
# Copyright 2017-2020 Free Software Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
# Test the symbol needs check mechanism if it assumes that faking
|
||||
# reads from a target is a safe thing to do.
|
||||
#
|
||||
# In particular, the test uses a relative branch DWARF operation to
|
||||
# hide a register read. If the target reads are indeed faked, the
|
||||
# result returned will be wrong.
|
||||
|
||||
load_lib dwarf.exp
|
||||
|
||||
# This test can only be run on targets which support DWARF-2 and use gas.
|
||||
if {![dwarf2_support]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Choose suitable integer registers for the test.
|
||||
|
||||
set dwarf_regnum 0
|
||||
|
||||
if { [is_aarch64_target] } {
|
||||
set regname x0
|
||||
} elseif { [is_aarch32_target]
|
||||
|| [istarget "s390*-*-*" ]
|
||||
|| [istarget "powerpc*-*-*"]
|
||||
|| [istarget "rs6000*-*-aix*"] } {
|
||||
set regname r0
|
||||
} elseif { [is_x86_like_target] } {
|
||||
set regname eax
|
||||
} elseif { [is_amd64_regs_target] } {
|
||||
set regname rax
|
||||
} else {
|
||||
verbose "Skipping ${gdb_test_file_name}."
|
||||
return
|
||||
}
|
||||
|
||||
standard_testfile symbol_needs_eval.c ${gdb_test_file_name}-dw.S
|
||||
|
||||
# Make some DWARF for the test.
|
||||
|
||||
set asm_file [standard_output_file $srcfile2]
|
||||
Dwarf::assemble $asm_file {
|
||||
global dwarf_regnum regname
|
||||
|
||||
set exec_mask_var [gdb_target_symbol exec_mask]
|
||||
|
||||
cu {} {
|
||||
DW_TAG_compile_unit {
|
||||
{DW_AT_name symbol_needs_eval.c}
|
||||
{DW_AT_comp_dir /tmp}
|
||||
} {
|
||||
declare_labels int_type_label
|
||||
|
||||
# define int type
|
||||
int_type_label: DW_TAG_base_type {
|
||||
{DW_AT_name "int"}
|
||||
{DW_AT_encoding @DW_ATE_signed}
|
||||
{DW_AT_byte_size 4 DW_FORM_sdata}
|
||||
}
|
||||
|
||||
# define artificial variable a
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name a}
|
||||
{DW_AT_type :$int_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_addr $exec_mask_var
|
||||
DW_OP_deref
|
||||
DW_OP_bra 4 # conditional jump to DW_OP_bregx
|
||||
DW_OP_lit0
|
||||
DW_OP_skip 3 # jump to DW_OP_stack_value
|
||||
DW_OP_bregx $dwarf_regnum 0
|
||||
DW_OP_stack_value
|
||||
} SPECIAL_expr}
|
||||
{external 1 flag}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if { [prepare_for_testing ${testfile}.exp ${testfile} \
|
||||
[list $srcfile $asm_file] {nodebug}] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
# The variable's location expression requires a frame,
|
||||
# so an error should be reported.
|
||||
gdb_test "print/d a" "No frame selected." "variable a can't be printed"
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test_no_output "set var \$$regname = 2" "init reg to 2"
|
||||
|
||||
gdb_test "print/d a" " = 2" "a == 2"
|
||||
127
gdb/testsuite/gdb.dwarf2/symbol_needs_eval_timeout.exp
Normal file
127
gdb/testsuite/gdb.dwarf2/symbol_needs_eval_timeout.exp
Normal file
@@ -0,0 +1,127 @@
|
||||
# Copyright 2017-2020 Free Software Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
# Test the symbol needs check mechanism if it assumes that faking
|
||||
# reads from a target is a safe thing to do.
|
||||
#
|
||||
# In particular, the test uses a relative branch DWARF operation to
|
||||
# potentially cause an infinite loop, if the target reads are indeed
|
||||
# faked.
|
||||
|
||||
load_lib dwarf.exp
|
||||
|
||||
# This test can only be run on targets which support DWARF-2 and use gas.
|
||||
if {![dwarf2_support]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Choose suitable integer registers for the test.
|
||||
|
||||
set dwarf_regnum 0
|
||||
|
||||
if { [is_aarch64_target] } {
|
||||
set regname x0
|
||||
} elseif { [is_aarch32_target]
|
||||
|| [istarget "s390*-*-*" ]
|
||||
|| [istarget "powerpc*-*-*"]
|
||||
|| [istarget "rs6000*-*-aix*"] } {
|
||||
set regname r0
|
||||
} elseif { [is_x86_like_target] } {
|
||||
set regname eax
|
||||
} elseif { [is_amd64_regs_target] } {
|
||||
set regname rax
|
||||
} else {
|
||||
verbose "Skipping ${gdb_test_file_name}."
|
||||
return
|
||||
}
|
||||
|
||||
standard_testfile symbol_needs_eval.c ${gdb_test_file_name}-dw.S
|
||||
|
||||
# Make some DWARF for the test.
|
||||
|
||||
set asm_file [standard_output_file $srcfile2]
|
||||
Dwarf::assemble $asm_file {
|
||||
global dwarf_regnum regname
|
||||
|
||||
set exec_mask_var [gdb_target_symbol exec_mask]
|
||||
|
||||
cu {} {
|
||||
DW_TAG_compile_unit {
|
||||
{DW_AT_name symbol_needs_eval.c}
|
||||
{DW_AT_comp_dir /tmp}
|
||||
} {
|
||||
declare_labels int_type_label
|
||||
|
||||
# define int type
|
||||
int_type_label: DW_TAG_base_type {
|
||||
{DW_AT_name "int"}
|
||||
{DW_AT_encoding @DW_ATE_signed}
|
||||
{DW_AT_byte_size 4 DW_FORM_sdata}
|
||||
}
|
||||
|
||||
# add info for variable exec_mask
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name exec_mask}
|
||||
{DW_AT_type :$int_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_addr $exec_mask_var
|
||||
} SPECIAL_expr}
|
||||
{external 1 flag}
|
||||
}
|
||||
|
||||
# add info for subprogram main
|
||||
DW_TAG_subprogram {
|
||||
{MACRO_AT_func { main }}
|
||||
{DW_AT_frame_base {
|
||||
DW_OP_regx $dwarf_regnum
|
||||
} SPECIAL_expr}
|
||||
} {
|
||||
# define artificial variable a
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name a}
|
||||
{DW_AT_type :$int_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_lit1
|
||||
DW_OP_addr $exec_mask_var
|
||||
DW_OP_deref
|
||||
DW_OP_skip 4 # jump to DW_OP_fbreg
|
||||
DW_OP_drop
|
||||
DW_OP_fbreg 0
|
||||
DW_OP_dup
|
||||
DW_OP_lit0
|
||||
DW_OP_eq
|
||||
DW_OP_bra -9 # conditional jump to DW_OP_drop
|
||||
DW_OP_stack_value
|
||||
} SPECIAL_expr}
|
||||
{external 1 flag}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if { [prepare_for_testing ${testfile}.exp ${testfile} \
|
||||
[list $srcfile $asm_file] {nodebug}] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test_no_output "set var \$$regname = 2" "init reg to 2"
|
||||
gdb_test_no_output "set var exec_mask = 0" "init exec_mask to 0"
|
||||
|
||||
gdb_test "print/d a" " = 2" "a == 2"
|
||||
@@ -102,7 +102,6 @@ die4e:
|
||||
.uleb128 1f - 2f # DW_AT_location
|
||||
2:
|
||||
.byte 0x13 # DW_OP_drop
|
||||
.quad 0
|
||||
1:
|
||||
#endif
|
||||
die5c:
|
||||
|
||||
@@ -63,4 +63,4 @@ set remote_python_file [gdb_remote_download host \
|
||||
${srcdir}/${subdir}/${testfile}.py]
|
||||
gdb_test_no_output "source ${remote_python_file}" "load python file"
|
||||
|
||||
gdb_test "bt" "niam \\(argc=<error reading variable: dwarf expression stack underflow>, argv=0x\[0-9a-f\]+\\) at py-framefilter-invalidarg.c:\[0-9\]+" "bt full with filters"
|
||||
gdb_test "bt" "niam \\(argc=<error reading variable: dwarf expression stack underflow>, argv=0x\[0-9a-f\]+\\) at py-framefilter-invalidarg.c:\[0-9\]+" "bt full with filters"
|
||||
@@ -1018,6 +1018,14 @@ namespace eval Dwarf {
|
||||
_op .sleb128 [lindex $line 2]
|
||||
}
|
||||
|
||||
DW_OP_fbreg {
|
||||
_op .sleb128 [lindex $line 1]
|
||||
}
|
||||
|
||||
DW_OP_LLVM_offset_constu {
|
||||
_op .uleb128 [lindex $line 1]
|
||||
}
|
||||
|
||||
default {
|
||||
if {[llength $line] > 1} {
|
||||
error "Unimplemented: operands in location for $opcode"
|
||||
|
||||
125
gdb/valops.c
125
gdb/valops.c
@@ -1018,20 +1018,31 @@ read_value_memory (struct value *val, LONGEST bit_offset,
|
||||
ULONGEST xfered_total = 0;
|
||||
struct gdbarch *arch = get_value_arch (val);
|
||||
int unit_size = gdbarch_addressable_memory_unit_size (arch);
|
||||
bool big_endian = type_byte_order (value_type (val)) == BFD_ENDIAN_BIG;
|
||||
enum target_object object;
|
||||
size_t extended_length
|
||||
= length + (bit_offset + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
|
||||
gdb_byte *buffer_ptr = buffer;
|
||||
gdb::byte_vector temp_buffer;
|
||||
|
||||
if (bit_offset)
|
||||
{
|
||||
temp_buffer.resize (extended_length);
|
||||
buffer_ptr = temp_buffer.data ();
|
||||
}
|
||||
|
||||
object = stack ? TARGET_OBJECT_STACK_MEMORY : TARGET_OBJECT_MEMORY;
|
||||
|
||||
while (xfered_total < length)
|
||||
while (xfered_total < extended_length)
|
||||
{
|
||||
enum target_xfer_status status;
|
||||
ULONGEST xfered_partial;
|
||||
|
||||
status = target_xfer_partial (current_top_target (),
|
||||
object, NULL,
|
||||
buffer + xfered_total * unit_size, NULL,
|
||||
buffer_ptr + xfered_total * unit_size, NULL,
|
||||
memaddr + xfered_total,
|
||||
length - xfered_total,
|
||||
extended_length - xfered_total,
|
||||
&xfered_partial);
|
||||
|
||||
if (status == TARGET_XFER_OK)
|
||||
@@ -1048,6 +1059,10 @@ read_value_memory (struct value *val, LONGEST bit_offset,
|
||||
xfered_total += xfered_partial;
|
||||
QUIT;
|
||||
}
|
||||
|
||||
if (bit_offset)
|
||||
copy_bitwise (buffer, 0, temp_buffer.data (),
|
||||
bit_offset, length * HOST_CHAR_BIT, big_endian);
|
||||
}
|
||||
|
||||
/* Store the contents of FROMVAL into the location of TOVAL.
|
||||
@@ -1119,7 +1134,7 @@ value_assign (struct value *toval, struct value *fromval)
|
||||
const gdb_byte *dest_buffer;
|
||||
CORE_ADDR changed_addr;
|
||||
int changed_len;
|
||||
gdb_byte buffer[sizeof (LONGEST)];
|
||||
gdb::byte_vector buffer;
|
||||
|
||||
if (value_bitsize (toval))
|
||||
{
|
||||
@@ -1145,10 +1160,25 @@ value_assign (struct value *toval, struct value *fromval)
|
||||
"don't fit in a %d bit word."),
|
||||
(int) sizeof (LONGEST) * HOST_CHAR_BIT);
|
||||
|
||||
read_memory (changed_addr, buffer, changed_len);
|
||||
modify_field (type, buffer, value_as_long (fromval),
|
||||
buffer.resize (changed_len);
|
||||
|
||||
read_memory (changed_addr, buffer.data (), changed_len);
|
||||
modify_field (type, buffer.data (), value_as_long (fromval),
|
||||
value_bitpos (toval), value_bitsize (toval));
|
||||
dest_buffer = buffer;
|
||||
dest_buffer = buffer.data ();
|
||||
}
|
||||
else if (value_bitpos (toval))
|
||||
{
|
||||
int bitpos = value_bitpos (toval);
|
||||
bool big_endian = type_byte_order (type) == BFD_ENDIAN_BIG;
|
||||
changed_addr = value_address (toval);
|
||||
changed_len = TYPE_LENGTH (type)
|
||||
+ (bitpos + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
|
||||
buffer.resize (changed_len);
|
||||
read_memory (changed_addr, buffer.data (), changed_len);
|
||||
copy_bitwise (buffer.data (), bitpos, value_contents (fromval),
|
||||
0, TYPE_LENGTH (type) * HOST_CHAR_BIT, big_endian);
|
||||
dest_buffer = buffer.data();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1163,10 +1193,6 @@ value_assign (struct value *toval, struct value *fromval)
|
||||
|
||||
case lval_register:
|
||||
{
|
||||
struct frame_info *frame;
|
||||
struct gdbarch *gdbarch;
|
||||
int value_reg;
|
||||
|
||||
/* Figure out which frame this is in currently.
|
||||
|
||||
We use VALUE_FRAME_ID for obtaining the value's frame id instead of
|
||||
@@ -1174,35 +1200,45 @@ value_assign (struct value *toval, struct value *fromval)
|
||||
put_frame_register_bytes() below. That function will (eventually)
|
||||
perform the necessary unwind operation by first obtaining the next
|
||||
frame. */
|
||||
frame = frame_find_by_id (VALUE_FRAME_ID (toval));
|
||||
|
||||
value_reg = VALUE_REGNUM (toval);
|
||||
struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (toval));
|
||||
|
||||
if (!frame)
|
||||
error (_("Value being assigned to is no longer active."));
|
||||
|
||||
gdbarch = get_frame_arch (frame);
|
||||
struct gdbarch *gdbarch = get_frame_arch (frame);
|
||||
int value_reg = VALUE_REGNUM (toval);
|
||||
LONGEST bitpos = value_bitpos (toval);
|
||||
LONGEST bitsize = value_bitsize (toval);
|
||||
LONGEST offset = value_offset (toval);
|
||||
|
||||
if (value_bitsize (toval))
|
||||
if (bitpos || bitsize)
|
||||
{
|
||||
struct value *parent = value_parent (toval);
|
||||
LONGEST offset = value_offset (parent) + value_offset (toval);
|
||||
int changed_len;
|
||||
gdb_byte buffer[sizeof (LONGEST)];
|
||||
bool big_endian = type_byte_order (type) == BFD_ENDIAN_BIG;
|
||||
|
||||
if (bitsize)
|
||||
{
|
||||
changed_len = (bitpos + bitsize + HOST_CHAR_BIT - 1)
|
||||
/ HOST_CHAR_BIT;
|
||||
|
||||
if (changed_len > (int) sizeof (LONGEST))
|
||||
error (_("Can't handle bitfields which "
|
||||
"don't fit in a %d bit word."),
|
||||
(int) sizeof (LONGEST) * HOST_CHAR_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
changed_len = TYPE_LENGTH (type)
|
||||
+ (bitpos + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
|
||||
|
||||
bitsize = TYPE_LENGTH (type) * HOST_CHAR_BIT;
|
||||
}
|
||||
|
||||
gdb::byte_vector buffer (changed_len);
|
||||
int optim, unavail;
|
||||
|
||||
changed_len = (value_bitpos (toval)
|
||||
+ value_bitsize (toval)
|
||||
+ HOST_CHAR_BIT - 1)
|
||||
/ HOST_CHAR_BIT;
|
||||
|
||||
if (changed_len > (int) sizeof (LONGEST))
|
||||
error (_("Can't handle bitfields which "
|
||||
"don't fit in a %d bit word."),
|
||||
(int) sizeof (LONGEST) * HOST_CHAR_BIT);
|
||||
|
||||
if (!get_frame_register_bytes (frame, value_reg, offset,
|
||||
changed_len, buffer,
|
||||
changed_len, buffer.data (),
|
||||
&optim, &unavail))
|
||||
{
|
||||
if (optim)
|
||||
@@ -1213,11 +1249,11 @@ value_assign (struct value *toval, struct value *fromval)
|
||||
_("value is not available"));
|
||||
}
|
||||
|
||||
modify_field (type, buffer, value_as_long (fromval),
|
||||
value_bitpos (toval), value_bitsize (toval));
|
||||
copy_bitwise (buffer.data (), bitpos, value_contents (fromval),
|
||||
0, bitsize, big_endian);
|
||||
|
||||
put_frame_register_bytes (frame, value_reg, offset,
|
||||
changed_len, buffer);
|
||||
changed_len, buffer.data ());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1234,8 +1270,7 @@ value_assign (struct value *toval, struct value *fromval)
|
||||
else
|
||||
{
|
||||
put_frame_register_bytes (frame, value_reg,
|
||||
value_offset (toval),
|
||||
TYPE_LENGTH (type),
|
||||
offset, TYPE_LENGTH (type),
|
||||
value_contents (fromval));
|
||||
}
|
||||
}
|
||||
@@ -1337,21 +1372,22 @@ value_assign (struct value *toval, struct value *fromval)
|
||||
struct value *
|
||||
value_repeat (struct value *arg1, int count)
|
||||
{
|
||||
struct value *val;
|
||||
|
||||
if (VALUE_LVAL (arg1) != lval_memory)
|
||||
error (_("Only values in memory can be extended with '@'."));
|
||||
if (count < 1)
|
||||
error (_("Invalid number %d of repetitions."), count);
|
||||
|
||||
val = allocate_repeat_value (value_enclosing_type (arg1), count);
|
||||
struct value *val
|
||||
= allocate_repeat_value (value_enclosing_type (arg1), count);
|
||||
|
||||
VALUE_LVAL (val) = lval_memory;
|
||||
set_value_address (val, value_address (arg1));
|
||||
set_value_bitpos (val, value_bitpos (arg1));
|
||||
struct type *enclosing_type = value_enclosing_type (val);
|
||||
|
||||
read_value_memory (val, 0, value_stack (val), value_address (val),
|
||||
value_contents_all_raw (val),
|
||||
type_length_units (value_enclosing_type (val)));
|
||||
read_value_memory (val, value_bitpos (val), value_stack (val),
|
||||
value_address (val), value_contents_all_raw (val),
|
||||
type_length_units (enclosing_type));
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -1700,7 +1736,7 @@ value_array (int lowbound, int highbound, struct value **elemvec)
|
||||
{
|
||||
val = allocate_value (arraytype);
|
||||
for (idx = 0; idx < nelem; idx++)
|
||||
value_contents_copy (val, idx * typelength, elemvec[idx], 0,
|
||||
value_contents_copy (val, idx * typelength, elemvec[idx], 0, 0,
|
||||
typelength);
|
||||
return val;
|
||||
}
|
||||
@@ -1710,7 +1746,8 @@ value_array (int lowbound, int highbound, struct value **elemvec)
|
||||
|
||||
val = allocate_value (arraytype);
|
||||
for (idx = 0; idx < nelem; idx++)
|
||||
value_contents_copy (val, idx * typelength, elemvec[idx], 0, typelength);
|
||||
value_contents_copy (val, idx * typelength, elemvec[idx], 0, 0,
|
||||
typelength);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -3977,7 +4014,7 @@ value_slice (struct value *array, int lowbound, int length)
|
||||
else
|
||||
{
|
||||
slice = allocate_value (slice_type);
|
||||
value_contents_copy (slice, 0, array, offset,
|
||||
value_contents_copy (slice, 0, array, offset, 0,
|
||||
type_length_units (slice_type));
|
||||
}
|
||||
|
||||
|
||||
70
gdb/value.c
70
gdb/value.c
@@ -1306,9 +1306,10 @@ value_ranges_copy_adjusted (struct value *dst, int dst_bit_offset,
|
||||
|
||||
void
|
||||
value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
|
||||
struct value *src, LONGEST src_offset, LONGEST length)
|
||||
struct value *src, LONGEST src_offset,
|
||||
LONGEST src_bit_offset, LONGEST length)
|
||||
{
|
||||
LONGEST src_bit_offset, dst_bit_offset, bit_length;
|
||||
LONGEST src_total_bit_offset, dst_total_bit_offset, bit_length;
|
||||
struct gdbarch *arch = get_value_arch (src);
|
||||
int unit_size = gdbarch_addressable_memory_unit_size (arch);
|
||||
|
||||
@@ -1327,17 +1328,29 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
|
||||
TARGET_CHAR_BIT * length));
|
||||
|
||||
/* Copy the data. */
|
||||
memcpy (value_contents_all_raw (dst) + dst_offset * unit_size,
|
||||
value_contents_all_raw (src) + src_offset * unit_size,
|
||||
length * unit_size);
|
||||
|
||||
/* Copy the meta-data, adjusted. */
|
||||
src_bit_offset = src_offset * unit_size * HOST_CHAR_BIT;
|
||||
dst_bit_offset = dst_offset * unit_size * HOST_CHAR_BIT;
|
||||
bit_length = length * unit_size * HOST_CHAR_BIT;
|
||||
|
||||
value_ranges_copy_adjusted (dst, dst_bit_offset,
|
||||
src, src_bit_offset,
|
||||
if (src_bit_offset)
|
||||
{
|
||||
bool big_endian = type_byte_order (value_type (dst)) == BFD_ENDIAN_BIG;
|
||||
|
||||
copy_bitwise (value_contents_all_raw (dst) + dst_offset * unit_size, 0,
|
||||
value_contents_all_raw (src) + src_offset * unit_size,
|
||||
src_bit_offset, bit_length, big_endian);
|
||||
}
|
||||
else
|
||||
memcpy (value_contents_all_raw (dst) + dst_offset * unit_size,
|
||||
value_contents_all_raw (src) + src_offset * unit_size,
|
||||
length * unit_size);
|
||||
|
||||
/* Copy the meta-data, adjusted. */
|
||||
src_total_bit_offset = src_offset * unit_size * HOST_CHAR_BIT
|
||||
+ src_bit_offset;
|
||||
dst_total_bit_offset = dst_offset * unit_size * HOST_CHAR_BIT;
|
||||
|
||||
|
||||
value_ranges_copy_adjusted (dst, dst_total_bit_offset,
|
||||
src, src_total_bit_offset,
|
||||
bit_length);
|
||||
}
|
||||
|
||||
@@ -1353,12 +1366,14 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
|
||||
|
||||
void
|
||||
value_contents_copy (struct value *dst, LONGEST dst_offset,
|
||||
struct value *src, LONGEST src_offset, LONGEST length)
|
||||
struct value *src, LONGEST src_offset,
|
||||
LONGEST src_bit_offset, LONGEST length)
|
||||
{
|
||||
if (src->lazy)
|
||||
value_fetch_lazy (src);
|
||||
|
||||
value_contents_copy_raw (dst, dst_offset, src, src_offset, length);
|
||||
value_contents_copy_raw (dst, dst_offset, src, src_offset,
|
||||
src_bit_offset, length);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -3015,7 +3030,7 @@ value_primitive_field (struct value *arg1, LONGEST offset,
|
||||
else
|
||||
{
|
||||
v = allocate_value (value_enclosing_type (arg1));
|
||||
value_contents_copy_raw (v, 0, arg1, 0,
|
||||
value_contents_copy_raw (v, 0, arg1, 0, 0,
|
||||
TYPE_LENGTH (value_enclosing_type (arg1)));
|
||||
}
|
||||
v->type = type;
|
||||
@@ -3050,7 +3065,7 @@ value_primitive_field (struct value *arg1, LONGEST offset,
|
||||
v = allocate_value (type);
|
||||
value_contents_copy_raw (v, value_embedded_offset (v),
|
||||
arg1, value_embedded_offset (arg1) + offset,
|
||||
type_length_units (type));
|
||||
0, type_length_units (type));
|
||||
}
|
||||
v->offset = (value_offset (arg1) + offset
|
||||
+ value_embedded_offset (arg1));
|
||||
@@ -3401,7 +3416,7 @@ pack_long (gdb_byte *buf, struct type *type, LONGEST num)
|
||||
|
||||
/* Pack NUM into BUF using a target format of TYPE. */
|
||||
|
||||
static void
|
||||
void
|
||||
pack_unsigned_long (gdb_byte *buf, struct type *type, ULONGEST num)
|
||||
{
|
||||
LONGEST len;
|
||||
@@ -3644,7 +3659,7 @@ value_from_component (struct value *whole, struct type *type, LONGEST offset)
|
||||
v = allocate_value (type);
|
||||
value_contents_copy (v, value_embedded_offset (v),
|
||||
whole, value_embedded_offset (whole) + offset,
|
||||
type_length_units (type));
|
||||
0, type_length_units (type));
|
||||
}
|
||||
v->offset = value_offset (whole) + offset + value_embedded_offset (whole);
|
||||
set_value_component_location (v, whole);
|
||||
@@ -3827,9 +3842,9 @@ value_fetch_lazy_memory (struct value *val)
|
||||
struct type *type = check_typedef (value_enclosing_type (val));
|
||||
|
||||
if (TYPE_LENGTH (type))
|
||||
read_value_memory (val, 0, value_stack (val),
|
||||
addr, value_contents_all_raw (val),
|
||||
type_length_units (type));
|
||||
read_value_memory (val, value_bitpos (val), value_stack (val),
|
||||
addr, value_contents_all_raw (val),
|
||||
type_length_units (type));
|
||||
}
|
||||
|
||||
/* Helper for value_fetch_lazy when the value is in a register. */
|
||||
@@ -3842,10 +3857,6 @@ value_fetch_lazy_register (struct value *val)
|
||||
struct type *type = check_typedef (value_type (val));
|
||||
struct value *new_val = val, *mark = value_mark ();
|
||||
|
||||
/* Offsets are not supported here; lazy register values must
|
||||
refer to the entire register. */
|
||||
gdb_assert (value_offset (val) == 0);
|
||||
|
||||
while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
|
||||
{
|
||||
struct frame_id next_frame_id = VALUE_NEXT_FRAME_ID (new_val);
|
||||
@@ -3888,6 +3899,11 @@ value_fetch_lazy_register (struct value *val)
|
||||
_("infinite loop while fetching a register"));
|
||||
}
|
||||
|
||||
/* Check if NEW_VALUE is big enough to cover
|
||||
the expected VAL type with an offset. */
|
||||
gdb_assert ((TYPE_LENGTH (type) + value_offset (val))
|
||||
<= TYPE_LENGTH (value_type (new_val)));
|
||||
|
||||
/* If it's still lazy (for instance, a saved register on the
|
||||
stack), fetch it. */
|
||||
if (value_lazy (new_val))
|
||||
@@ -3896,9 +3912,9 @@ value_fetch_lazy_register (struct value *val)
|
||||
/* Copy the contents and the unavailability/optimized-out
|
||||
meta-data from NEW_VAL to VAL. */
|
||||
set_value_lazy (val, 0);
|
||||
value_contents_copy (val, value_embedded_offset (val),
|
||||
new_val, value_embedded_offset (new_val),
|
||||
type_length_units (type));
|
||||
value_contents_copy (val, value_embedded_offset (val), new_val,
|
||||
value_embedded_offset (new_val) + value_offset (val),
|
||||
value_bitpos (val), type_length_units (type));
|
||||
|
||||
if (frame_debug)
|
||||
{
|
||||
|
||||
@@ -677,6 +677,8 @@ extern struct value *value_field_bitfield (struct type *type, int fieldno,
|
||||
const struct value *val);
|
||||
|
||||
extern void pack_long (gdb_byte *buf, struct type *type, LONGEST num);
|
||||
extern void pack_unsigned_long (gdb_byte *buf, struct type *type,
|
||||
ULONGEST num);
|
||||
|
||||
extern struct value *value_from_longest (struct type *type, LONGEST num);
|
||||
extern struct value *value_from_ulongest (struct type *type, ULONGEST num);
|
||||
@@ -737,10 +739,10 @@ extern struct value *allocate_value (struct type *type);
|
||||
extern struct value *allocate_value_lazy (struct type *type);
|
||||
extern void value_contents_copy (struct value *dst, LONGEST dst_offset,
|
||||
struct value *src, LONGEST src_offset,
|
||||
LONGEST length);
|
||||
LONGEST src_bit_offset, LONGEST length);
|
||||
extern void value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
|
||||
struct value *src, LONGEST src_offset,
|
||||
LONGEST length);
|
||||
LONGEST src_bit_offset, LONGEST length);
|
||||
|
||||
extern struct value *allocate_repeat_value (struct type *type, int count);
|
||||
|
||||
|
||||
@@ -704,6 +704,12 @@ DW_OP (DW_OP_PGI_omp_thread_num, 0xf8)
|
||||
to 0 except explicitly documented for one action. Please refer AArch64 DWARF
|
||||
ABI documentation for details. */
|
||||
DW_OP (DW_OP_AARCH64_operation, 0xea)
|
||||
/* LLVM extensions for heterogeneous targets */
|
||||
DW_OP_DUP (DW_OP_LLVM_offset, 0xe3)
|
||||
DW_OP_DUP (DW_OP_LLVM_offset_constu, 0xe4)
|
||||
DW_OP_DUP (DW_OP_LLVM_bit_offset, 0xe5)
|
||||
DW_OP (DW_OP_LLVM_undefined, 0xe7)
|
||||
DW_OP_DUP (DW_OP_LLVM_piece_end, 0xea)
|
||||
DW_END_OP
|
||||
|
||||
DW_FIRST_ATE (DW_ATE_void, 0x0)
|
||||
|
||||
Reference in New Issue
Block a user