This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 1/3] Add support for DW_OP_GNU_variable_value
- From: Kevin Buettner <kevinb at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Thu, 2 Aug 2018 21:17:54 -0700
- Subject: [PATCH 1/3] Add support for DW_OP_GNU_variable_value
- References: <20180802210405.5c04ca7a@pinnacle.lan>
This patch adds support for DW_OP_GNU_variable_value to GDB.
Jakub Jelinek provides a fairly expansive discussion of this DWARF
expression opcode in his GCC patch...
https://gcc.gnu.org/ml/gcc-patches/2017-02/msg01499.html
It has also been proposed for addition to the DWARF Standard:
http://www.dwarfstd.org/ShowIssue.php?issue=161109.2
If compiled with a suitable version of GCC, the test case associated
with GCC Bug 77589 uses DW_OP_GNU_variable_value in a DW_AT_byte_stride
expression. Here's a link to the bug:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77589
This is what the DWARF looks like. Look at the last line, which has
the DW_AT_byte_stride expression:
<2><e1>: Abbrev Number: 12 (DW_TAG_variable)
<e2> DW_AT_name : (indirect string, offset: 0x115): span.0
<e6> DW_AT_type : <0x2e>
<ea> DW_AT_artificial : 1
<ea> DW_AT_location : 3 byte block: 91 b0 7f (DW_OP_fbreg: -80)
...
<2><178>: Abbrev Number: 18 (DW_TAG_subrange_type)
<179> DW_AT_lower_bound : 4 byte block: 97 23 20 6 (DW_OP_push_object_address; DW_OP_plus_uconst: 32; DW_OP_deref)
<17e> DW_AT_upper_bound : 4 byte block: 97 23 28 6 (DW_OP_push_object_address; DW_OP_plus_uconst: 40; DW_OP_deref)
<183> DW_AT_byte_stride : 10 byte block: 97 23 18 6 fd e1 0 0 0 1e (DW_OP_push_object_address; DW_OP_plus_uconst: 24; DW_OP_deref; DW_OP_GNU_variable_value: <0xe1>; DW_OP_mul)
A patch to readelf, which I'm also submitting, is required to do this
decoding.
I found that GDB gave me the correct answer for "p c40pt(2)" once I
(correctly) implemented DW_OP_GNU_variable_value.
I also have test case (later in this series) which uses the DWARF
assembler and, therefore, does not rely on having a compiler with this
support.
gdb/ChangeLog:
* dwarf2expr.h (struct dwarf_expr_context): Add virtual method
dwarf_variable_value.
* dwarf2-frame.c (class dwarf_expr_executor):
Add override for dwarf_variable_value.
* dwarf2loc.c (class dwarf_evaluate_loc_desc): Likewise.
(class symbol_needs_eval_context): Likewise.
(indirect_synthetic_pointer): Add forward declaration.
(sect_variable_value): New function.
(dwarf2_compile_expr_to_ax): Add case for DW_OP_GNU_variable_value.
* dwarf2expr.c (dwarf_expr_context::execute_stack_op): Add case
for DW_OP_GNU_variable_value.
---
gdb/dwarf2-frame.c | 5 +++++
gdb/dwarf2expr.c | 11 +++++++++++
gdb/dwarf2expr.h | 3 +++
gdb/dwarf2loc.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 63 insertions(+)
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index 58f1ba4..f7dc820 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -284,6 +284,11 @@ class dwarf_expr_executor : public dwarf_expr_context
invalid ("DW_OP_call*");
}
+ struct value *dwarf_variable_value (sect_offset sect_off) override
+ {
+ invalid ("DW_OP_GNU_variable_value");
+ }
+
CORE_ADDR get_addr_index (unsigned int index) override
{
invalid ("DW_OP_GNU_addr_index");
diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c
index 445f857..f1ca033 100644
--- a/gdb/dwarf2expr.c
+++ b/gdb/dwarf2expr.c
@@ -1259,6 +1259,17 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
this->dwarf_call (cu_off);
}
goto no_push;
+
+ case DW_OP_GNU_variable_value:
+ {
+ sect_offset sect_off
+ = (sect_offset) extract_unsigned_integer (op_ptr,
+ this->ref_addr_size,
+ byte_order);
+ op_ptr += this->ref_addr_size;
+ result_val = this->dwarf_variable_value (sect_off);
+ }
+ break;
case DW_OP_entry_value:
case DW_OP_GNU_entry_value:
diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h
index c746bfe..c702a19 100644
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -221,6 +221,9 @@ struct dwarf_expr_context
subroutine. */
virtual void dwarf_call (cu_offset die_cu_off) = 0;
+ /* Execute "variable value" operation on DIED at SECT_OFF. */
+ virtual struct value *dwarf_variable_value (sect_offset sect_off) = 0;
+
/* Return the base type given by the indicated DIE at DIE_CU_OFF.
This can throw an exception if the DIE is invalid or does not
represent a base type. SIZE is non-zero if this function should
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index a98b676..5c7c4ba 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -61,6 +61,12 @@ static struct call_site_parameter *dwarf_expr_reg_to_entry_parameter
union call_site_parameter_u kind_u,
struct dwarf2_per_cu_data **per_cu_return);
+static struct value *indirect_synthetic_pointer
+ (sect_offset die, LONGEST byte_offset,
+ struct dwarf2_per_cu_data *per_cu,
+ struct frame_info *frame,
+ struct type *type);
+
/* Until these have formal names, we define these here.
ref: http://gcc.gnu.org/wiki/DebugFission
Each entry in .debug_loc.dwo begins with a byte that describes the entry,
@@ -546,6 +552,25 @@ per_cu_dwarf_call (struct dwarf_expr_context *ctx, cu_offset die_offset,
ctx->eval (block.data, block.size);
}
+struct value *
+sect_variable_value (struct dwarf_expr_context *ctx, sect_offset sect_off,
+ struct dwarf2_per_cu_data *per_cu)
+{
+ struct type *die_type = dwarf2_fetch_die_type_sect_off (sect_off, per_cu);
+
+ if (die_type == NULL)
+ error (_("Bad DW_OP_GNU_variable_value DIE."));
+
+ /* Note: Things still work when the following test is removed. This
+ test and error is here to conform to the proposed specification. */
+ if (!is_scalar_type (die_type) || TYPE_CODE (die_type) == TYPE_CODE_VOID)
+ error (_("Type of DW_OP_GNU_variable_value DIE must be an integer or pointer."));
+
+ struct type *type = lookup_pointer_type (die_type);
+ struct frame_info *frame = get_selected_frame (_("No frame selected."));
+ return indirect_synthetic_pointer (sect_off, 0, per_cu, frame, type);
+}
+
class dwarf_evaluate_loc_desc : public dwarf_expr_context
{
public:
@@ -587,6 +612,14 @@ class dwarf_evaluate_loc_desc : public dwarf_expr_context
per_cu_dwarf_call (this, die_offset, per_cu);
}
+ /* Helper interface of sect_variable_value for
+ dwarf2_evaluate_loc_desc. */
+
+ struct value *dwarf_variable_value (sect_offset sect_off) override
+ {
+ return sect_variable_value (this, sect_off, per_cu);
+ }
+
struct type *get_base_type (cu_offset die_offset, int size) override
{
struct type *result = dwarf2_get_die_type (die_offset, per_cu);
@@ -2815,6 +2848,14 @@ class symbol_needs_eval_context : public dwarf_expr_context
per_cu_dwarf_call (this, die_offset, per_cu);
}
+ /* Helper interface of sect_variable_value for
+ dwarf2_loc_desc_get_symbol_read_needs. */
+
+ struct value *dwarf_variable_value (sect_offset sect_off) override
+ {
+ return sect_variable_value (this, sect_off, per_cu);
+ }
+
/* DW_OP_entry_value accesses require a caller, therefore a
frame. */
@@ -3655,6 +3696,9 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
case DW_OP_call_ref:
unimplemented (op);
+ case DW_OP_GNU_variable_value:
+ unimplemented (op);
+
default:
unimplemented (op);
}