[PATCH] libdw: Add new DWARF5 Dwarf expression operations.

Mark Wielaard mark@klomp.org
Tue Mar 6 18:56:00 GMT 2018


DW_OP_implicit_pointer, DW_OP_entry_value, DW_OP_const_type,
DW_OP_regval_type, DW_OP_deref_type, DW_OP_xderef_type,
DW_OP_convert and OP_reinterpret are implemented like their
pre-DWARF5 GNU variants.

DW_OP_xderef_type is implemented as a (non-CU relative) variant of
DW_OP_deref_type.

DW_OP_addrx and DW_OP_constx are recognized but not interpreted yet.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libdw/ChangeLog                            | 19 +++++++++++++++++++
 libdw/dwarf.h                              | 11 +++++++++++
 libdw/dwarf_getlocation.c                  | 12 +++++++++++-
 libdw/dwarf_getlocation_attr.c             |  5 ++++-
 libdw/dwarf_getlocation_die.c              | 12 +++++++++++-
 libdw/dwarf_getlocation_implicit_pointer.c |  5 +++--
 src/ChangeLog                              |  7 +++++++
 src/readelf.c                              | 25 ++++++++++++++++++++++++-
 tests/ChangeLog                            |  7 +++++++
 tests/varlocs.c                            | 25 +++++++++++++++++++++++--
 10 files changed, 120 insertions(+), 8 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 4c3587b4..f552644d 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,22 @@
+2018-03-06  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf.h: Add DW_OP_implicit_pointer, DW_OP_addrx, DW_OP_constx,
+	DW_OP_entry_value, DW_OP_const_type, DW_OP_regval_type,
+	DW_OP_deref_type, DW_OP_xderef_type, DW_OP_convert and
+	DW_OP_reinterpret.
+	* dwarf_getlocation.c (__libdw_intern_expression): Handle
+	DW_OP_convert, DW_OP_reinterpret, DW_OP_addrx, DW_OP_constx,
+	DW_OP_regval_type, DW_OP_entry_value, DW_OP_implicit_pointer,
+	DW_OP_deref_type, DW_OP_xderef_type and DW_OP_const_type.
+	* dwarf_getlocation_attr.c (dwarf_getlocation_attr): Handle
+	DW_OP_entry_value, DW_OP_const_type and DW_OP_implicit_pointer.
+	* dwarf_getlocation_die.c (dwarf_getlocation_die): Handle
+	DW_OP_implicit_pointer, DW_OP_convert, DW_OP_reinterpret,
+	DW_OP_const_type, DW_OP_regval_type, DW_OP_deref_type and
+	DW_OP_xderef_type.
+	* dwarf_getlocation_implicit_pointer.c
+	(dwarf_getlocation_implicit_pointer): Handle DW_OP_implicit_pointer.
+
 2018-03-01  Mark Wielaard  <mark@klomp.org>
 
 	* dwarf.h: Add DW_AT_GNU_locviews and DW_AT_GNU_entry_view.
diff --git a/libdw/dwarf.h b/libdw/dwarf.h
index d53a30d8..99cc1128 100644
--- a/libdw/dwarf.h
+++ b/libdw/dwarf.h
@@ -567,6 +567,17 @@ enum
     DW_OP_implicit_value = 0x9e, /* DW_FORM_block follows opcode.  */
     DW_OP_stack_value = 0x9f,	 /* No operands, special like DW_OP_piece.  */
 
+    DW_OP_implicit_pointer = 0xa0,
+    DW_OP_addrx = 0xa1,
+    DW_OP_constx = 0xa2,
+    DW_OP_entry_value = 0xa3,
+    DW_OP_const_type = 0xa4,
+    DW_OP_regval_type = 0xa5,
+    DW_OP_deref_type = 0xa6,
+    DW_OP_xderef_type = 0xa7,
+    DW_OP_convert = 0xa8,
+    DW_OP_reinterpret = 0xa9,
+
     /* GNU extensions.  */
     DW_OP_GNU_push_tls_address = 0xe0,
     DW_OP_GNU_uninit = 0xf0,
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index 86a9ae7f..0fcf9502 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -1,5 +1,5 @@
 /* Return location expression list.
-   Copyright (C) 2000-2010, 2013-2015 Red Hat, Inc.
+   Copyright (C) 2000-2010, 2013-2015, 2017 Red Hat, Inc.
    This file is part of elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
 
@@ -452,8 +452,12 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
 	case DW_OP_plus_uconst:
 	case DW_OP_regx:
 	case DW_OP_piece:
+	case DW_OP_convert:
 	case DW_OP_GNU_convert:
+	case DW_OP_reinterpret:
 	case DW_OP_GNU_reinterpret:
+	case DW_OP_addrx:
+	case DW_OP_constx:
 	  get_uleb128 (newloc->number, data, end_data);
 	  break;
 
@@ -471,6 +475,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
 	  break;
 
 	case DW_OP_bit_piece:
+	case DW_OP_regval_type:
 	case DW_OP_GNU_regval_type:
 	  get_uleb128 (newloc->number, data, end_data);
 	  if (unlikely (data >= end_data))
@@ -479,6 +484,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
 	  break;
 
 	case DW_OP_implicit_value:
+	case DW_OP_entry_value:
 	case DW_OP_GNU_entry_value:
 	  /* This cannot be used in a CFI expression.  */
 	  if (unlikely (dbg == NULL))
@@ -492,6 +498,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
 	  data += newloc->number;		/* Skip the block.  */
 	  break;
 
+	case DW_OP_implicit_pointer:
 	case DW_OP_GNU_implicit_pointer:
 	  /* DW_FORM_ref_addr, depends on offset size of CU.  */
 	  if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
@@ -504,13 +511,16 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
 	  get_uleb128 (newloc->number2, data, end_data); /* Byte offset.  */
 	  break;
 
+	case DW_OP_deref_type:
 	case DW_OP_GNU_deref_type:
+	case DW_OP_xderef_type:
 	  if (unlikely (data + 1 >= end_data))
 	    goto invalid;
 	  newloc->number = *data++;
 	  get_uleb128 (newloc->number2, data, end_data);
 	  break;
 
+	case DW_OP_const_type:
 	case DW_OP_GNU_const_type:
 	  {
 	    size_t size;
diff --git a/libdw/dwarf_getlocation_attr.c b/libdw/dwarf_getlocation_attr.c
index e4dd7089..162330f6 100644
--- a/libdw/dwarf_getlocation_attr.c
+++ b/libdw/dwarf_getlocation_attr.c
@@ -1,5 +1,5 @@
 /* Return DWARF attribute associated with a location expression op.
-   Copyright (C) 2013, 2014 Red Hat, Inc.
+   Copyright (C) 2013, 2014, 2017 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -67,6 +67,7 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu
 	result->cu = attr_form_cu (attr);
 	break;
 
+      case DW_OP_entry_value:
       case DW_OP_GNU_entry_value:
 	result->code = DW_AT_location;
 	result->form = DW_FORM_exprloc;
@@ -74,6 +75,7 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu
 	result->cu = attr_form_cu (attr);
 	break;
 
+      case DW_OP_const_type:
       case DW_OP_GNU_const_type:
 	result->code = DW_AT_const_value;
 	result->form = DW_FORM_block1;
@@ -96,6 +98,7 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu
 	}
 	break;
 
+      case DW_OP_implicit_pointer:
       case DW_OP_GNU_implicit_pointer:
       case DW_OP_GNU_variable_value:
 	{
diff --git a/libdw/dwarf_getlocation_die.c b/libdw/dwarf_getlocation_die.c
index a07031ed..00369a9c 100644
--- a/libdw/dwarf_getlocation_die.c
+++ b/libdw/dwarf_getlocation_die.c
@@ -1,5 +1,5 @@
 /* Return DIE associated with a location expression op.
-   Copyright (C) 2013 Red Hat, Inc.
+   Copyright (C) 2013, 2017 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -43,6 +43,7 @@ dwarf_getlocation_die (Dwarf_Attribute *attr, const Dwarf_Op *op,
   Dwarf_Off dieoff;
   switch (op->atom)
     {
+    case DW_OP_implicit_pointer:
     case DW_OP_GNU_implicit_pointer:
     case DW_OP_call_ref:
     case DW_OP_GNU_variable_value:
@@ -50,19 +51,28 @@ dwarf_getlocation_die (Dwarf_Attribute *attr, const Dwarf_Op *op,
       break;
 
     case DW_OP_GNU_parameter_ref:
+    case DW_OP_convert:
     case DW_OP_GNU_convert:
+    case DW_OP_reinterpret:
     case DW_OP_GNU_reinterpret:
+    case DW_OP_const_type:
     case DW_OP_GNU_const_type:
     case DW_OP_call2:
     case DW_OP_call4:
       dieoff = attr->cu->start + op->number;
       break;
 
+    case DW_OP_regval_type:
     case DW_OP_GNU_regval_type:
+    case DW_OP_deref_type:
     case DW_OP_GNU_deref_type:
       dieoff = attr->cu->start + op->number2;
       break;
 
+    case DW_OP_xderef_type:
+      dieoff = op->number2;
+      break;
+
     default:
       __libdw_seterrno (DWARF_E_INVALID_ACCESS);
       return -1;
diff --git a/libdw/dwarf_getlocation_implicit_pointer.c b/libdw/dwarf_getlocation_implicit_pointer.c
index b704c706..0c1cd00a 100644
--- a/libdw/dwarf_getlocation_implicit_pointer.c
+++ b/libdw/dwarf_getlocation_implicit_pointer.c
@@ -1,5 +1,5 @@
 /* Return associated attribute for DW_OP_GNU_implicit_pointer.
-   Copyright (C) 2010 Red Hat, Inc.
+   Copyright (C) 2010, 2017 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -55,7 +55,8 @@ dwarf_getlocation_implicit_pointer (Dwarf_Attribute *attr, const Dwarf_Op *op,
   if (attr == NULL)
     return -1;
 
-  if (unlikely (op->atom != DW_OP_GNU_implicit_pointer))
+  if (unlikely (op->atom != DW_OP_implicit_pointer
+		&& op->atom != DW_OP_GNU_implicit_pointer))
     {
       __libdw_seterrno (DWARF_E_INVALID_ACCESS);
       return -1;
diff --git a/src/ChangeLog b/src/ChangeLog
index 70a2d438..c879712d 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,10 @@
+2018-03-06  Mark Wielaard  <mark@klomp.org>
+
+	* readelf.c (print_ops): Handle DW_OP_addrx, DW_OP_constx,
+	DW_OP_implicit_pointer, DW_OP_entry_value, DW_OP_const_type,
+	DW_OP_regval_type, DW_OP_deref_type, DW_OP_xderef_type,
+	DW_OP_convert, DW_OP_reinterpret.
+
 2018-03-01  Mark Wielaard  <mark@klomp.org>
 
 	* readelf.c (struct listptr): Add attr field.
diff --git a/src/readelf.c b/src/readelf.c
index 098209f0..fcf5e2cd 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -4295,7 +4295,9 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 	case DW_OP_piece:
 	case DW_OP_regx:
 	case DW_OP_plus_uconst:
-	case DW_OP_constu:;
+	case DW_OP_constu:
+	case DW_OP_addrx:
+	case DW_OP_constx:;
 	  const unsigned char *start = data;
 	  uint64_t uleb;
 	  NEED (1);
@@ -4388,6 +4390,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 	  offset += 1 + (data - start);
 	  break;
 
+	case DW_OP_implicit_pointer:
 	case DW_OP_GNU_implicit_pointer:
 	  /* DIE offset operand.  */
 	  start = data;
@@ -4410,6 +4413,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 	  offset += 1 + (data - start);
 	  break;
 
+	case DW_OP_entry_value:
 	case DW_OP_GNU_entry_value:
 	  /* Size plus expression block.  */
 	  start = data;
@@ -4425,6 +4429,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 	  offset += 1 + (data - start);
 	  break;
 
+	case DW_OP_const_type:
 	case DW_OP_GNU_const_type:
 	  /* uleb128 CU relative DW_TAG_base_type DIE offset, 1-byte
 	     unsigned size plus block.  */
@@ -4444,6 +4449,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 	  offset += 1 + (data - start);
 	  break;
 
+	case DW_OP_regval_type:
 	case DW_OP_GNU_regval_type:
 	  /* uleb128 register number, uleb128 CU relative
 	     DW_TAG_base_type DIE offset.  */
@@ -4460,6 +4466,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 	  offset += 1 + (data - start);
 	  break;
 
+	case DW_OP_deref_type:
 	case DW_OP_GNU_deref_type:
 	  /* 1-byte unsigned size of value, uleb128 CU relative
 	     DW_TAG_base_type DIE offset.  */
@@ -4477,7 +4484,23 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 	  offset += 1 + (data - start);
 	  break;
 
+	case DW_OP_xderef_type:
+	  /* 1-byte unsigned size of value, uleb128 base_type DIE offset.  */
+	  start = data;
+	  NEED (1);
+	  usize = *(uint8_t *) data++;
+	  NEED (1);
+	  get_uleb128 (uleb, data, data + len);
+	  printf ("%*s[%4" PRIuMAX "] %s %" PRIu8 " [%6" PRIxMAX "]\n",
+		  indent, "", (uintmax_t) offset,
+		  op_name, usize, uleb);
+	  CONSUME (data - start);
+	  offset += 1 + (data - start);
+	  break;
+
+	case DW_OP_convert:
 	case DW_OP_GNU_convert:
+	case DW_OP_reinterpret:
 	case DW_OP_GNU_reinterpret:
 	  /* uleb128 CU relative offset to DW_TAG_base_type, or zero
 	     for conversion to untyped.  */
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 9a89676a..fea1d17f 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,10 @@
+2018-03-06  Mark Wielaard  <mark@klomp.org>
+
+	* varlocs.c (print_expr): Handle DW_OP_implicit_pointer,
+	DW_OP_entry_value, DW_OP_convert, DW_OP_reinterpret,
+	DW_OP_regval_type, DW_OP_deref_type, DW_OP_xderef_type and
+	DW_OP_const_type.
+
 2018-02-16  Mark Wielaard  <mark@klomp.org>
 
 	* backtrace-subr.sh (check_native_core): Check if there is any core,
diff --git a/tests/varlocs.c b/tests/varlocs.c
index 0e432296..b2ceda2e 100644
--- a/tests/varlocs.c
+++ b/tests/varlocs.c
@@ -1,5 +1,5 @@
 /* Test program for dwarf location functions.
-   Copyright (C) 2013, 2015 Red Hat, Inc.
+   Copyright (C) 2013, 2015, 2017 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -411,6 +411,7 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
       }
       break;
 
+    case DW_OP_implicit_pointer:
     case DW_OP_GNU_implicit_pointer:
       /* Special, DIE offset, signed offset. Referenced DIE has a
 	 location or const_value attribute. */
@@ -504,6 +505,7 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
       }
       break;
 
+    case DW_OP_entry_value:
     case DW_OP_GNU_entry_value:
       /* Special, unsigned size plus expression block. All registers
 	 inside the block should be interpreted as they had on
@@ -546,7 +548,9 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
       }
       break;
 
+    case DW_OP_convert:
     case DW_OP_GNU_convert:
+    case DW_OP_reinterpret:
     case DW_OP_GNU_reinterpret:
       /* Special, unsigned CU relative DIE offset pointing to a
 	 DW_TAG_base_type. Pops a value, converts or reinterprets the
@@ -571,6 +575,7 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
       }
       break;
 
+    case DW_OP_regval_type:
     case DW_OP_GNU_regval_type:
       /* Special, unsigned register number plus unsigned CU relative
          DIE offset pointing to a DW_TAG_base_type. */
@@ -586,9 +591,10 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
       }
       break;
 
+    case DW_OP_deref_type:
     case DW_OP_GNU_deref_type:
       /* Special, unsigned size plus unsigned CU relative DIE offset
-	 pointing to a DW_TAG_base_type. */ 
+	 pointing to a DW_TAG_base_type. */
       {
 	Dwarf_Die type;
 	if (dwarf_getlocation_die (attr, expr, &type) != 0)
@@ -601,6 +607,21 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
       }
       break;
 
+    case DW_OP_xderef_type:
+      /* Special, unsigned size plus unsigned DIE offset
+	 pointing to a DW_TAG_base_type. */
+      {
+	Dwarf_Die type;
+	if (dwarf_getlocation_die (attr, expr, &type) != 0)
+	  error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s",
+		 dwarf_errmsg (-1));
+	// XXX check size against base_type size?
+	printf ("%s(%" PRIu64 ")", opname, expr->number);
+	print_base_type (&type);
+      }
+      break;
+
+    case DW_OP_const_type:
     case DW_OP_GNU_const_type:
       /* Special, unsigned CU relative DIE offset pointing to a
 	 DW_TAG_base_type, an unsigned size length plus a block with
-- 
2.16.1



More information about the Elfutils-devel mailing list