mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-26 09:08:59 +00:00
Add support for nested composite locations
After allowing a location description to be placed on a DWARF stack, in an effort to achieve a full composability of the DWARF expression, it is necessary to enable forming of a nested composite location descriptions. To be able do this, a new operation DW_OP_LLVM_piece_end needs to be introduced, along with some additional rules on the way how the composite location description is formed using the existing DW_OP_piece and DW_OP_bit_piece operations. These new rules are fully compatible with the composite forming rules from the DWARF 5 standard. More details on the new operation and added rules can be found here: https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html gdb/ChangeLog: * compile/compile-loc2c.c (compute_stack_depth_worker): Add new DW_OP_LLVM_piece_end operation support. * dwarf2/expr.c (class dwarf_value): Add copy constructor. (class dwarf_location): Add copy constructor. (class dwarf_undefined): Add copy constructor. (class dwarf_memory): Add copy constructor. (class dwarf_register): Add copy constructor. (class dwarf_implicit): Add copy constructor. (class dwarf_implicit_pointer): Add copy constructor. (class dwarf_composite): Add copy constructor. (read_from_location): Add composite completed check. (write_to_location): Add composite completed check. (read_value_contents_from_location): New function. (dwarf_entry_factory::copy_entry): New method. (rw_closure_value): Now calls read_value_contents_from_location function. (dwarf_expr_context::add_piece): Use new composite forming rules. (dwarf_expr_context::execute_stack_op): Add new DW_OP_LLVM_piece_end operation support. * dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new DW_OP_LLVM_piece_end operation support. include/ChangeLog: * dwarf2.def (DW_OP_DUP): Add new DW_OP_LLVM_piece_end enumeration. gdb/testsuite/ChangeLog: * gdb.dwarf2/dw2-llvm-piece-end.exp: New test. Change-Id: Ib0b25e5de3f23df89d7d9e86aad56029c7d173df
This commit is contained in:
committed by
Simon Marchi
parent
dab5aee6dc
commit
1127a49b32
@@ -365,6 +365,7 @@ compute_stack_depth_worker (int start, int *need_tempvar,
|
||||
++stack_depth;
|
||||
break;
|
||||
|
||||
case DW_OP_LLVM_piece_end:
|
||||
case DW_OP_LLVM_offset_constu:
|
||||
case DW_OP_nop:
|
||||
break;
|
||||
|
||||
@@ -308,6 +308,17 @@ public:
|
||||
m_type = type;
|
||||
}
|
||||
|
||||
dwarf_value (const dwarf_value &value)
|
||||
{
|
||||
struct type *type = value.m_type;
|
||||
size_t type_len = TYPE_LENGTH (type);
|
||||
|
||||
m_contents.reset ((gdb_byte *) xzalloc (type_len));
|
||||
|
||||
memcpy (m_contents.get (), value.m_contents.get (), type_len);
|
||||
m_type = type;
|
||||
}
|
||||
|
||||
virtual ~dwarf_value () = default;
|
||||
|
||||
const gdb_byte* get_contents () const
|
||||
@@ -352,6 +363,12 @@ public:
|
||||
m_bit_suboffset = bit_suboffset % HOST_CHAR_BIT;
|
||||
}
|
||||
|
||||
dwarf_location (const dwarf_location &location)
|
||||
: m_offset (location.m_offset),
|
||||
m_bit_suboffset (location.m_bit_suboffset),
|
||||
m_initialised (location.m_initialised)
|
||||
{}
|
||||
|
||||
virtual ~dwarf_location () = default;
|
||||
|
||||
LONGEST get_offset () const
|
||||
@@ -404,6 +421,11 @@ public:
|
||||
dwarf_undefined (LONGEST offset = 0, LONGEST bit_suboffset = 0)
|
||||
: dwarf_location (offset, bit_suboffset)
|
||||
{}
|
||||
|
||||
dwarf_undefined (const dwarf_undefined &undefined_entry)
|
||||
: dwarf_location (undefined_entry)
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
class dwarf_memory : public dwarf_location
|
||||
@@ -415,6 +437,11 @@ public:
|
||||
m_stack (stack)
|
||||
{}
|
||||
|
||||
dwarf_memory (const dwarf_memory &memory_entry)
|
||||
: dwarf_location (memory_entry),
|
||||
m_stack (memory_entry.m_stack)
|
||||
{}
|
||||
|
||||
bool in_stack () const
|
||||
{
|
||||
return m_stack;
|
||||
@@ -440,6 +467,11 @@ public:
|
||||
m_regnum (regnum)
|
||||
{}
|
||||
|
||||
dwarf_register (const dwarf_register ®ister_entry)
|
||||
: dwarf_location (register_entry),
|
||||
m_regnum (register_entry.m_regnum)
|
||||
{}
|
||||
|
||||
unsigned int get_regnum () const
|
||||
{
|
||||
return m_regnum;
|
||||
@@ -468,6 +500,17 @@ public:
|
||||
m_byte_order = byte_order;
|
||||
}
|
||||
|
||||
dwarf_implicit (const dwarf_implicit &implicit_entry)
|
||||
: dwarf_location (implicit_entry)
|
||||
{
|
||||
size_t size = implicit_entry.m_size;
|
||||
m_contents.reset ((gdb_byte *) xzalloc (size));
|
||||
|
||||
memcpy (m_contents.get (), implicit_entry.m_contents.get (), size);
|
||||
m_size = size;
|
||||
m_byte_order = implicit_entry.m_byte_order;
|
||||
}
|
||||
|
||||
const gdb_byte* get_contents () const
|
||||
{
|
||||
return m_contents.get ();
|
||||
@@ -508,6 +551,14 @@ public:
|
||||
m_addr_size (addr_size), m_die_offset (die_offset)
|
||||
{}
|
||||
|
||||
dwarf_implicit_pointer (const dwarf_implicit_pointer &implicit_ptr_entry)
|
||||
: dwarf_location (implicit_ptr_entry),
|
||||
m_per_objfile (implicit_ptr_entry.m_per_objfile),
|
||||
m_per_cu (implicit_ptr_entry.m_per_cu),
|
||||
m_addr_size (implicit_ptr_entry.m_addr_size),
|
||||
m_die_offset (implicit_ptr_entry.m_die_offset)
|
||||
{}
|
||||
|
||||
dwarf2_per_objfile *get_per_objfile () const
|
||||
{
|
||||
return m_per_objfile;
|
||||
@@ -551,6 +602,22 @@ public:
|
||||
: dwarf_location (offset, bit_suboffset)
|
||||
{}
|
||||
|
||||
dwarf_composite (const dwarf_composite &composite_entry)
|
||||
: dwarf_location (composite_entry)
|
||||
{
|
||||
/* We do a shallow copy of the pieces because they are not
|
||||
expected to be modified after they are already formed. */
|
||||
for (unsigned int i = 0; i < composite_entry.m_pieces.size (); i++)
|
||||
{
|
||||
dwarf_location* location = composite_entry.m_pieces[i].m_location;
|
||||
|
||||
location->incref ();
|
||||
m_pieces.emplace_back (location, composite_entry.m_pieces[i].m_size);
|
||||
}
|
||||
|
||||
m_completed = composite_entry.m_completed;
|
||||
}
|
||||
|
||||
/* A composite location gets detached from its factory object for
|
||||
the purpose of lval_computed resolution, which means that it
|
||||
needs to take care of garbage collecting its pieces. */
|
||||
@@ -591,6 +658,16 @@ public:
|
||||
return m_pieces.size ();
|
||||
}
|
||||
|
||||
void set_completed (bool completed)
|
||||
{
|
||||
m_completed = completed;
|
||||
};
|
||||
|
||||
bool is_completed () const
|
||||
{
|
||||
return m_completed;
|
||||
};
|
||||
|
||||
private:
|
||||
/* Composite piece that contains a piece location
|
||||
description and it's size. */
|
||||
@@ -608,6 +685,9 @@ private:
|
||||
|
||||
/* Vector of composite pieces. */
|
||||
std::vector<struct piece> m_pieces;
|
||||
|
||||
/* True if location description is completed. */
|
||||
bool m_completed = false;
|
||||
};
|
||||
|
||||
/* Read contents from the location specified by the DWARF location
|
||||
@@ -789,6 +869,9 @@ read_from_location (const dwarf_location *location, struct frame_info *frame,
|
||||
unsigned int pieces_num = composite_entry->get_pieces_num ();
|
||||
unsigned int i;
|
||||
|
||||
if (!composite_entry->is_completed ())
|
||||
ill_formed_expression ();
|
||||
|
||||
total_bits_to_skip += offset * HOST_CHAR_BIT + bit_suboffset;
|
||||
|
||||
/* Skip pieces covered by the read offset. */
|
||||
@@ -971,6 +1054,9 @@ write_to_location (const dwarf_location *location, struct frame_info *frame,
|
||||
unsigned int pieces_num = composite_entry->get_pieces_num ();
|
||||
unsigned int i;
|
||||
|
||||
if (!composite_entry->is_completed ())
|
||||
ill_formed_expression ();
|
||||
|
||||
total_bits_to_skip += offset * HOST_CHAR_BIT + bit_suboffset;
|
||||
|
||||
/* Skip pieces covered by the write offset. */
|
||||
@@ -1008,6 +1094,92 @@ write_to_location (const dwarf_location *location, struct frame_info *frame,
|
||||
internal_error (__FILE__, __LINE__, _("invalid location type"));
|
||||
}
|
||||
|
||||
/* Read value contents from the location specified by the DWARF
|
||||
location description entry LOCATION.
|
||||
|
||||
The read operation is performed in the context of FRAME. BIT_SIZE
|
||||
is the number of bits to read. The data read is copied to the
|
||||
caller-managed buffer BUF. BITS_TO_SKIP is a bit offset into the
|
||||
location and BUF_BIT_OFFSET is buffer BUF's bit offset.
|
||||
LOCATION_BIT_LIMIT is a maximum number of bits that location can
|
||||
hold, where value zero signifies that there is no such restriction.
|
||||
|
||||
Note that some location types can be read without a FRAME context. */
|
||||
|
||||
static void
|
||||
read_value_contents_from_location (struct value * value,
|
||||
const dwarf_location *location,
|
||||
struct frame_info *frame,
|
||||
LONGEST bits_to_skip,
|
||||
int value_bit_offset, size_t bit_size,
|
||||
size_t location_bit_limit)
|
||||
{
|
||||
/* Implicit pointers are handled later. */
|
||||
if (dynamic_cast<const dwarf_implicit_pointer *> (location) != nullptr)
|
||||
return;
|
||||
|
||||
auto composite_entry = dynamic_cast<const dwarf_composite *> (location);
|
||||
|
||||
if (composite_entry == nullptr)
|
||||
{
|
||||
int optimized, unavailable;
|
||||
bool big_endian = type_byte_order (value_type (value)) == BFD_ENDIAN_BIG;
|
||||
|
||||
read_from_location (location, frame, bits_to_skip,
|
||||
value_contents_raw (value),
|
||||
value_bit_offset, bit_size, location_bit_limit,
|
||||
big_endian, &optimized, &unavailable);
|
||||
|
||||
if (optimized)
|
||||
mark_value_bits_optimized_out (value, value_bit_offset, bit_size);
|
||||
if (unavailable)
|
||||
mark_value_bits_unavailable (value, value_bit_offset, bit_size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!composite_entry->is_completed ())
|
||||
ill_formed_expression ();
|
||||
|
||||
unsigned int pieces_num = composite_entry->get_pieces_num ();
|
||||
unsigned int i;
|
||||
|
||||
LONGEST total_bits_to_skip = bits_to_skip
|
||||
+ composite_entry->get_offset () * HOST_CHAR_BIT
|
||||
+ composite_entry->get_bit_suboffset ();
|
||||
|
||||
/* Skip pieces covered by the read offset. */
|
||||
for (i = 0; i < pieces_num; i++)
|
||||
{
|
||||
LONGEST piece_bit_size = composite_entry->get_bit_size_at (i);
|
||||
|
||||
if (total_bits_to_skip < piece_bit_size)
|
||||
break;
|
||||
|
||||
total_bits_to_skip -= piece_bit_size;
|
||||
}
|
||||
|
||||
for (; i < pieces_num; i++)
|
||||
{
|
||||
LONGEST piece_bit_size = composite_entry->get_bit_size_at (i);
|
||||
const dwarf_location *piece = composite_entry->get_piece_at (i);
|
||||
|
||||
if (piece_bit_size > bit_size)
|
||||
piece_bit_size = bit_size;
|
||||
|
||||
read_value_contents_from_location (value, piece, frame,
|
||||
total_bits_to_skip,
|
||||
value_bit_offset, piece_bit_size,
|
||||
piece_bit_size);
|
||||
|
||||
if (bit_size == piece_bit_size)
|
||||
break;
|
||||
|
||||
value_bit_offset += piece_bit_size;
|
||||
bit_size -= piece_bit_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a value entry to the matching struct value representation
|
||||
of a given TYPE. OFFSET defines the offset into the value
|
||||
contents.
|
||||
@@ -1107,6 +1279,9 @@ public:
|
||||
dwarf_composite *create_composite (LONGEST offset = 0,
|
||||
LONGEST bit_suboffset = 0);
|
||||
|
||||
/* Create a deep copy of the DWARF ENTRY. */
|
||||
dwarf_entry *copy_entry (dwarf_entry *entry);
|
||||
|
||||
/* Convert an entry to a location description entry. If the entry
|
||||
is a location description entry a dynamic cast is applied.
|
||||
|
||||
@@ -1252,6 +1427,33 @@ dwarf_entry_factory::create_composite (LONGEST offset, LONGEST bit_suboffset)
|
||||
return composite_entry;
|
||||
}
|
||||
|
||||
dwarf_entry *
|
||||
dwarf_entry_factory::copy_entry (dwarf_entry *entry)
|
||||
{
|
||||
dwarf_entry *entry_copy;
|
||||
|
||||
if (auto value = dynamic_cast<dwarf_value *> (entry))
|
||||
entry_copy = new dwarf_value (*value);
|
||||
else if (auto undefined = dynamic_cast<dwarf_undefined *> (entry))
|
||||
entry_copy = new dwarf_undefined (*undefined);
|
||||
else if (auto memory = dynamic_cast<dwarf_memory *> (entry))
|
||||
entry_copy = new dwarf_memory (*memory);
|
||||
else if (auto reg = dynamic_cast<dwarf_register *> (entry))
|
||||
entry_copy = new dwarf_register (*reg);
|
||||
else if (auto implicit = dynamic_cast<dwarf_implicit *> (entry))
|
||||
entry_copy = new dwarf_implicit (*implicit);
|
||||
else if (auto implicit_pointer
|
||||
= dynamic_cast<dwarf_implicit_pointer *> (entry))
|
||||
entry_copy = new dwarf_implicit_pointer (*implicit_pointer);
|
||||
else if (auto composite = dynamic_cast<dwarf_composite *> (entry))
|
||||
entry_copy = new dwarf_composite (*composite);
|
||||
else
|
||||
internal_error (__FILE__, __LINE__, _("invalid DWARF entry to copy."));
|
||||
|
||||
record_entry (entry_copy);
|
||||
return entry_copy;
|
||||
}
|
||||
|
||||
dwarf_location *
|
||||
dwarf_entry_factory::entry_to_location (dwarf_entry *entry)
|
||||
{
|
||||
@@ -1460,30 +1662,19 @@ rw_closure_value (struct value *v, struct value *from)
|
||||
const dwarf_location *location = composite_entry->get_piece_at (i);
|
||||
ULONGEST bit_size = composite_entry->get_bit_size_at (i);
|
||||
size_t this_bit_size = bit_size - bits_to_skip;
|
||||
int optimized, unavailable;
|
||||
|
||||
if (this_bit_size > max_bit_offset - bit_offset)
|
||||
this_bit_size = max_bit_offset - bit_offset;
|
||||
|
||||
if (from == NULL)
|
||||
{
|
||||
/* Implicit pointers are handled later. */
|
||||
if (dynamic_cast<const dwarf_implicit_pointer *>
|
||||
(location) == nullptr)
|
||||
{
|
||||
read_from_location (location, frame, bits_to_skip,
|
||||
value_contents_raw (v), bit_offset,
|
||||
this_bit_size, bit_size, big_endian,
|
||||
&optimized, &unavailable);
|
||||
|
||||
if (optimized)
|
||||
mark_value_bits_optimized_out (v, bit_offset, this_bit_size);
|
||||
if (unavailable)
|
||||
mark_value_bits_unavailable (v, bit_offset, this_bit_size);
|
||||
}
|
||||
read_value_contents_from_location (v, location, frame, bits_to_skip,
|
||||
bit_offset, this_bit_size, bit_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
int optimized, unavailable;
|
||||
|
||||
write_to_location (location, frame, bits_to_skip,
|
||||
value_contents (from), bit_offset,
|
||||
this_bit_size, bit_size, big_endian,
|
||||
@@ -1892,10 +2083,34 @@ private:
|
||||
|
||||
/* Pop a top element of the stack and add as a composite piece.
|
||||
|
||||
If the fallowing top element of the stack is a composite
|
||||
location description, the piece will be added to it. Otherwise
|
||||
a new composite location description will be created and
|
||||
the piece will be added to that composite. */
|
||||
The action is based on the context:
|
||||
|
||||
- If the stack is empty, then an incomplete composite location
|
||||
description (comprised of one undefined location description),
|
||||
is pushed on the stack.
|
||||
|
||||
- Otherwise, if the top stack entry is an incomplete composite
|
||||
location description, then it is updated to append a new piece
|
||||
comprised of one undefined location description. The
|
||||
incomplete composite location description is then left on the
|
||||
stack.
|
||||
|
||||
- Otherwise, if the top stack entry is a location description or
|
||||
can be converted to one, it is popped. Then:
|
||||
|
||||
- If the top stack entry (after popping) is a location
|
||||
description comprised of one incomplete composite location
|
||||
description, then it is updated to append a new piece
|
||||
specified by the previously popped location description.
|
||||
The incomplete composite location description is then left
|
||||
on the stack.
|
||||
|
||||
- Otherwise, a new location description comprised of one
|
||||
incomplete composite location description, with a new piece
|
||||
specified by the previously popped location description, is
|
||||
pushed on the stack.
|
||||
|
||||
- Otherwise, the DWARF expression is ill-formed */
|
||||
dwarf_entry *add_piece (ULONGEST bit_size, ULONGEST bit_offset);
|
||||
|
||||
/* The engine for the expression evaluator. Using the context in this
|
||||
@@ -2534,26 +2749,39 @@ dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset)
|
||||
dwarf_location *piece_entry;
|
||||
dwarf_composite *composite_entry;
|
||||
|
||||
if (!stack_empty_p ()
|
||||
&& dynamic_cast<dwarf_composite *> (fetch (0)) == nullptr)
|
||||
if (stack_empty_p ())
|
||||
piece_entry = entry_factory->create_undefined ();
|
||||
else
|
||||
{
|
||||
piece_entry = entry_factory->entry_to_location (fetch (0));
|
||||
|
||||
if (auto old_composite_entry
|
||||
= dynamic_cast<dwarf_composite *> (piece_entry))
|
||||
{
|
||||
if (!old_composite_entry->is_completed ())
|
||||
piece_entry = entry_factory->create_undefined ();
|
||||
}
|
||||
else if (dynamic_cast<dwarf_undefined *> (piece_entry) != nullptr)
|
||||
pop ();
|
||||
}
|
||||
|
||||
if (dynamic_cast<dwarf_undefined *> (piece_entry) == nullptr)
|
||||
{
|
||||
piece_entry->add_bit_offset (bit_offset);
|
||||
pop ();
|
||||
}
|
||||
else
|
||||
piece_entry = entry_factory->create_undefined ();
|
||||
|
||||
piece_entry->add_bit_offset (bit_offset);
|
||||
|
||||
/* If stack is empty then it is a start of a new composite. In the
|
||||
future this will check if the composite is finished or not. */
|
||||
if (stack_empty_p ()
|
||||
|| dynamic_cast<dwarf_composite *> (fetch (0)) == nullptr)
|
||||
composite_entry = entry_factory->create_composite ();
|
||||
else
|
||||
{
|
||||
composite_entry = dynamic_cast<dwarf_composite *> (fetch (0));
|
||||
pop ();
|
||||
|
||||
if (composite_entry->is_completed ())
|
||||
composite_entry = entry_factory->create_composite ();
|
||||
else
|
||||
pop ();
|
||||
}
|
||||
|
||||
composite_entry->add_piece (piece_entry, bit_size);
|
||||
@@ -3156,7 +3384,7 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
|
||||
break;
|
||||
|
||||
case DW_OP_dup:
|
||||
result_entry = fetch (0);
|
||||
result_entry = entry_factory->copy_entry (fetch (0));
|
||||
break;
|
||||
|
||||
case DW_OP_drop:
|
||||
@@ -3182,7 +3410,7 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
|
||||
}
|
||||
|
||||
case DW_OP_over:
|
||||
result_entry = fetch (1);
|
||||
result_entry = entry_factory->copy_entry (fetch (1));
|
||||
break;
|
||||
|
||||
case DW_OP_rot:
|
||||
@@ -3742,6 +3970,23 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
|
||||
result_entry = entry_factory->create_undefined ();
|
||||
break;
|
||||
|
||||
case DW_OP_LLVM_piece_end:
|
||||
{
|
||||
dwarf_entry *entry = fetch (0);
|
||||
|
||||
dwarf_composite *composite_entry
|
||||
= dynamic_cast<dwarf_composite *> (entry);
|
||||
|
||||
if (composite_entry == nullptr)
|
||||
ill_formed_expression ();
|
||||
|
||||
if (composite_entry->is_completed ())
|
||||
ill_formed_expression ();
|
||||
|
||||
composite_entry->set_completed (true);
|
||||
goto no_push;
|
||||
}
|
||||
|
||||
default:
|
||||
error (_("Unhandled dwarf expression opcode 0x%x"), op);
|
||||
}
|
||||
|
||||
@@ -1832,6 +1832,7 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
|
||||
case DW_OP_LLVM_offset:
|
||||
case DW_OP_LLVM_bit_offset:
|
||||
case DW_OP_LLVM_undefined:
|
||||
case DW_OP_LLVM_piece_end:
|
||||
break;
|
||||
|
||||
case DW_OP_form_tls_address:
|
||||
|
||||
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"
|
||||
|
||||
@@ -709,6 +709,7 @@ 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