Compare commits

...

30 Commits

Author SHA1 Message Date
Zoran Zaric
b7383d64e7 Add support for new DWARF overlay operations
Another complex DWARF expression operations, that are usefull for
SIMD/SIMT like architectures are: DW_OP_LLVM_overlay and
DW_OP_LLVM_bit_overlay. These operations pop four stack entries,
where the first must be an integral that represents an overlay size,
the second must be an integral that represents a starting point of the
overlay from the base location, the third must be a location
description that represents the overlay location description and the
forth must be a location description that represents the base location
description.

Resulting composite location description contains parts from base
location description, overlayed by the overlay location description,
starting from the overlay offset, ending at a sum of the overlay offset
and overlay size.

A new test in gdb.dwarf2 called dw2-llvm-overlay has been also added to
test the support for both operations.
2022-10-26 10:43:27 +01:00
Zoran Zaric
a50f771b91 Add support for DWARF location offset type that is larger than 64-bit
To support new DWARF extension restrictions for location handling a new
data type for representing an offset within a location has been added.

The new loc_offset type defines a separate handling of the byte and
sub_bit parts of the offset while enabling the byte part of the
information to utilize a full 64-bit range of values.
2022-10-25 14:32:49 +01:00
Zoran Zaric
e56df7452d Add DW_OP_LLVM_select_bit_piece DWARF operation
Second more complex DWARF expression operation, that is usefull for
SIMD/SIMT like architectures is DW_OP_LLVM_select_bit_piece. This
operation pops three stack entries, where the first must be an integral
type value that represents a bit mask, the second must be a location
description that represents the one-location description and the third
must be a location description that represents the zero-location
description.

Resulting composite location description contains a given number of
pieces of a given bit size, created with parts from either of the two
location description, based on the bit mask.

gdb/ChangeLog:

        * compile/compile-loc2c.c (compute_stack_depth_worker): Add
        new DW_OP_LLVM_select_bit_piece operation support.
        * dwarf2/expr.c (dwarf_expr_context::create_select_composite):
        New method that creates the select bit piece composite.
        (dwarf_location::slice): New method.
        (dwarf_composite::slice): New method.
        (dwarf_expr_context::execute_stack_op): Add new
        DW_OP_LLVM_select_bit_piece operation support.
        * dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new
        DW_OP_LLVM_select_bit_piece operation support.
        (disassemble_dwarf_expression): Add new
        DW_OP_LLVM_select_bit_piece operation support.

include/ChangeLog:

        * dwarf2.def: Add new DW_OP_LLVM_select_bit_piece enumeration.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-llvm-select-bit-piece.exp: New test.
        * lib/dwarf.exp: Add new DW_OP_LLVM_select_bit_piece operation
        support.
2021-11-05 11:48:16 +00:00
Zoran Zaric
90c993b5a4 Add DW_OP_LLVM_extend DWARF operation
Previous changes allow a new set of more complex DWARF expression
operations to be added which are very usefull for SIMD/SIMT like
architectures. First of which is the DW_OP_LLVM_extend operation
that pops one stack element (which must be a location description)
and treat it as a number of pieces of a new composite location
description.

This means that a resulting composite location contains a given
number of pieces of a given bit size, where all the pieces are
described by the same location description found on top of the stack.

gdb/ChangeLog:

        * compile/compile-loc2c.c (compute_stack_depth_worker): Add
        new DW_OP_LLVM_extend operation support.
        * dwarf2/expr.c (dwarf_expr_context::create_extend_composite):
        New method that creates the extend composite.
        (dwarf_expr_context::execute_stack_op): Add new
        DW_OP_LLVM_extend operation support.
        * dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new
        DW_OP_LLVM_extend operation support.
        (disassemble_dwarf_expression): Add new DW_OP_LLVM_extend
        operation support.

include/ChangeLog:

        * dwarf2.def: Add new DW_OP_LLVM_extend enumeration.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-llvm-extend.exp: New test.
        * lib/dwarf.exp: Add new DW_OP_LLVM_extend operation support.
2021-11-05 11:48:16 +00:00
Zoran Zaric
e88f8e00b1 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

The dwarf_composite also needed to be modified to make a distinction
between completed composite locationd description and not completed
one.

This also mean that some DWARF expression operations can duplicate a
composite location description that is not completed and end up with
more then one different composite location description on the stack.
To be able to do this, classes that derive from a DWARF entry class
need to have a clone method.

gdb/ChangeLog:

        * compile/compile-loc2c.c (compute_stack_depth_worker): Add
        new DW_OP_LLVM_piece_end operation support.
        * dwarf2/expr.c (dwarf_composite::m_completed): New data
        member.
        (dwarf_entry::dwarf_entry): New copy constructor.
        (dwarf_location::dwarf_location): New copy constructor.
        (dwarf_value::dwarf_value): New copy constructor.
        (dwarf_undefined::dwarf_undefined): New copy constructor.
        (dwarf_memory::dwarf_memory): New copy constructor.
        (dwarf_register::dwarf_register): New copy constructor.
        (dwarf_implicit::dwarf_implicit): New method.
        (dwarf_implicit_pointer::dwarf_implicit_pointer): New copy
        constructor.
        (dwarf_composite::dwarf_composite): New copy constructor.
        (dwarf_entry::clone): New method.
        (dwarf_location::clone): New method.
        (dwarf_value::clone): New method.
        (dwarf_undefined::clone): New method.
        (dwarf_memory::clone): New method.
        (dwarf_register::clone): New method.
        (dwarf_implicit::clone): New method.
        (dwarf_implicit_pointer::clone): New method.
        (dwarf_composite::clone): New method.
        (dwarf_composite::is_completed): New method.
        (dwarf_composite::set_completed): New method.
        (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.
2021-11-05 11:48:16 +00:00
Zoran Zaric
63ec59357c Add support for DW_OP_LLVM_undefined operation
For the DW_OP_piece and DW_OP_bit_piece operations, in the DWARF 5
standard, it is stated that if the location description (of that piece)
is empty, then the piece is describing an undefined location
description.

The act of allowing any location description to be placed on a DWARF
stack means that now a new operations can be defined which could pop
more then one location description from a DWARF stack.

This means that the old rule is not really applicable any more and a
new operation that explicitly pushes an undefined location description
on the DWARF stack is needed.

This new rule however is fully backward compatibility as described
in the document found on:

https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html

Under the new definitions for the DW_OP_piece and DW_OP_bit_piece
operations.

gdb/ChangeLog:

	* compile/compile-loc2c.c (compute_stack_depth_worker): Add
	support for new DW_OP_LLVM_undefined operations.
	* dwarf2/expr.c (dwarf_expr_context::execute_stack_op): Add
	support for new DW_OP_LLVM_undefined operations.
        * dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new
        DW_OP_LLVM_undefined operation support.

include/ChangeLog:

	* dwarf2.def (DW_OP): New DW_OP_LLVM_undefined operations
	enumeration.

gdb/testsuite/ChangeLog:

	* gdb.dwarf2/dw2-llvm-undefined.exp: New test.
2021-11-05 11:48:16 +00:00
Zoran Zaric
0dec3e5ba2 Add DWARF operations for byte and bit offset
Currently in DWARF, there are only two ways to specify an offset for a
location description.

For a memory location description, the location description can be
first converted to a DWARF value, after which an arithmetic operation
can be applied to it. This however, only works while there are no
address spaces involved, that are not mapped to a general address space
(CORE_ADDR). Another limitation is that there is no way to specify a
bit offset to that location description.

Second way of specifying an offset to a location description is more
universal and involves wrapping that location description in a
composite piece, where piece itself has a bit/byte offset defined. The
problem with this approach is that both DW_OP_piece and DW_OP_bit_piece
define an offset as a DWARF operation operand, which means that an
offset needs to be a constant value encoded into the DWARF expression.

By adding three new operations (DW_OP_LLVM_offset,
DW_OP_LLVM_offset_constu and DW_OP_LLVM_bit_offset) these restrictions
are now lifted.

Detailed descriptions of these new operations can be found here:

https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html

The same document also explores an idea of extending the
DW_OP_push_object_address operation to allow pushing any location
description on the DWARF stack. This together with the new bit/byte
offset operations, generalizes DWARF to work with bit fields and could
replace the odd passed-in buffer mechanics in a more elegant way.

There seem to be a difference in views on what the big endian machine
register byte ordering should be. On one hand, some would expect for
a register to behave in the same way as memory, but on another, there
seems to be an existing implementation for (IBM big endian based
machines) which seems to be viewing registers differently, depending
if the register location description is part of a composite piece or
not. More on this topic can be found here:

https://sourceware.org/legacy-ml/gdb-patches/2017-04/msg00177.html

Unfortunately, the gdb current implementation favors the second option,
which feels like a target specific implementation.

Because of this, I've decided to not favor a specific implementation
in the added test for new DWARF operations (dw2-llvm-offset.exp), so
the test is restricted to only run on little endian platforms.

gdb/ChangeLog:

	* ada-lang.c (coerce_unspec_val_to_type): Add source bit offset
	argument to the value_contents_copy call.
	* compile/compile-loc2c.c (compute_stack_depth_worker): Add new
	DWARF operations support.
	* dwarf2/expr.c (dwarf_register::to_gdb_value): Add bit offset
	support.
        (dwarf_register::to_gdb_value): Add bit offset support.
	(dwarf_register::to_gdb_value): Add source bit
	offset argument to the value_contents_copy call.
	(dwarf_expr_context::execute_stack_op): Add new DWARF
	operations support.
        * dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new DWARF
        operation support.
        (disassemble_dwarf_expression): Add support for new
        DW_OP_LLVM_offset_constu operation.
	* findvar.c (read_frame_register_value): Add source bit offset
	argument to the value_contents_copy call.
        * frame.c (get_frame_register_bytes): Takes into account a
        potential unwound register struct value offset.
        (get_frame_register_bytes): Takes into account a potential
        unwound register struct value offset.
	* valops.c (read_value_memory): Add bit offset support.
	(value_assign): Add bit offset support.
	(value_repeat): Add bit offset support.
	(value_array): Add source bit offset argument to the
	value_contents_copy call.
	(value_slice): Add source bit offset argument to the
	value_contents_copy call.
	* value.c (value_contents_copy_raw): Add source bit offset
	support.
	(value_contents_copy): Add source bit offset argument to
	value_contents_copy_raw call.
	(value_primitive_field): Add source bit offset argument to the
	value_contents_copy call.
	(value_from_component): Add source bit offset argument to the
	value_contents_copy call.
	(value_fetch_lazy_memory): Add bit offset argument to the
	read_value_memory call.
	(value_fetch_lazy_register): Add source bit offset argument to
	the value_contents_copy call.
	* value.h (value_contents_copy): Add source bit offset
	argument.

include/ChangeLog:

	* dwarf2.def (DW_OP_DUP): New DWARF operations enumeration.

gdb/testsuite/ChangeLog:

	* lib/dwarf.exp: Add support for new DW_OP_LLVM_offset_constu
	DWARF operation.
	* gdb.dwarf2/dw2-llvm-offset.exp: New test.
2021-11-05 11:48:16 +00:00
Zoran Zaric
edb4cff0d8 Add support for any location description in CFI
One of the main benefits of allowing location description to be on the
DWARF stack is that now CFI expression based register rules can be
defined using a location description operations. This allows a register
of one frame to be saved in any location, including any composite
location.

To fully support this feature, the execute_stack_op function in
dwarf2/frame.c needs to return a single struct value object instead of
just an address.

Function put_frame_register_bytes also needs to change to support any
location description.

This support is a one of the key features to truly support optimized
code.

gdb/ChangeLog:

	* dwarf2/frame.c (execute_stack_op): Change to return a struct
	value object.
	(dwarf2_frame_cache): Change to call new execute_stack_op
	definition.
	(dwarf2_frame_prev_register): Change to call new execute_stack_op
	definition.
	* frame.c (put_frame_register_bytes): Add support for writing to
	composite location description.
2021-11-05 11:46:38 +00:00
Zoran Zaric
087ced679c Remove DWARF expression composition check
The dwarf_expr_require_composition function reports an error if the
last operation is not a leaf node of the DWARF expression. This was
previously used to prevent location description operations to be used
freely in the DWARF expression.

With the new approach, all operations are treated the same and
everything is composable, so there is no need for the previous
restrictions in the expression evaluator.

gdb/ChangeLog:

	* dwarf2/expr.c (dwarf_expr_context::execute_stack_op): Remove
	the use of dwarf_expr_require_composition.
2021-11-05 11:46:38 +00:00
Zoran Zaric
c99af81b30 Add frame info check to DW_OP_reg operations
After enabling location description to be on a DWARF stack, it is now
needed to check the frame context information validity when creating a
register location description.

gdb/ChangeLog:

	* dwarf2/expr.c (dwarf_expr_context::execute_stack_op): Add
	check_frame_info call for DW_OP_reg operations.
2021-11-05 11:46:38 +00:00
Zoran Zaric
a572357c56 Move read_addr_from_reg function to frame.c
read_addr_from_reg function is now only called from frame.c file, this
means that the function can safely be moved there.

gdb/ChangeLog:

	* dwarf2/expr.c (read_addr_from_reg): Move function to frame.c.
	* dwarf2/expr.h (read_addr_from_reg): Remove function.
	* dwarf2/frame.c (read_addr_from_reg): Add function from
	expr.c.
2021-11-05 11:46:38 +00:00
Zoran Zaric
54ecae43a3 Remove dwarf_expr_context from expr.h interface
After the switch to the new evaluator implementation, it is now
possible to completely remove the dwarf_expr_context class from the
expr.h interface and encapsulate it inside the expr.c file.

The new interface consists of a new function called dwarf2_evaluate
that takes a DWARF expression stream, initial DWARF stack elements (in
a form of a vector of a struct value objects), evaluation context and
expected result type information. Function returns an evaluation result
in a form of a struct value object.

Currently, there is ever only one initial stack element provided to the
evaluator and that element is always a memory address, so having a
vector of struct value object might seems like an overkill.

In reality this new flexibility allows implementation of a new DWARF
attribute extensions that could provide any number of initial stack
elements to describe any location description or value.

gdb/ChangeLog:

	* dwarf2/expr.c (dwarf2_evaluate): New function.
	(struct dwarf_expr_context): Move from expr.h.
        (class dwarf_entry): Move from expr.h
	(dwarf_expr_context::push_address): Remove function.
	* dwarf2/expr.h (struct dwarf_expr_context): Move to expr.c.
        (class dwarf_entry): Move to expr.c.
        (address_type): Expose function.
	* dwarf2/frame.c (execute_stack_op): Now calls dwarf2_evaluate.
	* dwarf2/loc.c (dwarf2_evaluate_loc_desc_full): Now calls
	dwarf2_evaluate.
	(dwarf2_locexpr_baton_eval): Now calls dwarf2_evaluate.
2021-11-05 11:46:38 +00:00
Zoran Zaric
0b63131f07 Comments cleanup between expr.h and expr.c
This is just a cosmetic cleanup of the expr.h and expr.c documentation.

gdb/ChangeLog:

        * dwarf2/expr.c: Comments cleanup.
        * dwarf2/expr.h: Comments cleanup.
2021-11-05 11:46:38 +00:00
Zoran Zaric
416088cccd Remove old computed struct value callbacks
After changing the DWARF stack to use the new DWARF entry based
classes, the previous computed struct value callback
infrastructure is not used anymore and can be removed.

gdb/ChangeLog:

        * dwarf2/expr.c (struct piece_closure): Remove structure.
        (rw_pieced_value): Remove unused function.
        (read_pieced_value): Remove unused function.
        (write_pieced_value): Remove unused function.
        (check_pieced_synthetic_pointer): Remove unused function.
        (indirect_pieced_value): Remove unused function.
        (coerce_pieced_ref): Remove unused function.
        (copy_pieced_value_closure): Remove unused function.
        (free_pieced_value_closure): Remove unused function.
        * dwarf2/expr.h (class dwarf_entry): New declaration.
        (struct dwarf_expr_piece): Remove structure.
        (enum dwarf_value_location): Remove enumeration.
2021-11-05 11:46:38 +00:00
Zoran Zaric
d9ff45713c Change DWARF stack to use new dwarf_entry classes
To replace existing DWARF stack element (dwarf_stack_value) with
dwarf_entry class based objects, a support for conversion between
struct value and the new classes is needed. The reason for this is
that dwarf_entry based classes are not designed to be visible outside
the expr.c file. This makes the DWARF expression evaluator more self
contained. This can be beneficial if there is ever a need to have a
DWARF support in gdbserver.

In the previous patch the conversion between the DWARF entry classes to
the struct value has been already added in a form of a to_gdb_value
method.

The interface that is still missing is to convert from struct value to
the DWARF entry classes. New static function gdb_value_to_dwarf_entry
has been added for this purpose.

We also need a way to perform DWARF arithmetic and logical operations
on DWARF values and for this a new set of static functions
(dwarf_value_X) has been provided.

Currently the existing struct value operations are used under the
hood of these functions to avoid the code duplication. Vector types
are planned to be promoted to base types in the future anyway which
means that the operations subset needed is just going to grow.

Also, dwarf_entry class declaration had to be temporarily moved to the
expr.h file so that unique_ptr wrapper type could be used in some
dwarf_expr_context method declaration and will be moved back to the
expr.c file in one of the next patches.

Now, everything is ready so that the DWARF stack element can easily be
swapped out.

It is worth mentioning that a few tests under gdb/testsuite/gdb.dwarf2/
folder, also had to be changed to reflect the design change which
effected an edge case error message text. Tests that had to be changed
slightly are: dw2-param-error.exp, dw2-stack-boundary.exp and
dw2_op_call.exp. The reason for this is that they all contained a
DWARF expression that once evaluated resulted in a stack underflow
error reported by a fetch method, but with the switch to the new stack
element type and a bit different stack algorithm, the message can no
longer be reported by that method, but by a stack pop method instead.

gdb/ChangeLog:

        * dwarf2/expr.c (gdb_value_to_dwarf_entry): New function.
        (to_location): New function.
        (to_value): New function.
        (dwarf_value_cast_op): New function.
        (dwarf_value_complement_op): New function.
        (dwarf_value_negation_op): New function.
        (dwarf_value_binary_op): New function.
        (dwarf_value_less_op): New function.
        (dwarf_value_equal_op): New function.
        (allocate_piece_closure): Remove unused function.
        (dwarf_expr_context::push): Change to use dwarf_entry based
        classes.
        (dwarf_expr_context::push_address): Change to use dwarf_entry
        based classes.
        (dwarf_expr_context::fetch): Change to use dwarf_entry based
        classes.
        (dwarf_expr_context::read_mem): Remove method.
        (dwarf_expr_context::fetch_result): Change to use dwarf_entry
        based classes.
        (dwarf_expr_context::fetch_address): Change to use dwarf_entry
        based classes.
        (dwarf_expr_context::fetch_in_stack_memory): Remove method.
        (dwarf_expr_context::add_piece): Change to use dwarf_entry based
        classes.
        (dwarf_expr_context::execute_stack_op): Change to use dwarf_entry
        based classes.
        (dwarf_location::clone): New method.
        (dwarf_value::clone): New method.
        * dwarf2/expr.h (class dwarf_entry): New declaration.
        (struct dwarf_stack_value): Remove structure.
        (struct dwarf_expr_context): Change to use dwarf_entry based.
        (dwarf_entry::clone): New method.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-param-error.exp: Error message text change.
        * gdb.dwarf2/dw2-stack-boundry.exp: Error message text change.
        * gdb.dwarf2/dw2-op-call.exp Error message text change.
2021-11-05 11:46:38 +00:00
Zoran Zaric
957fb3d805 Add to_gdb_value method to DWARF entry class
The result of the DWARF expression evaluation is expected to be in a
format of a struct value object. This means that a new to_gdb_value
method is needed for both dwarf_location and dwarf_value classes.

In the case of the dwarf_value class, the conversion between that
class and struct value can happen often, this is why it is usefull to
cache once created struct value object in a dwarf_value
m_gdb_value member to reduce the number of conversions needed.
However, this also means that the to_gdb_value method cant be declared
as a constant method.

In the case of classes that derive from dwarf_location class, there is
now a need for a cloning method because the encapsulating
computed_closure class has a life span separated from the expression
evaluator.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_entry::to_gdb_value): New method.
        (dwarf_location::to_gdb_value): New method.
        (dwarf_location::clone_location): New method.
        (dwarf_value::m_gdb_value): New member.
        (dwarf_value::to_gdb_value): New method.
        (dwarf_undefined::to_gdb_value): New method.
        (dwarf_undefined::clone_location): New method.
        (dwarf_memory::to_gdb_value): New method.
        (dwarf_memory::clone_location): New method.
        (dwarf_register::to_gdb_value): New method.
        (dwarf_register::clone_location): New method.
        (dwarf_implicit::to_gdb_value): New method.
        (dwarf_implicit::clone_location): New method.
        (dwarf_implicit_pointer::to_gdb_value): New method.
        (dwarf_implicit_pointer::clone_location): New method.
        (dwarf_composite::to_gdb_value): New method.
        (dwarf_composite::clone_location): New method.
2021-11-05 11:46:38 +00:00
Zoran Zaric
f5f70c00d8 Add new computed struct value callback interface
At this point all support is there to add a new callback interface
for the computed struct value infrastructure.

Original callback interface (piece closure) is going to be removed as
soon as the switch to the new DWARF entry classes is done in the next
few patches.

gdb/ChangeLog:

        * dwarf2/expr.c (class computed_closure): New class.
        (closure_value_funcs): New closure callback structure.
        (copy_value_closure): New function.
        (free_value_closure): New function.
        (rw_closure_value): New function.
        (check_synthetic_pointer): New function.
        (write_closure_value): New function.
        (read_closure_value): New function.
        (is_optimized_out_closure_value): New function.
        (indirect_closure_value): New function.
        (coerce_closure_ref): New function.
2021-11-05 11:46:38 +00:00
Zoran Zaric
8b08c52759 Add is_optimized_out to dwarf_location class
Similarly to the is_implicit_ptr_at method, the existing function
callback interface of the computed struct value, requiers a way to
check if the underlying location description describes any part as
optimized out.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::is_optimized_out):
        New method.
        (dwarf_implicit::is_optimized_out): New method.
        (dwarf_register::is_optimized_out): New method.
        (dwarf_composite::is_optimized_out): New method.
2021-11-05 11:46:38 +00:00
Zoran Zaric
f10d92ca88 Add indirect_implicit_ptr to dwarf_location class
Similarly to the is_implicit_ptr_at method, the existing function
callback interface of the computed struct value, requiers a way to
apply indirection to an implicit pointer on a given offset of a given
length of an underlying location description.

This is different than reading from a struct value object (previously
described write_to_gdb_value method) in a way that the result of this
operation is expected to be a struct value of a pointed source level
variable instead of reading the value of that variable.

In the same way this is also different operation than the deref method
because the deref returns a read value of a given type from that
location description.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::indirect_implicit_ptr):
        New method.
        (dwarf_implicit_pointer::indirect_implicit_ptr): New method.
        (dwarf_composite::indirect_implicit_ptr): New method.
2021-11-05 11:46:38 +00:00
Zoran Zaric
9ccbaf1956 Add is_implicit_ptr_at method to dwarf_location
Another expectation of the existing function callback interface of the
computed struct value is to check if a specific part (on a given offset
of a given length) of an underlying location description is an implicit
pointer location description.

To satisfy this expectation a new is_implicit_ptr_at has been added.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::is_implicit_ptr_at):
        New method.
        (dwarf_implicit_pointer::is_implicit_ptr_at): New method.
        (dwarf_composite::is_implicit_ptr_at): New method.
2021-11-05 11:46:38 +00:00
Zoran Zaric
7bd280514c Add write_to_gdb_value method to dwarf_location
Similar story behind the previous read_from_gdb_value method applies
to the new write_to_gdb_value.

In the same way, reading the data from a location described and writing
that data to a struct value object, can be different from just generic
read the data from a buffer (location description read method).

To make this distinction clear, a new write_to_gdb_value method is
added to classes that derive from location description class.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::write_to_gdb_value):
        New method.
        (dwarf_composite::write_to_gdb_value): New method.
2021-11-05 11:46:38 +00:00
Zoran Zaric
47fc8df2f8 Add read_from_gdb_value method to dwarf_location
The few patches are addressing the expectations of the existing
function calback interface of the computed struct value objects.

As mentioned in the previous patches the location description and the
interaction with that location are opaque to the struct value object,
but currently that interaction is influenced by the data contained
inside of that object and outside of the location description class.

Also, the struct value evaluation involves more then just writing or
reading the object contents buffer, in certain cases it is also
expected to throw an exception or mark different parts of the object
with additional information (optimized out bitmap for example).

As a result, reading the data from a struct value object and writing
that data into the location described, can be different then just
generic writing the data from a buffer (dwarf_location write method).

To make this distinction clear a new read_from_gdb_value method is
added to classes that derive from location description class.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::read_from_gdb_value):
        New method.
        (dwarf_composite::read_from_gdb_value): New method.
2021-11-05 11:46:38 +00:00
Zoran Zaric
710e538fc4 Add deref method to location description classes
Concept of reading from a location seems to be too low level for the
DWARF standard. What the standard actually describes is a concept of
dereferencing, where the type of the operation result can be
specified in advance.

This can be seen in the definition of the DW_OP_derefX family of
expression operations, but it is also happening implicitly in the case
of DW_OP_fbreg, DW_OP_regval_type and DW_OP_bregX family of operations.

Currently, the DW_OP_derefX operations will take the value from the
DWARF expression stack and implicitly convert it to a memory location
description (in reality treat it as a memory address for a given
target) and apply the dereference operation to it. When we allow any
location description on a DWARF expression stack, these operations need
to work in the same way.

The conclusion here is that we need a universal method that models the
dereference operation for any class derived from a location description
class.

It is worth mentioning that because of how the passed in buffers are
currently being implemented, we needed a specialisation for the deref
method of the dwarf_memory class to support them.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::deref): New method.
        (dwarf_memory::deref): New method.
2021-11-05 11:46:38 +00:00
Zoran Zaric
b71ff12cf7 Add write method to location description classes
After adding the interface for reading from the location, it also
makes sense to add the interface for writing.

To be clear, DWARF standard doesn't have a concept of writting to a
location, but because of the way how callback functions are used to
interact with the opaque implementation of the computed struct value
objects, the choice was to either use the existing DWARF entry classes
or to invent another way of representing the complexity behind those
computed objects.

Adding a write method seems to be a simpler option of the two.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::write): New method.
        (dwarf_undefined::write): New method.
        (dwarf_memory::write): New method.
        (dwarf_register::write): New method.
        (dwarf_implicit::write): New method.
        (dwarf_implicit_pointer::write): New method.
        (dwarf_composite::write): New method.
2021-11-05 11:46:38 +00:00
Zoran Zaric
c4296c3e41 Add read method to location description classes
After adding the interface for register and memory location access, a
new method for reading from any location derived from a dwarf_location
class, can now be defined.

In the case of implicit pointer location description the existing
indirect_synthetic_pointer interface requiers a type of the pointer
to be specified, so for a generic read interface the only type that
makes sense is the DWARF generic type. This means that the existing
address_type method of a dwarf_expr_context class needs to be exposed
outside of that class.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::read): New method.
        (dwarf_undefined::read): New method.
        (dwarf_memory::read): New method.
        (dwarf_register::read): New method.
        (dwarf_implicit::read): New method.
        (dwarf_implicit_pointer::read): New method.
        (dwarf_composite::read): New method.
        (dwarf_expr_context::address_type): Change to use the new
        address_type function.
        (address_type): New function.
2021-11-05 11:46:38 +00:00
Zoran Zaric
b650f7fd86 Add to_value method to dwarf_location class
Following the idea from the last patch this patch is adding a
conversion method from any dwarf_location derived object into
a dwarf_value object.

Currently, we only know how to convert from a memory location
description into a value, but it is resonable to expect a set
of target hooks that would let the target decide on how to do
other conversions in the future.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::to_value): New method.
        (dwarf_memory::to_value): New method.
        (ill_formed_expression): New function.
2021-11-05 11:46:38 +00:00
Zoran Zaric
851fa76da8 Add to_location method to dwarf_value class
DWARF standard already contains an implicit conversion between location
description and a DWARF value. In the DWARF 5 version, one place
where this can happen is at the very end of the evaluation where a
client decides if the result is expected to be in a form of a value or
a location description (as_lval argument of the new evaluation method).

By allowing any location description to be on the DWARF stack, these
implicit conversions are expected on per operation basis which means
that the new dwarf_value class need to have a support for it.

This patch adds a conversion method from a dwarf_value object into a
location description object.

To support the conversion method we also need an implementation of the
C++14 standard library function make_unique which was copied from the
standard library implementation.

gdb/ChangeLog:

        * dwarf2/expr.c (class dwarf_value::to_location): New method.

gdbsupport/ChangeLog:

        * common-utils.h (make_unique): New function.
2021-11-05 11:46:38 +00:00
Zoran Zaric
0dd1a71b4d Add new classes that model DWARF stack element
The rest of the patch series addresses the issues described in a
"Motivation" section of the AMD's DWARF standard extensions that
can be found at:

https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html

The document describes a couple of main issues found when using the
current DWARF 5 version to describe optimized code for SIMD and SIMT
architectures.

Without going much into details described in the document, the main
point is that DWARF version 5 does not allow a proper support for
address spaces and it does not allow a location description to be used
anywhere in the DWARF expression, instead a location description can
using a result left on the DWARF stack (after the evaluation of that
expression) to describe the location.

Both issues can be solved in a clean way by introducing a new set of
classes that describe all entry types which can be placed on a DWARF
stack, while keeping most of backward compatibility with the previous
standard version. These entry types can now be either a typed value
or any location description.

Known edge case where placing a location description on the DWARF stack
is not fully backward compatible with DWARF version 5 is in the case of
DW_OP_call operations, where the current standard only defines that an
expression stack is shared between the caller and the callee, but there
it is unknown what happens with the resuling location description after
the evaluation of the callee's location description expression.

Considering that this edge case is not defined in the standard, it
would be very unusual and dangerous for any compiler to use it in their
own way and in the existing testsuite, there is no indication of that.

Currently, the result of an expression evaluation is kept in a separate
data structure, while with the new approach, it will be always found as
a top element of the DWARF stack.

Question here is, why do we need a new set of classes and why not just
use the struct value instead?

As it stands, there are couple of issues with using the struct value to
describe a DWARF stack element:

 - It is not designed to represent a DWARF location description
specifically, instead it behaves more like unified debug information
format that represents an actual target resource. One example of this
is accessing data of a struct value register location description,
where if the amount of data accessed is larger then the register,
results in accessing more then one register. In DWARF this is not a
valid behavior and locations that span more then one register should be
described as a composite location description.

- There is a tight coupling between struct value and it's type
information, regardless if the data represented is describing a value
(not_lval) or a location description. While the type information
dictates how the data is accessed for a struct value case, in DWARF,
location description doesn't have a type so data access is not bound by
it.

- DWARF values only support much simpler base types, while struct value
can be linked to any type. Admittedly, new classes are still using the
same struct value infrastructure for a value based operations at the
moment, but that is planned to change in the near future.

- struct value register location description requires a frame id
information which makes them unsuitable for CFA expression evaluation.

So, there seems to be a lack of separation of concerns in the design
of a struct value infrastructure, while the new classes are handling
one specific purpose and are completely encapsulated in the expr.c.

Additional benefit of this design is that it makes a step in a
right direction for being able to evaluate DWARF expressions on a
gdbserver side in the near future, which sounds like a desirable thing.

It is also worth mentioning that this new location description
representation is based on a bit granularity (the bit_suboffset class
member) even though the DWARF standard has a very limited support for
it (mostly used for DW_OP_bit_piece operation).

By allowing any location description to define a bit sub-offset of the
location, we are able to give more options for supporting of new
concepts (like the existing packed arrays in Ada language).

In this patch, a new set of classes that describe a DWARF stack element
are added. The new classes are:

- Value - describes a numerical value with a DWARF base type.
- Location description - describes a DWARF location description.
  - Undefined location - describes a location that is not defined.
  - Memory location - describes a location in memory.
  - Register location - describes a register location in a frame
    context.
  - Implicit location - describes a location that implicitly holds a
    value that it describes.
  - Implicit pointer - describes a concept of an implicit pointer to
    a source variable.
  - Composite location - describes a location that is composed from
    pieces of other location descriptions.

For now, these classes are just defined, and they are planned to be
used by the following patches.

gdb/ChangeLog:

	* dwarf2/expr.c (class dwarf_entry): New class.
	(class dwarf_value): New class.
	(class dwarf_location): New class.
	(class dwarf_undefined): New class.
	(class dwarf_memory): New class.
	(class dwarf_register): New class.
	(class dwarf_implicit): New class.
	(class dwarf_implicit_pointer): New class.
	(class dwarf_composite): New class.
	* value.c (pack_unsigned_long): Expose function.
	* value.h (pack_unsigned_long): Expose function.
2021-11-05 11:46:38 +00:00
Zoran Zaric
8b1bcaf79c Add new memory access interface to expr.c
DWARF expression evaluator is currently using a few different
interfaces for memory access: write_memory_with_notification,
read_value_memory, read_memory.

They all seem incosistent, while some of them even need a struct
value typed argument to be present.

This patch is simplifying that interface by replacing it with two new
low level functions: read_from_memory and write_to_memory.

The advantage of this new interface is that it behaves in the same way
as the register access interface from the previous patch. Both of these
have the same error returning policy, which will be usefull for the
following patches.

	* dwarf2/expr.c (xfer_memory):  New function.
	(read_from_memory): New function.
	(write_to_memory): New function.
	(rw_pieced_value): Now calls the read_from_memory and
	write_to_memory functions.
2021-11-05 11:29:37 +00:00
Zoran Zaric
de004eec8e Add new register access interface to expr.c
DWARF expression evaluator is currently using get_frame_register_bytes
and put_frame_register_bytes interface for register access.

The problem with evaluator using this interface is that it allows a
bleed out register access. This means that if the caller specifies a
larger amount of data then the size of a specified register, the
operation will continue accessing the neighboring registers until a
full amount of data has been reached.

DWARF specification does not define this behavior, so a new simplified
register access interface is needed instead.

	* dwarf2/expr.c (read_from_register): New function.
	(write_to_register): New function.
	(rw_pieced_value): Now calls the read_from_register and
	write_to_register functions.
2021-11-05 11:29:37 +00:00
25 changed files with 4998 additions and 1523 deletions

View File

@@ -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));

View File

@@ -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;

File diff suppressed because it is too large Load Diff

View File

@@ -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);

View File

@@ -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

View File

@@ -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");

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View 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"

View 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"

View 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;
}

View 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"

View 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"

View 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"

View 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"

View File

@@ -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}

View File

@@ -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\)}

View File

@@ -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"

View File

@@ -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"

View File

@@ -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));
}

View File

@@ -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)
{

View File

@@ -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);

View File

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

View File

@@ -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)