From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 57346 invoked by alias); 6 Mar 2018 18:56:04 -0000 Mailing-List: contact elfutils-devel-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Post: List-Help: List-Subscribe: Sender: elfutils-devel-owner@sourceware.org Received: (qmail 57332 invoked by uid 89); 6 Mar 2018 18:56:03 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.99.3 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.2 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.2 spammy=44777, sk:dw_at_c, sk:DW_AT_c X-Spam-Status: No, score=-25.2 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-HELO: gnu.wildebeest.org Received: from wildebeest.demon.nl (HELO gnu.wildebeest.org) (212.238.236.112) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 06 Mar 2018 18:56:00 +0000 Received: from librem.wildebeest.org (zebra.wildebeest.org [80.127.118.214]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id 49B8A300072F; Tue, 6 Mar 2018 19:55:57 +0100 (CET) Received: by librem.wildebeest.org (Postfix, from userid 1000) id DE3711403CB; Tue, 6 Mar 2018 19:55:56 +0100 (CET) From: Mark Wielaard To: elfutils-devel@sourceware.org Cc: Mark Wielaard Subject: [PATCH] libdw: Add new DWARF5 Dwarf expression operations. Date: Tue, 06 Mar 2018 18:56:00 -0000 Message-Id: <20180306185549.22544-1-mark@klomp.org> X-Mailer: git-send-email 2.16.1 X-Spam-Flag: NO X-IsSubscribed: yes X-SW-Source: 2018-q1/txt/msg00070.txt.bz2 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 --- 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 + + * 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 * 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 , 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 + + * 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 * 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 + + * 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 * 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