From patchwork Thu Jan 18 16:26:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 84357 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 324E5385840B for ; Thu, 18 Jan 2024 16:27:09 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-il1-x132.google.com (mail-il1-x132.google.com [IPv6:2607:f8b0:4864:20::132]) by sourceware.org (Postfix) with ESMTPS id 452BB3858D33 for ; Thu, 18 Jan 2024 16:26:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 452BB3858D33 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=adacore.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=adacore.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 452BB3858D33 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::132 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1705595203; cv=none; b=D5OA0f+i0Sl0cxhg9VDTR5kLZyJgUP0tVpZ1FQ8zwx3rUoVkEE6dLWPMauvt9BhD3Nl0RTvGWGxsPBjB7C3LR7j9ad4g+i0KehbbjXkmem/LmQ0gHY2587pkPSyAB1CHlqsXkm1DGAtEnoYMlkaESv6tBX9zKE4FKAiHI9IHX40= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1705595203; c=relaxed/simple; bh=r3/r3qxQFGVYRO1FHyWqG/PbbkJLv67NIkQVcy4lUls=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=T0+AT/wgJt0dzj6z41M9JLR8mrM+h7e0LIG9FeB2sGIqYZJMCV9Sd87gFVZmH+OPnjRmcH3sDnVX0gyThzD5gHdIIUPwK+m+F+kNFmQaHDSCJKehsbag+NwFy8WBDjspvrSulGRUApRaHV4RUqF6q3wxFakGn9Xg20i3BD/dN4s= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-il1-x132.google.com with SMTP id e9e14a558f8ab-361a741723eso546555ab.0 for ; Thu, 18 Jan 2024 08:26:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1705595199; x=1706199999; darn=sourceware.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=d51y/O3yMYGPg02zRi8PzABa4eJAm6bsxhOfXsfUHAQ=; b=NFM2X7oTqkbrKo/pipXMMHC1FXsLtuJyYeJwR53R47V18FxjkI5hC8IkTN3aBN4Sdv HEA6hOshL/5LNTLLmDJZ5tI81phy1aKtCUFhC6RaMmgaloNoKYAW9+n6yPbdLlzyXmTF 40BkxvAtk8/znTmTGSckNabBgK7wHNKacJ9xg3rAbUPQxpphhMmgg976674i2qzFWKcW QQICpeNE08MB0J0BY8a1QVFwzOWv6trJI6IbDLKy/DnQd1quXvqIwCWMFfoweTfgreOL uRrHaKqCDbSgARsB3rEdgSN+qscEfk+kc/ig4B/vRn057Ws2TSUYWwWvfGbMnebPJqNW mGZw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1705595199; x=1706199999; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=d51y/O3yMYGPg02zRi8PzABa4eJAm6bsxhOfXsfUHAQ=; b=kWqyZ30N0SQe1Nd7Z5wMND8yvGt+rk9hETgv0hlvCYa7wdh8DG7aRXLrk/V9j2747H uWvbxH/DUAHD761JqLnr3haEwoKM856JYX080M5UD52A37pqhWmPzze6AEnEBmewnrWq ojuCuqz/vmElPhK+wfBNN2Jq2aH+jV9d5nfh/pet0+KuziIJ17FduMKl+3FboeuDKfH3 DVdtaZ5mT5kZ6nf8y8AiH/MZPsR4b8FmQ5BbYLnv7k1KeiIU8Hvfr9cgEh1wcTHYWbAV otT/eIoVj89pjXx0fMDU0xgwLQ6ViQb7vtqV2wqjTitI8xbMw8SIgLjtnyEgynXh1yAb H5Pg== X-Gm-Message-State: AOJu0YxIS8aeiUSYx2uljjnSRF8qL7A+OTfIxALLA6EngBYS7g5n6EMB Nd3PhUrhAnwVvyQuDqwiJWsCIt1QG1hCxClei9CircazLdQO1XH6dPxxJ6MPytH3WvxL7Kerg7Q = X-Google-Smtp-Source: AGHT+IH3LaVyqJPj6Hd5JOsYCqjxAPpM6toETrN2Hb0jorszazH0psqdSEPVSmT4gDCbFliu3wBb5Q== X-Received: by 2002:a05:6e02:144a:b0:361:a7db:7d64 with SMTP id p10-20020a056e02144a00b00361a7db7d64mr62543ilo.8.1705595199320; Thu, 18 Jan 2024 08:26:39 -0800 (PST) Received: from localhost.localdomain (97-122-68-157.hlrn.qwest.net. [97.122.68.157]) by smtp.gmail.com with ESMTPSA id z20-20020a056638001400b0046eaf3bfcabsm785127jao.18.2024.01.18.08.26.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 18 Jan 2024 08:26:38 -0800 (PST) From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [PATCH] Handling of arrays with optimized-out bounds Date: Thu, 18 Jan 2024 09:26:29 -0700 Message-ID: <20240118162629.3853066-1-tromey@adacore.com> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org In Ada, sometimes the compiler must emit array bounds by referencing an artificial variable that's created for this purpose. However, with optimization enabled, these variables can be optimized away. Currently this can result in displays like: (gdb) print mumble $1 = (warning: unable to get bounds of array, assuming null array ) This patch changes this to report that the array is optimized-out, instead, which is closer to the truth, and more generally useful. For example, Python pretty-printers can now recognize this situation. In order to accomplish this, I introduced a new PROP_OPTIMIZED_OUT enumerator and changed one place to use it. Reusing the "unknown" state wouldn't work properly, because in C it is normal for array bounds to be unknown. --- gdb/ada-lang.c | 4 +- gdb/c-varobj.c | 2 +- gdb/eval.c | 2 +- gdb/f-lang.c | 2 +- gdb/gdbtypes.c | 32 +++++--- gdb/gdbtypes.h | 26 +++++++ gdb/testsuite/gdb.dwarf2/arr-opt-out.c | 22 ++++++ gdb/testsuite/gdb.dwarf2/arr-opt-out.exp | 95 ++++++++++++++++++++++++ gdb/value.c | 11 ++- 9 files changed, 180 insertions(+), 16 deletions(-) create mode 100644 gdb/testsuite/gdb.dwarf2/arr-opt-out.c create mode 100644 gdb/testsuite/gdb.dwarf2/arr-opt-out.exp diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index c04c48e2e90..d49426a0842 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -682,7 +682,7 @@ ada_discrete_type_high_bound (struct type *type) return high.const_val (); else { - gdb_assert (high.kind () == PROP_UNDEFINED); + gdb_assert (!high.is_available ()); /* This happens when trying to evaluate a type's dynamic bound without a live target. There is nothing relevant for us to @@ -717,7 +717,7 @@ ada_discrete_type_low_bound (struct type *type) return low.const_val (); else { - gdb_assert (low.kind () == PROP_UNDEFINED); + gdb_assert (!low.is_available ()); /* This happens when trying to evaluate a type's dynamic bound without a live target. There is nothing relevant for us to diff --git a/gdb/c-varobj.c b/gdb/c-varobj.c index ac840c69493..4a747644909 100644 --- a/gdb/c-varobj.c +++ b/gdb/c-varobj.c @@ -192,7 +192,7 @@ c_number_of_children (const struct varobj *var) { case TYPE_CODE_ARRAY: if (type->length () > 0 && target->length () > 0 - && (type->bounds ()->high.kind () != PROP_UNDEFINED)) + && type->bounds ()->high.is_available ()) children = type->length () / target->length (); else /* If we don't know how many elements there are, don't display diff --git a/gdb/eval.c b/gdb/eval.c index 495effe2d03..4f4582e2d79 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -2819,7 +2819,7 @@ var_value_operation::evaluate_for_sizeof (struct expression *exp, if (type_not_allocated (type) || type_not_associated (type)) return value::zero (size_type, not_lval); else if (is_dynamic_type (type->index_type ()) - && type->bounds ()->high.kind () == PROP_UNDEFINED) + && !type->bounds ()->high.is_available ()) return value::allocate_optimized_out (size_type); } } diff --git a/gdb/f-lang.c b/gdb/f-lang.c index c35c73a0eb7..7317caecd94 100644 --- a/gdb/f-lang.c +++ b/gdb/f-lang.c @@ -1372,7 +1372,7 @@ fortran_undetermined::value_subarray (value *array, have a known upper bound, so don't error check in that situation. */ if (index < lb - || (dim_type->index_type ()->bounds ()->high.kind () != PROP_UNDEFINED + || (dim_type->index_type ()->bounds ()->high.is_available () && index > ub) || (array->lval () != lval_memory && dim_type->index_type ()->bounds ()->high.kind () == PROP_UNDEFINED)) diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 1dc68a99104..1208caf2591 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -2177,21 +2177,35 @@ resolve_dynamic_range (struct type *dyn_range_type, gdb_assert (rank >= 0); const struct dynamic_prop *prop = &dyn_range_type->bounds ()->low; - if (resolve_p && dwarf2_evaluate_property (prop, frame, addr_stack, &value, - { (CORE_ADDR) rank })) - low_bound.set_const_val (value); + if (resolve_p) + { + if (dwarf2_evaluate_property (prop, frame, addr_stack, &value, + { (CORE_ADDR) rank })) + low_bound.set_const_val (value); + else if (prop->kind () == PROP_UNDEFINED) + low_bound.set_undefined (); + else + low_bound.set_optimized_out (); + } else low_bound.set_undefined (); prop = &dyn_range_type->bounds ()->high; - if (resolve_p && dwarf2_evaluate_property (prop, frame, addr_stack, &value, - { (CORE_ADDR) rank })) + if (resolve_p) { - high_bound.set_const_val (value); + if (dwarf2_evaluate_property (prop, frame, addr_stack, &value, + { (CORE_ADDR) rank })) + { + high_bound.set_const_val (value); - if (dyn_range_type->bounds ()->flag_upper_bound_is_count) - high_bound.set_const_val - (low_bound.const_val () + high_bound.const_val () - 1); + if (dyn_range_type->bounds ()->flag_upper_bound_is_count) + high_bound.set_const_val + (low_bound.const_val () + high_bound.const_val () - 1); + } + else if (prop->kind () == PROP_UNDEFINED) + high_bound.set_undefined (); + else + high_bound.set_optimized_out (); } else high_bound.set_undefined (); diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 2afcf163a81..20f68885d6a 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -271,6 +271,7 @@ enum dynamic_prop_kind PROP_VARIANT_PARTS, /* Variant parts. */ PROP_TYPE, /* Type. */ PROP_VARIABLE_NAME, /* Variable name. */ + PROP_OPTIMIZED_OUT, /* Optimized out. */ }; union dynamic_prop_data @@ -318,6 +319,18 @@ struct dynamic_prop m_kind = PROP_UNDEFINED; } + void set_optimized_out () + { + m_kind = PROP_OPTIMIZED_OUT; + } + + /* Return true if this property is "available", at least in theory + -- meaning it is neither undefined nor optimized out. */ + bool is_available () const + { + return m_kind != PROP_UNDEFINED && m_kind != PROP_OPTIMIZED_OUT; + } + LONGEST const_val () const { gdb_assert (m_kind == PROP_CONST); @@ -760,6 +773,13 @@ struct range_bounds return this->stride.const_val (); } + /* Return true if either bounds is optimized out. */ + bool optimized_out () const + { + return (low.kind () == PROP_OPTIMIZED_OUT + || high.kind () == PROP_OPTIMIZED_OUT); + } + /* * Low bound of range. */ struct dynamic_prop low; @@ -1135,6 +1155,12 @@ struct type this->main_type->flds_bnds.bounds = bounds; } + /* Return true if this type's bounds were optimized out. */ + bool bound_optimized_out () const + { + return bounds ()->optimized_out (); + } + ULONGEST bit_stride () const { if (this->code () == TYPE_CODE_ARRAY && this->field (0).bitsize () != 0) diff --git a/gdb/testsuite/gdb.dwarf2/arr-opt-out.c b/gdb/testsuite/gdb.dwarf2/arr-opt-out.c new file mode 100644 index 00000000000..5397911fea6 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/arr-opt-out.c @@ -0,0 +1,22 @@ +/* Copyright 2023 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 . */ + +int global_array[] = {0, 0}; + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/arr-opt-out.exp b/gdb/testsuite/gdb.dwarf2/arr-opt-out.exp new file mode 100644 index 00000000000..387ac0ce996 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/arr-opt-out.exp @@ -0,0 +1,95 @@ +# Copyright 2023 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 . + +# Test that an array whose bounds are optimized out is itself marked +# as optimized out. + +load_lib dwarf.exp +load_lib gdb-python.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +require dwarf2_support + +standard_testfile .c -dw.S + +# Make some DWARF for the test. +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + cu {} { + DW_TAG_compile_unit { + {DW_AT_language @DW_LANG_Ada95} + {DW_AT_name foo.adb} + {DW_AT_comp_dir /tmp} + } { + declare_labels integer_label array_label \ + low_bound_label high_bound_label + + integer_label: DW_TAG_base_type { + {DW_AT_byte_size 4 DW_FORM_sdata} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name integer} + } + + # Note that the bounds don't have a location -- they are + # optimized out. This mimics what it is seen sometimes in + # the wild with optimized Ada code. + low_bound_label: DW_TAG_variable { + {DW_AT_name pck__table___L} + {DW_AT_type :$integer_label} + {DW_AT_declaration 1 flag} + } + high_bound_label: DW_TAG_variable { + {DW_AT_name pck__table___U} + {DW_AT_type :$integer_label} + {DW_AT_declaration 1 flag} + } + + array_label: DW_TAG_array_type { + {DW_AT_name pck__table} + {DW_AT_type :$integer_label} + } { + DW_TAG_subrange_type { + {DW_AT_type :$integer_label} + {DW_AT_lower_bound :$low_bound_label} + {DW_AT_upper_bound :$high_bound_label} + } + } + + DW_TAG_variable { + {DW_AT_name the_table} + {DW_AT_type :$array_label} + {DW_AT_location { + DW_OP_addr [gdb_target_symbol global_array] + } SPECIAL_expr} + {DW_AT_external 1 flag} + } + } + } +} + +if {[prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}]} { + return -1 +} + +gdb_test_no_output "set language ada" + +gdb_test "print the_table" " = " + +# The same but in Python. +if {[allow_python_tests]} { + gdb_test "python print(gdb.parse_and_eval('the_table').is_optimized_out)" \ + True +} diff --git a/gdb/value.c b/gdb/value.c index 4ec9babcce8..04ed243f14d 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -3601,9 +3601,16 @@ value_from_contents_and_address (struct type *type, struct type *resolved_type = resolve_dynamic_type (type, view, address, &frame); struct type *resolved_type_no_typedef = check_typedef (resolved_type); - struct value *v; - if (valaddr == NULL) + struct value *v; + if (resolved_type_no_typedef->code () == TYPE_CODE_ARRAY + && resolved_type_no_typedef->bound_optimized_out ()) + { + /* Resolution found that the bounds are optimized out. In this + case, mark the array itself as optimized-out. */ + v = value::allocate_optimized_out (resolved_type); + } + else if (valaddr == nullptr) v = value::allocate_lazy (resolved_type); else v = value_from_contents (resolved_type, valaddr);