From patchwork Wed Dec 15 16:00:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Wielaard X-Patchwork-Id: 48982 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7F3A73858003 for ; Wed, 15 Dec 2021 16:21:09 +0000 (GMT) X-Original-To: libabigail@sourceware.org Delivered-To: libabigail@sourceware.org Received: from gnu.wildebeest.org (gnu.wildebeest.org [45.83.234.184]) by sourceware.org (Postfix) with ESMTPS id EFBD3385781D for ; Wed, 15 Dec 2021 16:00:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org EFBD3385781D Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=klomp.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=klomp.org Received: from tarox.wildebeest.org (83-87-18-245.cable.dynamic.v4.ziggo.nl [83.87.18.245]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id 4AC0C302FBA5; Wed, 15 Dec 2021 17:00:25 +0100 (CET) Received: by tarox.wildebeest.org (Postfix, from userid 1000) id BB29040007B0; Wed, 15 Dec 2021 17:00:24 +0100 (CET) From: "Mark J. Wielaard" To: libabigail@sourceware.org Subject: [PATCH] dwarf-reader: Workaround libdw dwarf_location_expression bug Date: Wed, 15 Dec 2021 17:00:21 +0100 Message-Id: <20211215160021.24200-1-mark@klomp.org> X-Mailer: git-send-email 2.18.4 X-Spam-Status: No, score=-10.1 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libabigail@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list of the Libabigail project List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , Cc: Mark Wielaard Errors-To: libabigail-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libabigail" From: Mark Wielaard elfutils libdw before 0.184 would not correctly handle a DW_AT_data_member_location when encoded as a DW_FORM_implicit const in dwarf_location_expression. Work around this by first trying to read a data_member_location as a constant value and only try to get it as a DWARF expression if that * src/abg-dwarf-reader.cc (die_constant_data_member_location): New function. (die_member_offset): Use die_constant_data_member_location before calling die_location_expr and eval_quickly. Signed-off-by: Mark Wielaard --- src/abg-dwarf-reader.cc | 72 +++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 14 deletions(-) https://code.wildebeest.org/git/user/mjw/libabigail/commit/?h=data_member_location diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index ec92f3f8..3f716944 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -8693,6 +8693,37 @@ read_and_convert_DW_at_bit_offset(const Dwarf_Die* die, return true; } +/// Get the value of the DW_AT_data_member_location of the given DIE +/// attribute as an constant. +/// +/// @param die the DIE to read the attribute from. +/// +/// @param offset the attribute as a constant value. This is set iff +/// the function returns true. +/// +/// @return true if the attribute exists and has a constant value. In +/// that case the offset is set to the value. +static bool +die_constant_data_member_location(const Dwarf_Die *die, + int64_t& offset) +{ + if (!die) + return false; + + Dwarf_Attribute attr; + if (!dwarf_attr(const_cast(die), + DW_AT_data_member_location, + &attr)) + return false; + + Dwarf_Word val; + if (dwarf_formudata(&attr, &val) != 0) + return false; + + offset = val; + return true; +} + /// Get the offset of a struct/class member as represented by the /// value of the DW_AT_data_member_location attribute. /// @@ -8758,21 +8789,34 @@ die_member_offset(const read_context& ctxt, return true; } - // Otherwise, let's see if the DW_AT_data_member_location attribute and, - // optionally, the DW_AT_bit_offset attributes are present. - if (!die_location_expr(die, DW_AT_data_member_location, &expr, &expr_len)) - return false; - - // The DW_AT_data_member_location attribute is present. - // Let's evaluate it and get its constant - // sub-expression and return that one. - if (!eval_quickly(expr, expr_len, offset)) - { - bool is_tls_address = false; - if (!eval_last_constant_dwarf_sub_expr(expr, expr_len, - offset, is_tls_address, - ctxt.dwarf_expr_eval_ctxt())) + // First try to read DW_AT_data_member_location as a plain constant. + // We do this because the generic method using die_location_expr + // might hit a bug in elfutils libdw dwarf_location_expression only + // fixed in elfutils 0.184+. The bug only triggers if the attribute + // is expressed as a (DWARF 5) DW_FORM_implicit_constant. But we + // handle all constants here because that is more consistent (and + // slightly faster in the general case where the attribute isn't a + // full DWARF expression). + if (!die_constant_data_member_location(die, offset)) + { + // Otherwise, let's see if the DW_AT_data_member_location + // attribute and, optionally, the DW_AT_bit_offset attributes + // are present. + if (!die_location_expr(die, DW_AT_data_member_location, + &expr, &expr_len)) return false; + + // The DW_AT_data_member_location attribute is present. Let's + // evaluate it and get its constant sub-expression and return + // that one. + if (!eval_quickly(expr, expr_len, offset)) + { + bool is_tls_address = false; + if (!eval_last_constant_dwarf_sub_expr(expr, expr_len, + offset, is_tls_address, + ctxt.dwarf_expr_eval_ctxt())) + return false; + } } offset *= 8;