mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
Compare commits
30 Commits
1ae9fa5c60
...
users/zari
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7383d64e7 | ||
|
|
a50f771b91 | ||
|
|
e56df7452d | ||
|
|
90c993b5a4 | ||
|
|
e88f8e00b1 | ||
|
|
63ec59357c | ||
|
|
0dec3e5ba2 | ||
|
|
edb4cff0d8 | ||
|
|
087ced679c | ||
|
|
c99af81b30 | ||
|
|
a572357c56 | ||
|
|
54ecae43a3 | ||
|
|
0b63131f07 | ||
|
|
416088cccd | ||
|
|
d9ff45713c | ||
|
|
957fb3d805 | ||
|
|
f5f70c00d8 | ||
|
|
8b08c52759 | ||
|
|
f10d92ca88 | ||
|
|
9ccbaf1956 | ||
|
|
7bd280514c | ||
|
|
47fc8df2f8 | ||
|
|
710e538fc4 | ||
|
|
b71ff12cf7 | ||
|
|
c4296c3e41 | ||
|
|
b650f7fd86 | ||
|
|
851fa76da8 | ||
|
|
0dd1a71b4d | ||
|
|
8b1bcaf79c | ||
|
|
de004eec8e |
@@ -531,7 +531,7 @@ coerce_unspec_val_to_type (struct value *val, struct type *type)
|
||||
else
|
||||
{
|
||||
result = allocate_value (type);
|
||||
value_contents_copy (result, 0, val, 0, TYPE_LENGTH (type));
|
||||
value_contents_copy (result, 0, val, 0, 0, TYPE_LENGTH (type));
|
||||
}
|
||||
set_value_component_location (result, val);
|
||||
set_value_bitsize (result, value_bitsize (val));
|
||||
|
||||
@@ -357,6 +357,27 @@ 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_select_bit_piece:
|
||||
stack_depth -= 2;
|
||||
break;
|
||||
|
||||
case DW_OP_LLVM_overlay:
|
||||
case DW_OP_LLVM_bit_overlay:
|
||||
stack_depth -= 3;
|
||||
break;
|
||||
|
||||
case DW_OP_LLVM_extend:
|
||||
case DW_OP_LLVM_piece_end:
|
||||
case DW_OP_LLVM_offset_constu:
|
||||
case DW_OP_nop:
|
||||
break;
|
||||
|
||||
|
||||
4591
gdb/dwarf2/expr.c
4591
gdb/dwarf2/expr.c
File diff suppressed because it is too large
Load Diff
@@ -27,249 +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. */
|
||||
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);
|
||||
|
||||
/* 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,
|
||||
int addr_size);
|
||||
virtual ~dwarf_expr_context () = default;
|
||||
|
||||
void push_address (CORE_ADDR value, 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 values. */
|
||||
std::vector<dwarf_stack_value> 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;
|
||||
|
||||
/* Location of the value. */
|
||||
dwarf_value_location m_location = DWARF_VALUE_MEMORY;
|
||||
|
||||
/* 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 m_len = 0;
|
||||
const gdb_byte *m_data = nullptr;
|
||||
|
||||
/* Initialization status of variable: Non-zero if variable has been
|
||||
initialized; zero otherwise. */
|
||||
int m_initialized = 0;
|
||||
|
||||
/* 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> m_pieces;
|
||||
|
||||
/* 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;
|
||||
|
||||
void eval (const gdb_byte *addr, size_t len);
|
||||
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 ();
|
||||
struct value *fetch (int n);
|
||||
CORE_ADDR fetch_address (int n);
|
||||
bool fetch_in_stack_memory (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);
|
||||
|
||||
/* Read LENGTH bytes at ADDR into BUF. This method also handles the
|
||||
case where a caller of the evaluator passes in some data,
|
||||
but with the address being 0. In this situation, we arrange for
|
||||
memory reads to come from the passed-in buffer. */
|
||||
void read_mem (gdb_byte *buf, CORE_ADDR addr, size_t length);
|
||||
};
|
||||
|
||||
/* Return the value of register number REG (a DWARF register number),
|
||||
read as an address in a given FRAME. */
|
||||
CORE_ADDR read_addr_from_reg (frame_info *frame, int reg);
|
||||
/* Return the address type used of the ARCH architecture and
|
||||
ADDR_SIZE is expected size of the type. */
|
||||
type *address_type (gdbarch *arch, 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);
|
||||
@@ -309,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 uleb128 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);
|
||||
|
||||
|
||||
@@ -193,6 +193,18 @@ dwarf2_frame_state::dwarf2_frame_state (CORE_ADDR pc_, struct dwarf2_cie *cie)
|
||||
{
|
||||
}
|
||||
|
||||
/* 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 (frame_info *frame, int reg)
|
||||
{
|
||||
gdbarch *arch = get_frame_arch (frame);
|
||||
int regnum = dwarf_reg_to_regnum_or_error (arch, reg);
|
||||
|
||||
return address_from_register (regnum, frame);
|
||||
}
|
||||
|
||||
/* Execute the required actions for both the DW_CFA_restore and
|
||||
DW_CFA_restore_extended instructions. */
|
||||
static void
|
||||
@@ -224,21 +236,35 @@ register %s (#%d) at %s"),
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
dwarf_expr_context ctx (per_objfile, addr_size);
|
||||
scoped_value_mark free_values;
|
||||
struct type *init_type = address_type (per_objfile->objfile->arch (),
|
||||
addr_size);
|
||||
|
||||
ctx.push_address (initial, initial_in_stack_memory);
|
||||
value *result_val = ctx.evaluate (exp, len, true, nullptr, this_frame);
|
||||
value *init_value = value_at_lazy (init_type, initial);
|
||||
std::vector<value *> init_values;
|
||||
|
||||
if (VALUE_LVAL (result_val) == lval_memory)
|
||||
return value_address (result_val);
|
||||
else
|
||||
return value_as_address (result_val);
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -969,10 +995,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:
|
||||
@@ -1170,24 +1200,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
|
||||
|
||||
@@ -1474,15 +1474,15 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
|
||||
if (size == 0)
|
||||
return allocate_optimized_out_value (subobj_type);
|
||||
|
||||
dwarf_expr_context ctx (per_objfile, per_cu->addr_size ());
|
||||
|
||||
value *retval;
|
||||
scoped_value_mark free_values;
|
||||
|
||||
try
|
||||
{
|
||||
retval = ctx.evaluate (data, size, as_lval, per_cu, frame, nullptr,
|
||||
type, subobj_type, subobj_byte_offset);
|
||||
retval
|
||||
= 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)
|
||||
{
|
||||
@@ -1553,23 +1553,28 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
|
||||
|
||||
dwarf2_per_objfile *per_objfile = dlbaton->per_objfile;
|
||||
dwarf2_per_cu_data *per_cu = dlbaton->per_cu;
|
||||
dwarf_expr_context ctx (per_objfile, per_cu->addr_size ());
|
||||
|
||||
value *result;
|
||||
scoped_value_mark free_values;
|
||||
std::vector<value *> init_values;
|
||||
|
||||
if (push_initial_value)
|
||||
{
|
||||
struct type *type = address_type (per_objfile->objfile->arch (),
|
||||
per_cu->addr_size ());
|
||||
|
||||
if (addr_stack != nullptr)
|
||||
ctx.push_address (addr_stack->addr, false);
|
||||
init_values.push_back (value_at_lazy (type, addr_stack->addr));
|
||||
else
|
||||
ctx.push_address (0, false);
|
||||
init_values.push_back (value_at_lazy (type, 0));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
result = ctx.evaluate (dlbaton->data, dlbaton->size,
|
||||
true, per_cu, frame, addr_stack);
|
||||
result
|
||||
= 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)
|
||||
{
|
||||
@@ -1919,6 +1924,12 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
|
||||
case DW_OP_nop:
|
||||
case DW_OP_GNU_uninit:
|
||||
case DW_OP_push_object_address:
|
||||
case DW_OP_LLVM_offset:
|
||||
case DW_OP_LLVM_bit_offset:
|
||||
case DW_OP_LLVM_undefined:
|
||||
case DW_OP_LLVM_piece_end:
|
||||
case DW_OP_LLVM_overlay:
|
||||
case DW_OP_LLVM_bit_overlay:
|
||||
break;
|
||||
|
||||
case DW_OP_form_tls_address:
|
||||
@@ -1936,6 +1947,7 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
|
||||
case DW_OP_constu:
|
||||
case DW_OP_plus_uconst:
|
||||
case DW_OP_piece:
|
||||
case DW_OP_LLVM_offset_constu:
|
||||
op_ptr = safe_skip_leb128 (op_ptr, expr_end);
|
||||
break;
|
||||
|
||||
@@ -1944,6 +1956,8 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
|
||||
break;
|
||||
|
||||
case DW_OP_bit_piece:
|
||||
case DW_OP_LLVM_extend:
|
||||
case DW_OP_LLVM_select_bit_piece:
|
||||
op_ptr = safe_skip_leb128 (op_ptr, expr_end);
|
||||
op_ptr = safe_skip_leb128 (op_ptr, expr_end);
|
||||
break;
|
||||
@@ -3652,6 +3666,33 @@ disassemble_dwarf_expression (struct ui_file *stream,
|
||||
data += offset_size;
|
||||
fprintf_filtered (stream, " offset %s", phex_nz (ul, offset_size));
|
||||
break;
|
||||
|
||||
case DW_OP_LLVM_offset_constu:
|
||||
data = safe_read_uleb128 (data, end, &ul);
|
||||
fprintf_filtered (stream, " %s", pulongest (ul));
|
||||
break;
|
||||
|
||||
case DW_OP_LLVM_extend:
|
||||
{
|
||||
uint64_t count;
|
||||
|
||||
data = safe_read_uleb128 (data, end, &ul);
|
||||
data = safe_read_uleb128 (data, end, &count);
|
||||
fprintf_filtered (stream, " piece size %s (bits) pieces count %s",
|
||||
pulongest (ul), pulongest (count));
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_OP_LLVM_select_bit_piece:
|
||||
{
|
||||
uint64_t count;
|
||||
|
||||
data = safe_read_uleb128 (data, end, &ul);
|
||||
data = safe_read_uleb128 (data, end, &count);
|
||||
fprintf_filtered (stream, " piece size %s (bits) pieces count %s",
|
||||
pulongest (ul), pulongest (count));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf_filtered (stream, "\n");
|
||||
|
||||
@@ -161,7 +161,7 @@ fortran_bounds_all_dims (bool lbound_p,
|
||||
gdb_assert (dst_offset + TYPE_LENGTH (value_type (v))
|
||||
<= TYPE_LENGTH (value_type (result)));
|
||||
gdb_assert (TYPE_LENGTH (value_type (v)) == elm_len);
|
||||
value_contents_copy (result, dst_offset, v, 0, elm_len);
|
||||
value_contents_copy (result, dst_offset, v, 0, 0, elm_len);
|
||||
|
||||
/* Peel another dimension of the array. */
|
||||
array_type = TYPE_TARGET_TYPE (array_type);
|
||||
@@ -289,7 +289,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));
|
||||
}
|
||||
@@ -736,7 +736,7 @@ fortran_array_shape (struct gdbarch *gdbarch, const language_defn *lang,
|
||||
gdb_assert (dst_offset + TYPE_LENGTH (value_type (v))
|
||||
<= TYPE_LENGTH (value_type (result)));
|
||||
gdb_assert (TYPE_LENGTH (value_type (v)) == elm_len);
|
||||
value_contents_copy (result, dst_offset, v, 0, elm_len);
|
||||
value_contents_copy (result, dst_offset, v, 0, 0, elm_len);
|
||||
|
||||
/* Peel another dimension of the array. */
|
||||
val_type = TYPE_TARGET_TYPE (val_type);
|
||||
|
||||
@@ -869,6 +869,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)));
|
||||
|
||||
@@ -892,7 +893,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;
|
||||
|
||||
45
gdb/frame.c
45
gdb/frame.c
@@ -1497,8 +1497,9 @@ get_frame_register_bytes (frame_info *frame, int regnum,
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy (myaddr, value_contents_all (value).data () + offset,
|
||||
curr_len);
|
||||
memcpy (myaddr,
|
||||
value_contents_all (value).data ()
|
||||
+ value_offset (value) + offset, curr_len);
|
||||
release_value (value);
|
||||
}
|
||||
|
||||
@@ -1532,21 +1533,53 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
|
||||
/* Copy the data. */
|
||||
while (len > 0)
|
||||
{
|
||||
struct value *value = frame_unwind_register_value (frame->next,
|
||||
regnum);
|
||||
/* Need to account the unwind register offset too. */
|
||||
offset += value == NULL ? 0 : value_offset (value);
|
||||
|
||||
if (offset >= register_size (gdbarch, regnum))
|
||||
{
|
||||
offset -= register_size (gdbarch, regnum);
|
||||
regnum++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int curr_len = register_size (gdbarch, regnum) - offset;
|
||||
|
||||
if (curr_len > len)
|
||||
curr_len = len;
|
||||
|
||||
const gdb_byte *myaddr = buffer.data ();
|
||||
if (curr_len == register_size (gdbarch, regnum))
|
||||
|
||||
/* Computed value is a special case. The computed callback
|
||||
mechanism requires a strut value argument, so we need to
|
||||
make one. */
|
||||
if (value != nullptr && VALUE_LVAL (value) == lval_computed)
|
||||
{
|
||||
const lval_funcs *funcs = value_computed_funcs (value);
|
||||
|
||||
if (funcs->write == nullptr)
|
||||
error (_("Attempt to assign to an unmodifiable value."));
|
||||
|
||||
type * reg_type = register_type (gdbarch, regnum);
|
||||
|
||||
struct value *from_value = allocate_value (reg_type);
|
||||
memcpy (value_contents_raw (from_value).data (), 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);
|
||||
gdb_assert (value != nullptr);
|
||||
|
||||
memcpy ((char *) value_contents_writeable (value).data () + offset,
|
||||
myaddr, curr_len);
|
||||
|
||||
147
gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp
Normal file
147
gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp
Normal file
@@ -0,0 +1,147 @@
|
||||
# Copyright (C) 2017-2021 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_extend operation.
|
||||
#
|
||||
# The test uses a composite location description, where all the pieces
|
||||
# are allocated in the same register by using the new operation.
|
||||
|
||||
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 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}
|
||||
} {
|
||||
|
||||
# All array elements are in first byte of REGNAME register.
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name var_array_1}
|
||||
{DW_AT_type :$array_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_regx $dwarf_regnum
|
||||
DW_OP_LLVM_extend 8 8
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
|
||||
# All array elements are in fourth byte of REGNAME register.
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name var_array_2}
|
||||
{DW_AT_type :$array_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_regx $dwarf_regnum
|
||||
DW_OP_LLVM_offset_constu 3
|
||||
DW_OP_LLVM_extend 8 8
|
||||
} 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 "0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1"}
|
||||
big {set val "0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4"}
|
||||
}
|
||||
|
||||
gdb_test "print/x var_array_1" " = \\{${val}\\}" "var_array_1 print"
|
||||
|
||||
switch $endian {
|
||||
little {set val "0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4"}
|
||||
big {set val "0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1"}
|
||||
}
|
||||
|
||||
gdb_test "print/x var_array_2" " = \\{${val}\\}" "var_array_2 print"
|
||||
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-2021 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"
|
||||
33
gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.c
Normal file
33
gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2022 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/>. */
|
||||
|
||||
unsigned buff[] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
void foo (unsigned dst[], unsigned src[], int len)
|
||||
{
|
||||
asm volatile ("foo_label: .globl foo_label");
|
||||
for (int i = 0; i < len; ++i)
|
||||
dst[i] += src[i];
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
asm volatile ("main_label: .globl main_label");
|
||||
foo (buff, buff, 1);
|
||||
return 0;
|
||||
}
|
||||
213
gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.exp
Normal file
213
gdb/testsuite/gdb.dwarf2/dw2-llvm-overlay.exp
Normal file
@@ -0,0 +1,213 @@
|
||||
# Copyright (C) 2022 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_overlay operation.
|
||||
#
|
||||
# The test uses a composite location description, where variable buff
|
||||
# address is used as a base location and a reg1 is used as an overlay
|
||||
# location.
|
||||
|
||||
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 1}
|
||||
|
||||
if { [is_aarch64_target] } {
|
||||
set regname {x0 x1}
|
||||
} elseif { [is_aarch32_target]
|
||||
|| [istarget "s390*-*-*" ]
|
||||
|| [istarget "powerpc*-*-*"]
|
||||
|| [istarget "rs6000*-*-aix*"] } {
|
||||
set regname {r0 r1}
|
||||
} elseif { [is_x86_like_target] } {
|
||||
set regname {eax ecx}
|
||||
} elseif { [is_amd64_regs_target] } {
|
||||
set regname {rax rdx}
|
||||
} else {
|
||||
verbose "Skipping $gdb_test_file_name."
|
||||
return
|
||||
}
|
||||
|
||||
standard_testfile .c -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 buff_src [gdb_target_symbol buff]
|
||||
|
||||
set foo_result [function_range foo ${srcdir}/${subdir}/${srcfile}]
|
||||
set foo_start [lindex $foo_result 0]
|
||||
set foo_length [lindex $foo_result 1]
|
||||
|
||||
cu {} {
|
||||
DW_TAG_compile_unit {
|
||||
{DW_AT_name $srcfile}
|
||||
{DW_AT_comp_dir /tmp}
|
||||
} {
|
||||
declare_labels int_type_label uint_type_label array_type_label
|
||||
|
||||
uint_type_label: DW_TAG_base_type {
|
||||
{DW_AT_name "uint32_t"}
|
||||
{DW_AT_encoding @DW_ATE_unsigned}
|
||||
{DW_AT_byte_size 4 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 :$uint_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 foo}
|
||||
{DW_AT_low_pc $foo_start addr}
|
||||
{DW_AT_high_pc $foo_length data8}
|
||||
} {
|
||||
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name dst_v1}
|
||||
{DW_AT_type :$array_type_label}
|
||||
{DW_AT_location {
|
||||
# 1. Memory location description of dst elements located in memory:
|
||||
DW_OP_addr $buff_src
|
||||
|
||||
# 2. Register location description of element dst\[i\] is located in a register:
|
||||
DW_OP_regx [lindex $dwarf_regnum 1]
|
||||
|
||||
# 3. Offset of the register within the memory of dst:
|
||||
DW_OP_bregx [lindex $dwarf_regnum 0] 0
|
||||
DW_OP_lit4
|
||||
DW_OP_mul
|
||||
|
||||
# 4. The size of the register element:
|
||||
DW_OP_lit4
|
||||
|
||||
# 5. Make a composite location description for dst that is the memory #1 with
|
||||
# the register #2 positioned as an overlay at offset #3 of size #4:
|
||||
DW_OP_LLVM_overlay
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name dst_v2}
|
||||
{DW_AT_type :$array_type_label}
|
||||
{DW_AT_location {
|
||||
# 1. Memory location description of dst elements located in memory:
|
||||
DW_OP_addr $buff_src
|
||||
|
||||
# 2. Register location description of element dst\[i\] is located in a register:
|
||||
DW_OP_regx [lindex $dwarf_regnum 1]
|
||||
|
||||
# 3. Offset of the register within the memory of dst:
|
||||
DW_OP_bregx [lindex $dwarf_regnum 0] 0
|
||||
DW_OP_lit4
|
||||
DW_OP_mul
|
||||
|
||||
# 4. The size of the register element:
|
||||
DW_OP_lit4
|
||||
|
||||
# 5. Make a composite location description for dst that is the memory #1 with
|
||||
# the register #2 positioned as an overlay at offset #3 of size #4:
|
||||
DW_OP_LLVM_bit_overlay
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name src}
|
||||
{DW_AT_type :$array_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_addr $buff_src
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name i}
|
||||
{DW_AT_type :$int_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_regx [lindex $dwarf_regnum 0]
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if { [prepare_for_testing ${testfile}.exp ${testfile} \
|
||||
[list $srcfile $asm_file] {nodebug}] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test "break foo" "Breakpoint.*at.*" "break at function foo"
|
||||
gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+,.*foo \\(\\).*" \
|
||||
"continue to foo"
|
||||
|
||||
gdb_test_no_output "set var \$[lindex $regname 0] = 0x0" "init reg 0"
|
||||
gdb_test_no_output "set var \$[lindex $regname 1] = 0xdeadbeef" "init reg 1"
|
||||
|
||||
# gdb_interact
|
||||
|
||||
# Determine byte order.
|
||||
set endian [get_endianness]
|
||||
|
||||
switch $endian {
|
||||
little {set val_v1 "0xdeadbeef, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7"}
|
||||
big {set val_v1 "0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0xdeadbeef"}
|
||||
}
|
||||
|
||||
gdb_test "print/x dst_v1" " = \\{${val_v1}\\}" "dst_v1 print i = 0"
|
||||
|
||||
switch $endian {
|
||||
little {set val_v2 "0xf, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7"}
|
||||
big {set val_v2 "0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0xf"}
|
||||
}
|
||||
|
||||
gdb_test "print/x dst_v2" " = \\{${val_v2}\\}" "dst_v2 print i = 0"
|
||||
|
||||
gdb_test_no_output "set var i = 0x2" "init reg 0 to 2"
|
||||
|
||||
switch $endian {
|
||||
little {set val_v1 "0x0, 0x1, 0xdeadbeef, 0x3, 0x4, 0x5, 0x6, 0x7"}
|
||||
big {set val_v1 "0x7, 0x6, 0x5, 0x4, 0x3, 0xdeadbeef, 0x1, 0x0"}
|
||||
}
|
||||
|
||||
gdb_test "print/x dst_v1" " = \\{${val_v1}\\}" "dst_v1 print i = 2"
|
||||
|
||||
switch $endian {
|
||||
little {set val_v2 "0xf00, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7"}
|
||||
big {set val_v2 "0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0xf00"}
|
||||
}
|
||||
|
||||
gdb_test "print/x dst_v2" " = \\{${val_v2}\\}" "dst_v2 print i = 2"
|
||||
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 (C) 2017-2021 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"
|
||||
|
||||
138
gdb/testsuite/gdb.dwarf2/dw2-llvm-select-bit-piece.exp
Normal file
138
gdb/testsuite/gdb.dwarf2/dw2-llvm-select-bit-piece.exp
Normal file
@@ -0,0 +1,138 @@
|
||||
# Copyright (C) 2017-2021 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2020-2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
# 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_select_bit_piece operation.
|
||||
#
|
||||
# The test uses a composite location description, where all the pieces
|
||||
# are selected from two registers in odd/even pattern using the new
|
||||
# operation.
|
||||
|
||||
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 1}
|
||||
|
||||
if { [is_aarch64_target] } {
|
||||
set regname {x0 x1}
|
||||
} elseif { [is_aarch32_target]
|
||||
|| [istarget "s390*-*-*" ]
|
||||
|| [istarget "powerpc*-*-*"]
|
||||
|| [istarget "rs6000*-*-aix*"] } {
|
||||
set regname {r0 r1}
|
||||
} elseif { [is_x86_like_target] } {
|
||||
set regname {eax ecx}
|
||||
} elseif { [is_amd64_regs_target] } {
|
||||
set regname {rax rdx}
|
||||
} 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 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}
|
||||
} {
|
||||
|
||||
# Odd array elements are in first byte of REGNAME 0 register,
|
||||
# while even elements are in first byte of REGNAME 1 register.
|
||||
DW_TAG_variable {
|
||||
{DW_AT_name var_array}
|
||||
{DW_AT_type :$array_type_label}
|
||||
{DW_AT_location {
|
||||
DW_OP_regx [lindex $dwarf_regnum 0]
|
||||
DW_OP_LLVM_extend 8 8
|
||||
DW_OP_regx [lindex $dwarf_regnum 1]
|
||||
DW_OP_LLVM_extend 8 8
|
||||
DW_OP_constu 0xaa
|
||||
DW_OP_LLVM_select_bit_piece 8 8
|
||||
} 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 \$[lindex $regname 0] = 0x04030201" "init reg 0"
|
||||
gdb_test_no_output "set var \$[lindex $regname 1] = 0x01020304" "init reg 1"
|
||||
|
||||
# Determine byte order.
|
||||
set endian [get_endianness]
|
||||
|
||||
switch $endian {
|
||||
little {set val "0x1, 0x4, 0x1, 0x4, 0x1, 0x4, 0x1, 0x4"}
|
||||
big {set val "0x4, 0x1, 0x4, 0x1, 0x4, 0x1, 0x4, 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-2021 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"
|
||||
@@ -40,4 +40,4 @@ if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
gdb_test "p arraynoloc" " = <optimized out>"
|
||||
gdb_test "p arraycallnoloc" {Asked for position 0 of stack, stack only has 0 elements on it\.}
|
||||
gdb_test "p arraycallnoloc" {dwarf expression stack underflow}
|
||||
|
||||
@@ -32,4 +32,4 @@ if ![runto f] {
|
||||
|
||||
# FAIL was printing:
|
||||
# [...] in f (bad=)
|
||||
gdb_test "frame" { f \(bad=<error reading variable: Asked for position 0 of stack, stack only has 0 elements on it\.>, good=23\)}
|
||||
gdb_test "frame" { f \(bad=<error reading variable: dwarf expression stack underflow>, good=23\)}
|
||||
|
||||
@@ -64,5 +64,5 @@ if { $readnow_p } {
|
||||
}
|
||||
gdb_assert {$w1 && $w2}
|
||||
|
||||
gdb_test "p underflow" {Asked for position 0 of stack, stack only has 0 elements on it\.}
|
||||
gdb_test "p underflow" {dwarf expression stack underflow}
|
||||
gdb_test "p overflow" " = 2"
|
||||
|
||||
@@ -1221,6 +1221,20 @@ namespace eval Dwarf {
|
||||
_op .sleb128 [lindex $line 1]
|
||||
}
|
||||
|
||||
DW_OP_LLVM_offset_constu {
|
||||
_op .uleb128 [lindex $line 1]
|
||||
}
|
||||
|
||||
DW_OP_LLVM_extend {
|
||||
_op .uleb128 [lindex $line 1]
|
||||
_op .uleb128 [lindex $line 2]
|
||||
}
|
||||
|
||||
DW_OP_LLVM_select_bit_piece {
|
||||
_op .uleb128 [lindex $line 1]
|
||||
_op .uleb128 [lindex $line 2]
|
||||
}
|
||||
|
||||
default {
|
||||
if {[llength $line] > 1} {
|
||||
error "Unimplemented: operands in location for $opcode"
|
||||
|
||||
133
gdb/valops.c
133
gdb/valops.c
@@ -1040,20 +1040,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_inferior ()->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)
|
||||
@@ -1070,6 +1081,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.
|
||||
@@ -1141,7 +1156,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))
|
||||
{
|
||||
@@ -1167,10 +1182,26 @@ 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).data (), 0,
|
||||
TYPE_LENGTH (type) * HOST_CHAR_BIT, big_endian);
|
||||
dest_buffer = buffer.data();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1186,7 +1217,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 register value is in. The value
|
||||
@@ -1204,29 +1234,41 @@ value_assign (struct value *toval, struct value *fromval)
|
||||
if (!frame)
|
||||
error (_("Value being assigned to is no longer active."));
|
||||
|
||||
gdbarch = get_frame_arch (frame);
|
||||
gdbarch *arch = get_frame_arch (frame);
|
||||
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);
|
||||
size_t changed_len;
|
||||
gdb_byte buffer[sizeof (LONGEST)];
|
||||
int changed_len;
|
||||
bool big_endian = type_byte_order (type) == BFD_ENDIAN_BIG;
|
||||
|
||||
if (bitsize)
|
||||
{
|
||||
offset += value_offset (value_parent (toval));
|
||||
|
||||
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 > 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,
|
||||
{buffer, changed_len},
|
||||
&optim, &unavail))
|
||||
buffer, &optim, &unavail))
|
||||
{
|
||||
if (optim)
|
||||
throw_error (OPTIMIZED_OUT_ERROR,
|
||||
@@ -1236,23 +1278,21 @@ 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).data (),
|
||||
0, bitsize, big_endian);
|
||||
|
||||
put_frame_register_bytes (frame, value_reg, offset,
|
||||
{buffer, changed_len});
|
||||
put_frame_register_bytes (frame, value_reg, offset, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gdbarch_convert_register_p (gdbarch, VALUE_REGNUM (toval),
|
||||
type))
|
||||
if (gdbarch_convert_register_p (arch, VALUE_REGNUM (toval), type))
|
||||
{
|
||||
/* If TOVAL is a special machine register requiring
|
||||
conversion of program values to a special raw
|
||||
format. */
|
||||
gdbarch_value_to_register (gdbarch, frame,
|
||||
VALUE_REGNUM (toval), type,
|
||||
value_contents (fromval).data ());
|
||||
gdbarch_value_to_register (arch, frame, VALUE_REGNUM (toval),
|
||||
type, value_contents (fromval).data ());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1260,8 +1300,7 @@ value_assign (struct value *toval, struct value *fromval)
|
||||
= gdb::make_array_view (value_contents (fromval).data (),
|
||||
TYPE_LENGTH (type));
|
||||
put_frame_register_bytes (frame, value_reg,
|
||||
value_offset (toval),
|
||||
contents);
|
||||
offset, contents);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1363,21 +1402,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);
|
||||
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));
|
||||
type *enclosing_type = value_enclosing_type (val);
|
||||
|
||||
read_value_memory (val, 0, value_stack (val), value_address (val),
|
||||
value_contents_all_raw (val).data (),
|
||||
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).data (),
|
||||
type_length_units (enclosing_type));
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -1726,7 +1766,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;
|
||||
}
|
||||
@@ -1736,7 +1776,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;
|
||||
}
|
||||
|
||||
@@ -4005,7 +4046,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));
|
||||
}
|
||||
|
||||
|
||||
72
gdb/value.c
72
gdb/value.c
@@ -1322,9 +1322,10 @@ value_ranges_copy_adjusted (struct value *dst, int dst_bit_offset,
|
||||
|
||||
static 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);
|
||||
|
||||
@@ -1343,17 +1344,31 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
|
||||
TARGET_CHAR_BIT * length));
|
||||
|
||||
/* Copy the data. */
|
||||
memcpy (value_contents_all_raw (dst).data () + dst_offset * unit_size,
|
||||
value_contents_all_raw (src).data () + 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).data ()
|
||||
+ dst_offset * unit_size, 0,
|
||||
value_contents_all_raw (src).data ()
|
||||
+ src_offset * unit_size,
|
||||
src_bit_offset, bit_length, big_endian);
|
||||
}
|
||||
else
|
||||
memcpy (value_contents_all_raw (dst).data () + dst_offset * unit_size,
|
||||
value_contents_all_raw (src).data () + 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);
|
||||
}
|
||||
|
||||
@@ -1369,12 +1384,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
|
||||
@@ -3089,7 +3106,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;
|
||||
@@ -3124,7 +3141,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));
|
||||
@@ -3476,7 +3493,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;
|
||||
@@ -3731,7 +3748,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);
|
||||
@@ -3913,9 +3930,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).data (),
|
||||
type_length_units (type));
|
||||
read_value_memory (val, value_bitpos (val), value_stack (val),
|
||||
addr, value_contents_all_raw (val).data (),
|
||||
type_length_units (type));
|
||||
}
|
||||
|
||||
/* Helper for value_fetch_lazy when the value is in a register. */
|
||||
@@ -3928,10 +3945,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);
|
||||
@@ -3974,6 +3987,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))
|
||||
@@ -3982,9 +4000,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)
|
||||
{
|
||||
|
||||
@@ -678,6 +678,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);
|
||||
@@ -738,7 +740,7 @@ 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 struct value *allocate_repeat_value (struct type *type, int count);
|
||||
|
||||
|
||||
@@ -206,4 +206,22 @@ extern int hex2bin (const char *hex, gdb_byte *bin, int count);
|
||||
/* Like the above, but return a gdb::byte_vector. */
|
||||
gdb::byte_vector hex2bin (const char *hex);
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
#include <memory>
|
||||
|
||||
using std::make_unique;
|
||||
#else
|
||||
namespace gdb {
|
||||
|
||||
/* Stolen from libstdc++ and adjusted, so probably fine license-wise. */
|
||||
template<typename _Tp, typename ... _Args>
|
||||
std::unique_ptr<_Tp>
|
||||
make_unique (_Args &&... __args)
|
||||
{
|
||||
return std::unique_ptr<_Tp> (new _Tp (std::forward<_Args>(__args)...));
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* __cplusplus >= 201402L */
|
||||
|
||||
#endif /* COMMON_COMMON_UTILS_H */
|
||||
|
||||
@@ -704,6 +704,16 @@ 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_OP (DW_OP_LLVM_extend, 0xeb)
|
||||
DW_OP (DW_OP_LLVM_select_bit_piece, 0xec)
|
||||
DW_OP (DW_OP_LLVM_bit_overlay, 0xed)
|
||||
DW_OP (DW_OP_LLVM_overlay, 0xee)
|
||||
DW_END_OP
|
||||
|
||||
DW_FIRST_ATE (DW_ATE_void, 0x0)
|
||||
|
||||
Reference in New Issue
Block a user