From patchwork Thu Jan 12 09:01:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Maciej W. Rozycki" X-Patchwork-Id: 63088 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 CE29638543BB for ; Thu, 12 Jan 2023 09:02:02 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-lf1-x136.google.com (mail-lf1-x136.google.com [IPv6:2a00:1450:4864:20::136]) by sourceware.org (Postfix) with ESMTPS id 4095F385B532 for ; Thu, 12 Jan 2023 09:01:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4095F385B532 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-lf1-x136.google.com with SMTP id b3so27482676lfv.2 for ; Thu, 12 Jan 2023 01:01:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=mime-version:user-agent:references:message-id:in-reply-to:subject :cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=xvW8x6JNTBOCRxzkPgBxjFeAAOuKjXePWRMzc4zmtbs=; b=ZejxlyuYiHyEmkIFXPqeYNFUezmzbJI/X21O9Hf3WrgZpo16tm+ijHRjUn9TrlG7+l 2tfnxyRvXzLSNzug8K7d9HO8AP826sN8R0JYprIE0jmmyC7KmQ7Ann+ZcIV6PPjZAUgY JCEb3c1vpntluk8W/wM3yJI2YRHriDFtAaZE6gQCoDcm7yWaM/Rgu8z6K8Xpvq6FtUA6 lVjCxTeFvnmZmKF70DmaBYnD5DYO9DFZxnnMB1Q+L+h5mNhO/3O+SrWlFzvB3f/iQZJc nGmVZG++ZFe3tiEzH55bBPU0orsE+imKffpdUEtbpDmn6I0a4EsktdokK/y0dzqnt9+f ZDfQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:references:message-id:in-reply-to:subject :cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=xvW8x6JNTBOCRxzkPgBxjFeAAOuKjXePWRMzc4zmtbs=; b=aHNoThHp+CPzsMwdjweMIS2UnsuX/rjZllLbeUibouSqIVOpvDJZRnD4RNYibdJ8dc rHzset0dEEEYwBs3M3TsKhGQA6+6KOgwVV5IKaYpp2cdfGpkul5mup/arYBO8HrA6eMV 4m1B5+FvyPiDRYMZN81aUcbCasDyIq0NR4u+B7TprQC47CkDy5Hi8ieg/o/u+0gJ+8n8 3+7NUtI9jMipOpvFntZH/7+d8PLWIMMuOE4JOkc4YsC+Oz+xFnZj2a6W8Jd9KBWn3Uj7 gqpuaAEma/yh3Q9anM79yBa65jOHxRmUQCXdJJmty62YpELy3cRp5KfSGXWFYulAVGN1 m6Lg== X-Gm-Message-State: AFqh2kpFjFZPlFeAD/DrBdQE00XjgF8jeYNujADdXqp0qa8B3peafq+a XpPoDo2eHJIEhF2wXuKVuZS2zZPv0VHGFIYd X-Google-Smtp-Source: AMrXdXsOJVbwkDpSQioYtQhq1gHZNS+RKW+ng8bwk22fjlZ4JVHT32LwbBjLO1mkr1nPyA4j4rFRHw== X-Received: by 2002:a05:6512:3e05:b0:4b9:a91c:b0c9 with SMTP id i5-20020a0565123e0500b004b9a91cb0c9mr23614183lfv.7.1673514101857; Thu, 12 Jan 2023 01:01:41 -0800 (PST) Received: from [192.168.219.3] ([78.8.192.131]) by smtp.gmail.com with ESMTPSA id w29-20020a0565120b1d00b004b6e9530900sm3142620lfu.110.2023.01.12.01.01.40 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 12 Jan 2023 01:01:41 -0800 (PST) Date: Thu, 12 Jan 2023 09:01:39 +0000 (GMT) From: "Maciej W. Rozycki" To: gdb-patches@sourceware.org cc: Andrew Burgess , Tom Tromey , Richard Bunt Subject: [PATCH v2 1/5] GDB: Ignore `max-value-size' setting with value history accesses In-Reply-To: Message-ID: References: User-Agent: Alpine 2.20 (DEB 67 2015-01-07) MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=no 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.29 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 Sender: "Gdb-patches" We have an inconsistency in value history accesses where array element accesses cause an error for entries exceeding the currently selected `max-value-size' setting even where such accesses successfully complete for elements located in the inferior, e.g.: (gdb) p/d one $1 = 0 (gdb) p/d one_hundred $2 = {0 } (gdb) p/d one_hundred[99] $3 = 0 (gdb) set max-value-size 25 (gdb) p/d one_hundred value requires 100 bytes, which is more than max-value-size (gdb) p/d one_hundred[99] $7 = 0 (gdb) p/d $2 value requires 100 bytes, which is more than max-value-size (gdb) p/d $2[99] value requires 100 bytes, which is more than max-value-size (gdb) According to our documentation the `max-value-size' setting is a safety guard against allocating an overly large amount of memory. Moreover a statement in documentation says, concerning this setting, that: "Setting this variable does not effect values that have already been allocated within GDB, only future allocations." While in the implementer-speak the sentence may be unambiguous I think the outside user may well infer that the setting only applies to values that need to be retrieved from the debuggee. Therefore rather than just fixing this inconsistency it seems reasonable to lift the setting for value history accesses, under an implication that by having been retrieved from the debuggee they have already passed the safety check. Do it then, making the last two commands succeed: (gdb) p/d $2 $8 = {0 } (gdb) p/d $2 [99] $9 = 0 (gdb) Expand the testsuite accordingly. --- gdb/testsuite/gdb.base/max-value-size.exp | 3 + gdb/value.c | 56 ++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 17 deletions(-) gdb-value-history-size.diff Index: src/gdb/testsuite/gdb.base/max-value-size.exp =================================================================== --- src.orig/gdb/testsuite/gdb.base/max-value-size.exp +++ src/gdb/testsuite/gdb.base/max-value-size.exp @@ -53,6 +53,9 @@ proc do_value_printing { max_value_size gdb_test "p/d one_hundred" " = \\{0 \\}" } gdb_test "p/d one_hundred \[99\]" " = 0" + # Verify that accessing value history is undisturbed. + gdb_test "p/d \$2" " = \\{0 \\}" + gdb_test "p/d \$2 \[99\]" " = 0" } } Index: src/gdb/value.c =================================================================== --- src.orig/gdb/value.c +++ src/gdb/value.c @@ -1034,31 +1034,42 @@ check_type_length_before_alloc (const st } } -/* Allocate the contents of VAL if it has not been allocated yet. */ +/* Allocate the contents of VAL if it has not been allocated yet. + If CHECK_SIZE is true, then apply the usual max-value-size checks. */ static void -allocate_value_contents (struct value *val) +allocate_value_contents (struct value *val, bool check_size) { if (!val->contents) { - check_type_length_before_alloc (val->enclosing_type); + if (check_size) + check_type_length_before_alloc (val->enclosing_type); val->contents.reset ((gdb_byte *) xzalloc (val->enclosing_type->length ())); } } -/* Allocate a value and its contents for type TYPE. */ +/* Allocate a value and its contents for type TYPE. If CHECK_SIZE is true, + then apply the usual max-value-size checks. */ -struct value * -allocate_value (struct type *type) +static struct value * +allocate_value (struct type *type, bool check_size) { struct value *val = allocate_value_lazy (type); - allocate_value_contents (val); + allocate_value_contents (val, check_size); val->lazy = 0; return val; } +/* Allocate a value and its contents for type TYPE. */ + +struct value * +allocate_value (struct type *type) +{ + return allocate_value (type, true); +} + /* Allocate a value that has the correct length for COUNT repetitions of type TYPE. */ @@ -1169,7 +1180,7 @@ value_contents_raw (struct value *value) struct gdbarch *arch = get_value_arch (value); int unit_size = gdbarch_addressable_memory_unit_size (arch); - allocate_value_contents (value); + allocate_value_contents (value, true); ULONGEST length = value_type (value)->length (); return gdb::make_array_view @@ -1179,7 +1190,7 @@ value_contents_raw (struct value *value) gdb::array_view value_contents_all_raw (struct value *value) { - allocate_value_contents (value); + allocate_value_contents (value, true); ULONGEST length = value_enclosing_type (value)->length (); return gdb::make_array_view (value->contents.get (), length); @@ -1752,12 +1763,14 @@ value_release_to_mark (const struct valu return result; } -/* Return a copy of the value ARG. - It contains the same contents, for same memory address, - but it's a different block of storage. */ +/* Return a copy of the value ARG. It contains the same contents, + for the same memory address, but it's a different block of storage. + If CHECK_SIZE is true, then throw an exception whenever the size + of memory allocated for the contents of the value would exceed + max-value-size. */ -struct value * -value_copy (const value *arg) +static struct value * +value_copy (const value *arg, bool check_size) { struct type *encl_type = value_enclosing_type (arg); struct value *val; @@ -1765,7 +1778,7 @@ value_copy (const value *arg) if (value_lazy (arg)) val = allocate_value_lazy (encl_type); else - val = allocate_value (encl_type); + val = allocate_value (encl_type, check_size); val->type = arg->type; VALUE_LVAL (val) = arg->lval; val->location = arg->location; @@ -1802,6 +1815,15 @@ value_copy (const value *arg) return val; } +/* Return a copy of the value ARG. It contains the same contents, + for the same memory address, but it's a different block of storage. */ + +struct value * +value_copy (const value *arg) +{ + return value_copy (arg, true); +} + /* Return a "const" and/or "volatile" qualified version of the value V. If CNST is true, then the returned value will be qualified with "const". @@ -1965,7 +1987,7 @@ access_value_history (int num) absnum--; - return value_copy (value_history[absnum].get ()); + return value_copy (value_history[absnum].get (), false); } /* See value.h. */ @@ -4162,7 +4184,7 @@ void value_fetch_lazy (struct value *val) { gdb_assert (value_lazy (val)); - allocate_value_contents (val); + allocate_value_contents (val, true); /* A value is either lazy, or fully fetched. The availability/validity is only established as we try to fetch a value. */ From patchwork Thu Jan 12 09:01:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Maciej W. Rozycki" X-Patchwork-Id: 63089 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 2EF7C3854380 for ; Thu, 12 Jan 2023 09:02:09 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-lf1-x12a.google.com (mail-lf1-x12a.google.com [IPv6:2a00:1450:4864:20::12a]) by sourceware.org (Postfix) with ESMTPS id EACFC3854382 for ; Thu, 12 Jan 2023 09:01:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org EACFC3854382 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-lf1-x12a.google.com with SMTP id bq39so27518478lfb.0 for ; Thu, 12 Jan 2023 01:01:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=mime-version:user-agent:references:message-id:in-reply-to:subject :cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=xqluHNCIpW3vTSrMSsrnehW9x3dLuXNPvFBSc3T71Cg=; b=c8zanxEQw0aGri8Sd40+jOI459kAKadGl6fXyHvn50PEYe1EEiaC2rfACc/QWtEiil 5ERpVwn2ZKR5L76mYIcXGQ0X/IWnayhIoKN8a/qvnap5DgsRG2xgrzAETSHR9BKGVEsh Pbvu4RM36IDnP9NdbiDlDaCeOoVVTI7Rl1o3nsO64tzVtucPrN4HvxgHHgHtykLc051F u+1qNrU7WWL8+gv/b+bdOQlK6zPH2I71W8AEnhIsJVSRbJ61s29mX7EYn34wD7/4iJoS WE0MDINDjVmIpEDSwQzKVzT8Ab4SsKKzj+iB8rxQ9qY5NI9nS6Bc9B55DCJNGtrZRvGI qFkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:references:message-id:in-reply-to:subject :cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=xqluHNCIpW3vTSrMSsrnehW9x3dLuXNPvFBSc3T71Cg=; b=C2Ngzv5pBQRh1FSzb5zuwfvjld9skkSqRfY0EahQqAihNBn3xoPenzQAPbDDdB9uVh XTsflL9vPtfCCuHApoSGnnkygXR2/YTdKHUNOGfkwslYngIsrzYh0IGMZWtl5BZw6QSU Ck79uT17SrXRxPrkzX+8jV7ceiDT3VzWfm0G0iF0jZNu8Af+NZoR5OL37bjnqIaFVVUS ChSXwxnt0h8klifilXMZtkg2ujs4LQPcOvJbk1g9lSaJbOQxZjmwhJoHCwebyEXALY2P EYdTk5BuIMcae9ypPG1lZ5CRSTjdO8B7VUew7JlgFknARCEIMq6qcuMyrMSXrLMwpqX5 SZUg== X-Gm-Message-State: AFqh2krfzre9o6aJFTVPNQ0EHzZPcnY6qqP/7FDK2bV6TZv9Pg3oM/gq kxGMrfbfuP40n7kKHBg229HhCI1K0sBDCIcO X-Google-Smtp-Source: AMrXdXsJW5JeWP+60qusUBY8fWObK8W6wFQ3PXKvz6q1ZfOTxAAukhQBOnPOEm035Uu4O5p5YEy5jg== X-Received: by 2002:ac2:5f6a:0:b0:4cb:d16:3f09 with SMTP id c10-20020ac25f6a000000b004cb0d163f09mr14886909lfc.25.1673514112458; Thu, 12 Jan 2023 01:01:52 -0800 (PST) Received: from [192.168.219.3] ([78.8.192.131]) by smtp.gmail.com with ESMTPSA id y4-20020a0565123f0400b004cc590975f7sm3177420lfa.183.2023.01.12.01.01.50 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 12 Jan 2023 01:01:52 -0800 (PST) Date: Thu, 12 Jan 2023 09:01:49 +0000 (GMT) From: "Maciej W. Rozycki" To: gdb-patches@sourceware.org cc: Andrew Burgess , Tom Tromey , Richard Bunt Subject: [PATCH v2 2/5] GDB: Fix the mess with value byte/bit range types In-Reply-To: Message-ID: References: User-Agent: Alpine 2.20 (DEB 67 2015-01-07) MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=no 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.29 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 Sender: "Gdb-patches" Consistently use the LONGEST and ULONGEST types for value byte/bit offsets and lengths respectively, avoiding slient truncation for ranges exceeding the 32-bit span, which may cause incorrect matching. Also report a conversion overflow on byte ranges that cannot be expressed in terms of bits with these data types, e.g.: (gdb) print one_hundred[1LL << 58] Integer overflow in data location calculation (gdb) print one_hundred[(-1LL << 58) - 1] Integer overflow in data location calculation (gdb) Previously such accesses would be let through with unpredictable results produced. --- gdb/value.c | 43 ++++++++++++++++++++++++++----------------- gdb/value.h | 8 ++++---- 2 files changed, 30 insertions(+), 21 deletions(-) gdb-value-range-types.diff Index: src/gdb/value.c =================================================================== --- src.orig/gdb/value.c +++ src/gdb/value.c @@ -74,7 +74,7 @@ struct range LONGEST offset; /* Length of the range. */ - LONGEST length; + ULONGEST length; /* Returns true if THIS is strictly less than OTHER, useful for searching. We keep ranges sorted by offset and coalesce @@ -97,10 +97,10 @@ struct range [offset2, offset2+len2) overlap. */ static int -ranges_overlap (LONGEST offset1, LONGEST len1, - LONGEST offset2, LONGEST len2) +ranges_overlap (LONGEST offset1, ULONGEST len1, + LONGEST offset2, ULONGEST len2) { - ULONGEST h, l; + LONGEST h, l; l = std::max (offset1, offset2); h = std::min (offset1 + len1, offset2 + len2); @@ -112,7 +112,7 @@ ranges_overlap (LONGEST offset1, LONGEST static int ranges_contain (const std::vector &ranges, LONGEST offset, - LONGEST length) + ULONGEST length) { range what; @@ -380,7 +380,8 @@ get_value_arch (const struct value *valu } int -value_bits_available (const struct value *value, LONGEST offset, LONGEST length) +value_bits_available (const struct value *value, + LONGEST offset, ULONGEST length) { gdb_assert (!value->lazy); @@ -389,8 +390,16 @@ value_bits_available (const struct value int value_bytes_available (const struct value *value, - LONGEST offset, LONGEST length) + LONGEST offset, ULONGEST length) { + ULONGEST sign = (1ULL << (sizeof (ULONGEST) * 8 - 1)) / TARGET_CHAR_BIT; + ULONGEST mask = (sign << 1) - 1; + + if (offset != ((offset & mask) ^ sign) - sign + || length != ((length & mask) ^ sign) - sign + || (length > 0 && (~offset & (offset + length - 1) & sign) != 0)) + error (_("Integer overflow in data location calculation")); + return value_bits_available (value, offset * TARGET_CHAR_BIT, length * TARGET_CHAR_BIT); @@ -460,7 +469,7 @@ value_entirely_optimized_out (struct val static void insert_into_bit_range_vector (std::vector *vectorp, - LONGEST offset, LONGEST length) + LONGEST offset, ULONGEST length) { range newr; @@ -558,8 +567,8 @@ insert_into_bit_range_vector (std::vecto if (ranges_overlap (bef.offset, bef.length, offset, length)) { /* #1 */ - ULONGEST l = std::min (bef.offset, offset); - ULONGEST h = std::max (bef.offset + bef.length, offset + length); + LONGEST l = std::min (bef.offset, offset); + LONGEST h = std::max (bef.offset + bef.length, offset + length); bef.offset = l; bef.length = h - l; @@ -600,7 +609,7 @@ insert_into_bit_range_vector (std::vecto struct range &r = *i; if (r.offset <= t.offset + t.length) { - ULONGEST l, h; + LONGEST l, h; l = std::min (t.offset, r.offset); h = std::max (t.offset + t.length, r.offset + r.length); @@ -626,14 +635,14 @@ insert_into_bit_range_vector (std::vecto void mark_value_bits_unavailable (struct value *value, - LONGEST offset, LONGEST length) + LONGEST offset, ULONGEST length) { insert_into_bit_range_vector (&value->unavailable, offset, length); } void mark_value_bytes_unavailable (struct value *value, - LONGEST offset, LONGEST length) + LONGEST offset, ULONGEST length) { mark_value_bits_unavailable (value, offset * TARGET_CHAR_BIT, @@ -786,7 +795,7 @@ static int find_first_range_overlap_and_match (struct ranges_and_idx *rp1, struct ranges_and_idx *rp2, LONGEST offset1, LONGEST offset2, - LONGEST length, ULONGEST *l, ULONGEST *h) + ULONGEST length, ULONGEST *l, ULONGEST *h) { rp1->idx = find_first_range_overlap (rp1->ranges, rp1->idx, offset1, length); @@ -1306,14 +1315,14 @@ value_contents_all (struct value *value) static void ranges_copy_adjusted (std::vector *dst_range, int dst_bit_offset, const std::vector &src_range, int src_bit_offset, - int bit_length) + unsigned int bit_length) { for (const range &r : src_range) { - ULONGEST h, l; + LONGEST h, l; l = std::max (r.offset, (LONGEST) src_bit_offset); - h = std::min (r.offset + r.length, + h = std::min ((LONGEST) (r.offset + r.length), (LONGEST) src_bit_offset + bit_length); if (l < h) Index: src/gdb/value.h =================================================================== --- src.orig/gdb/value.h +++ src/gdb/value.h @@ -512,7 +512,7 @@ extern int value_bits_synthetic_pointer byte is unavailable. */ extern int value_bytes_available (const struct value *value, - LONGEST offset, LONGEST length); + LONGEST offset, ULONGEST length); /* Given a value, determine whether the contents bits starting at OFFSET and extending for LENGTH bits are available. This returns @@ -520,7 +520,7 @@ extern int value_bytes_available (const bit is unavailable. */ extern int value_bits_available (const struct value *value, - LONGEST offset, LONGEST length); + LONGEST offset, ULONGEST length); /* Like value_bytes_available, but return false if any byte in the whole object is unavailable. */ @@ -534,13 +534,13 @@ extern int value_entirely_unavailable (s LENGTH bytes as unavailable. */ extern void mark_value_bytes_unavailable (struct value *value, - LONGEST offset, LONGEST length); + LONGEST offset, ULONGEST length); /* Mark VALUE's content bits starting at OFFSET and extending for LENGTH bits as unavailable. */ extern void mark_value_bits_unavailable (struct value *value, - LONGEST offset, LONGEST length); + LONGEST offset, ULONGEST length); /* Compare LENGTH bytes of VAL1's contents starting at OFFSET1 with LENGTH bytes of VAL2's contents starting at OFFSET2. From patchwork Thu Jan 12 09:02:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Maciej W. Rozycki" X-Patchwork-Id: 63090 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 7FA7D3854386 for ; Thu, 12 Jan 2023 09:02:26 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-lf1-x12f.google.com (mail-lf1-x12f.google.com [IPv6:2a00:1450:4864:20::12f]) by sourceware.org (Postfix) with ESMTPS id A615D38493DC for ; Thu, 12 Jan 2023 09:02:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A615D38493DC Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-lf1-x12f.google.com with SMTP id f34so27437617lfv.10 for ; Thu, 12 Jan 2023 01:02:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=mime-version:user-agent:references:message-id:in-reply-to:subject :cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=JqJi2Q6s3apIV8cecU7Kfx2aPe4GZwQFHcvp0tcyULc=; b=WeDPF7bfKaJDz4uRebr6TU+6cu1eaVajfzrMASDdYzZzgovoJsTpJS0SHkSc2hHQ2F f0vtPg129O/4UfWYJ6iUS7o30dT7MfcvIRng86pY6TKNX4q/ELa+hS+E5/L+jARQIa3y IbIDQfK17qmeAgqS0MFMk81/Kd5t1RXksSlbTd9wN/JF671mGxu14+ryK2G5TxR0My9/ VQqDA4XFotAYOcjnbnsHg++2SqG4wydt9qa2RlcrLM+NbGCoD7L6pTjyV2pMf851F5zi 0IkZ0ILBsHyNmXDPlEH+pjQk3jl39uTzKX4ZMiaNC1P1DsovEcCGWjeXc6vxdAk/EEX2 Cq5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:references:message-id:in-reply-to:subject :cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=JqJi2Q6s3apIV8cecU7Kfx2aPe4GZwQFHcvp0tcyULc=; b=UEENJD91oQawXVOS4lW/aPjb2gpFqRuGsGUasj9uePIIG63BuKkb8IGd5CKCzgGx4Q ahD9Idhm3rwm1i4JJ8/B31WTq75J1ToS4k3Heb1g9ZOCZ07H7leULoS23TST1MLXcyDo wMDPp+FJwS0rVCAvVlht0Q9pkqUyDhx4I0IEMwYlsnDMGloodVOmrFLgCPpHpZuotiL4 jUr9C/BOa6Pf2tQqF6c1dT7nNX5MzlHwkhT7K10ZKvR1qmgIwsDBErrDFq6qx6UP4Tiw 6O6e1phx5DfQJnp5UHzB5mcZJdoWv7tP52WCUWRLmBabY9sDdjS00CgMhynfcjsF0bo/ yEkQ== X-Gm-Message-State: AFqh2kpihIEOqxG7GD4wV/JsSfSZNQjqqKdzySrpvhYCmJtgkfggRIq3 e6juk3MP8U7GHzd8aw6LQ51qqEmmcUNQSqrH X-Google-Smtp-Source: AMrXdXsbhu4O/MggdvpN3LyHzJRK1SfG7xqdLRHaiouIy5e8bBc5ZOoXOuVgjkV+eTP8pzgwK0X1OQ== X-Received: by 2002:a05:6512:1049:b0:4a4:68b8:c2ec with SMTP id c9-20020a056512104900b004a468b8c2ecmr24765489lfb.67.1673514124240; Thu, 12 Jan 2023 01:02:04 -0800 (PST) Received: from [192.168.219.3] ([78.8.192.131]) by smtp.gmail.com with ESMTPSA id a18-20020a056512201200b004cc59b46f74sm3157472lfb.106.2023.01.12.01.02.02 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 12 Jan 2023 01:02:03 -0800 (PST) Date: Thu, 12 Jan 2023 09:02:01 +0000 (GMT) From: "Maciej W. Rozycki" To: gdb-patches@sourceware.org cc: Andrew Burgess , Tom Tromey , Richard Bunt Subject: [PATCH v2 3/5] GDB: Only make data actually retrieved into value history available In-Reply-To: Message-ID: References: User-Agent: Alpine 2.20 (DEB 67 2015-01-07) MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, KAM_ASCII_DIVIDERS, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=no 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.29 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 Sender: "Gdb-patches" While it makes sense to allow accessing out-of-bounds elements in the debuggee and see whatever there might happen to be there in memory (we are a debugger and not a programming rules enforcement facility and we want to make people's life easier in chasing bugs), e.g.: (gdb) print one_hundred[-1] $1 = 0 (gdb) print one_hundred[100] $2 = 0 (gdb) we shouldn't really pretend that we have any meaningful data around values recorded in history (what these commands really retrieve are current debuggee memory contents outside the original data accessed, really confusing in my opinion). Add code to mark data around values recorded in history unavailable then: (gdb) print one_hundred[-1] $1 = (gdb) print one_hundred[100] $2 = Adjust `value_entirely_available' accordingly; also zero-length types need special handling in `value_entirely_covered_by_range_vector'. Add a suitable test case, which also covers integer overflows in data location calculation. --- Hi, While at it I noticed that while values recorded in the history are just as one would expect immutable, one can poke at the original data object data in history has originated from by writing to the value in the history, e.g.: (gdb) print -elements 3 -- one_hundred $1 = {0, 1, 2...} (gdb) print -elements 3 -- $1 $2 = {0, 1, 2...} (gdb) set $1[0] = -1 (gdb) print -elements 3 -- $1 $3 = {0, 1, 2...} (gdb) print -elements 3 -- one_hundred $4 = {-1, 1, 2...} (gdb) This is undocumented and I find it surprising to say the least. Shall I file a bug for this phenomenon? LONG_MIN is not used, but I have thought we can have it anyway for consistency and so that people do not try to invent local variants. Maciej --- gdb/defs.h | 8 ++ gdb/testsuite/gdb.base/value-history-unavailable.c | 29 +++++++ gdb/testsuite/gdb.base/value-history-unavailable.exp | 73 +++++++++++++++++++ gdb/valarith.c | 15 +++ gdb/value.c | 24 ++++-- 5 files changed, 144 insertions(+), 5 deletions(-) gdb-value-history-unavailable.diff Index: src/gdb/defs.h =================================================================== --- src.orig/gdb/defs.h +++ src/gdb/defs.h @@ -469,6 +469,10 @@ enum val_prettyformat #define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF for 32-bits */ #endif +#if !defined (LONG_MIN) /* 0x80000000 for 32-bits */ +#define LONG_MIN ((long) (~(long) 0 ^ LONG_MAX)) +#endif + #if !defined (ULONGEST_MAX) #define ULONGEST_MAX (~(ULONGEST)0) /* 0xFFFFFFFFFFFFFFFF for 64-bits */ #endif @@ -477,6 +481,10 @@ enum val_prettyformat #define LONGEST_MAX ((LONGEST)(ULONGEST_MAX >> 1)) #endif +#if !defined (LONGEST_MIN) /* 0x8000000000000000 for 64-bits */ +#define LONGEST_MIN ((LONGEST) (~(LONGEST) 0 ^ LONGEST_MAX)) +#endif + /* * Convert a LONGEST to an int. This is used in contexts (e.g. number of arguments to a function, number in a value history, register number, etc.) where the value must not be larger than can fit in an int. */ Index: src/gdb/testsuite/gdb.base/value-history-unavailable.c =================================================================== --- /dev/null +++ src/gdb/testsuite/gdb.base/value-history-unavailable.c @@ -0,0 +1,29 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright (C) 2022 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 . */ + +struct +{ + unsigned char x[1024]; + unsigned char a[1024]; + unsigned char y[1024]; +} a = { {-1} }; + +int +main () +{ + return 0; +} Index: src/gdb/testsuite/gdb.base/value-history-unavailable.exp =================================================================== --- /dev/null +++ src/gdb/testsuite/gdb.base/value-history-unavailable.exp @@ -0,0 +1,73 @@ +# Copyright (C) 2022 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 GDB's value availability ranges. + +standard_testfile + +if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } { + return -1 +} + +if ![runto_main] then { + perror "couldn't run to breakpoint" + continue +} + +set target_char_mask [get_valueof "/u" "a.x\[0]" "255" "get target char mask"] +set target_char_bit 0 +for {set i $target_char_mask} {$i > 0} {set i [expr $i >> 1]} { + incr target_char_bit +} +set target_char_rank -1 +for {set i $target_char_bit} {$i > 0} {set i [expr $i >> 1]} { + incr target_char_rank +} + +# Verify accesses to original inferior data. +gdb_test "print a.a" "\\\$2 = '\\\\000' " +gdb_test "print a.a\[-1\]" "\\\$3 = 0 '\\\\000'" +gdb_test "print a.a\[1024\]" "\\\$4 = 0 '\\\\000'" + +# Verify in-range value history accesses. +gdb_test "print \$2" "\\\$5 = '\\\\000' " +gdb_test "print \$2\[0\]" "\\\$6 = 0 '\\\\000'" +gdb_test "print \$2\[1023\]" "\\\$7 = 0 '\\\\000'" + +# Values outside the array recorded will have not been retrieved. +gdb_test "print \$2\[-1\]" "\\\$8 = " +gdb_test "print \$2\[1024\]" "\\\$9 = " +gdb_test "print \$2\[-1LL << 63 - $target_char_rank\]" \ + "\\\$10 = " +gdb_test "print \$2\[(1LL << 63 - $target_char_rank) - 1\]" \ + "\\\$11 = " + +# Accesses through pointers in history go straight to the inferior though. +gdb_test "print \$2\[0\]@1" "\\\$12 = \"\"" +gdb_test "print \$2\[-1\]@1" "\\\$13 = \"\"" +gdb_test "print \$2\[1024\]@1" "\\\$14 = \"\"" + +# Verify out-of-range value history accesses. +gdb_test "print \$2\[(-1LL << 63 - $target_char_rank) - 1\]" \ + "Integer overflow in data location calculation" +gdb_test "print \$2\[(1LL << 63 - $target_char_rank)\]" \ + "Integer overflow in data location calculation" +gdb_test "print \$2\[-1LL << 63\]" \ + "Integer overflow in data location calculation" +gdb_test "print \$2\[(1ULL << 63) - 1\]" \ + "Integer overflow in data location calculation" + +# Sanity-check a copy of an unavailable value. +gdb_test "print \$11" "\\\$15 = " Index: src/gdb/valarith.c =================================================================== --- src.orig/gdb/valarith.c +++ src/gdb/valarith.c @@ -182,6 +182,21 @@ value_subscript (struct value *array, LO } index -= *lowerbound; + + /* Do not try to dereference a pointer to an unavailable value. + Instead mock up a new one and give it the original address. */ + struct type *elt_type = check_typedef (tarray->target_type ()); + LONGEST elt_size = type_length_units (elt_type); + if (!value_lazy (array) + && !value_bytes_available (array, elt_size * index, elt_size)) + { + struct value *val = allocate_value (elt_type); + mark_value_bytes_unavailable (val, 0, elt_size); + VALUE_LVAL (val) = lval_memory; + set_value_address (val, value_address (array) + elt_size * index); + return val; + } + array = value_coerce_array (array); } Index: src/gdb/value.c =================================================================== --- src.orig/gdb/value.c +++ src/gdb/value.c @@ -421,7 +421,9 @@ value_entirely_available (struct value * if (value->lazy) value_fetch_lazy (value); - if (value->unavailable.empty ()) + if (value->unavailable.empty () + || value_bytes_available (value, 0, + value_enclosing_type (value)->length ())) return 1; return 0; } @@ -441,11 +443,12 @@ value_entirely_covered_by_range_vector ( if (ranges.size () == 1) { + ULONGEST length = value_enclosing_type (value)->length (); const struct range &t = ranges[0]; - if (t.offset == 0 - && t.length == (TARGET_CHAR_BIT - * value_enclosing_type (value)->length ())) + if (length == 0) + return t.offset == 0 && t.length == 0; + if (t.offset <= 0 && t.offset + t.length >= TARGET_CHAR_BIT * length) return 1; } @@ -1277,7 +1280,9 @@ require_not_optimized_out (const struct static void require_available (const struct value *value) { - if (!value->unavailable.empty ()) + if (!value->unavailable.empty () + && !value_bytes_available (value, 0, + value_enclosing_type (value)->length ())) throw_error (NOT_AVAILABLE_ERROR, _("value is not available")); } @@ -1962,6 +1967,15 @@ record_latest_value (struct value *val) a value on the value history never changes. */ if (value_lazy (val)) value_fetch_lazy (val); + + /* Don't pretend we have anything available there in the history beyond + the boundaries of the value recorded. It's not like inferior memory + where there is actual stuff underneath. */ + ULONGEST length = value_enclosing_type (val)->length (); + mark_value_bits_unavailable (val, LONGEST_MIN, 0 ^ LONGEST_MIN); + mark_value_bits_unavailable (val, length * TARGET_CHAR_BIT, + LONGEST_MAX - length * TARGET_CHAR_BIT); + /* We preserve VALUE_LVAL so that the user can find out where it was fetched from. This is a bit dubious, because then *&$1 does not just return $1 but the current contents of that location. c'est la vie... */ From patchwork Thu Jan 12 09:02:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Maciej W. Rozycki" X-Patchwork-Id: 63091 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 0266F385B535 for ; Thu, 12 Jan 2023 09:02:33 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-lf1-x136.google.com (mail-lf1-x136.google.com [IPv6:2a00:1450:4864:20::136]) by sourceware.org (Postfix) with ESMTPS id 7E3703860742 for ; Thu, 12 Jan 2023 09:02:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7E3703860742 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-lf1-x136.google.com with SMTP id bp15so27452703lfb.13 for ; Thu, 12 Jan 2023 01:02:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=mime-version:user-agent:references:message-id:in-reply-to:subject :cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=uak7f3NZrm8Qy7P6G8349oBNVwuXsm0a8GOmKaDRTLw=; b=N/+uKcRaMFUAX9RvJDfNuhE893Z8OrDLJW24bpRSLwY0rnZlmSe7CCp3Htc0kr2S+U 2QmOdULVYLsj6qSZV7BkgEXuhFRDl0FAsQSf3ZxTAXpShP73mGloPPF2iLbCRX1Zs6Xj jsVPL4UpVl/aGIB2jptTM/PxgvR4uTKXetScA9d6O0dgclzCyva8gkMTYngc1IZLFZTz PtPwiJ3Z0ZADy78sFkuIq92nG0+aWv7mT/VWaqROd4R+KfOL0mWHzHZyUkGtdZYwoiSc 4Zl+zAmeh6yO5YuGucBEdMrgtDraXITJnpx1E1TiaSQUq6Cdz5qbPlk/cwpYH+D6/8zG tOmw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:references:message-id:in-reply-to:subject :cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=uak7f3NZrm8Qy7P6G8349oBNVwuXsm0a8GOmKaDRTLw=; b=CVE62kqUoLV9Rd5kzzf8L64/hsFjc2UqcKjZbTdwPWXJFdBHJw3S4khWGnZ3gP4dDr ECyX8EB5bOgAKNaOsSfZIY0XQ7oeSMifx0yTjyjCNzwdM75NLoWNt+b9MNvDY381nPpW AKoOMz0jxsf9lmH3Moi8Gz/P+j2c+G0sGGu3n5Ai0+44ZuOYxb6UcfYT9+7NLX7Dhvrk U78upxakUBIAdqDCe+NCbC6WZvWOByICvNaVshOtMRi22zum6VGG9cc+/rIplFEbD7uU HkTRixrDBHafNvZ7y7Pea0RgcztANMAdYwbxiEu5twNiSHB4FA3iu6AqZp5jgVf8+0mx Z3eg== X-Gm-Message-State: AFqh2krYYDcmb7LetsBmu/2pos8jnGeSeHorUmTWteruDmxtnSWk7JtP zGknbX6WBfkzB2+JmEVlajxN6lCby1TRD3fl X-Google-Smtp-Source: AMrXdXv3kxqG9kcul/svgobuC6+wxkO5Jw027TXKCGiIIUScVck92lSORD5llWNNQ0xwJm+vKuaK6A== X-Received: by 2002:a05:6512:e8f:b0:4ca:ffe0:e754 with SMTP id bi15-20020a0565120e8f00b004caffe0e754mr3636594lfb.18.1673514135090; Thu, 12 Jan 2023 01:02:15 -0800 (PST) Received: from [192.168.219.3] ([78.8.192.131]) by smtp.gmail.com with ESMTPSA id n1-20020a05651203e100b004b591829352sm3181542lfq.64.2023.01.12.01.02.13 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 12 Jan 2023 01:02:14 -0800 (PST) Date: Thu, 12 Jan 2023 09:02:12 +0000 (GMT) From: "Maciej W. Rozycki" To: gdb-patches@sourceware.org cc: Andrew Burgess , Tom Tromey , Richard Bunt Subject: [PATCH v2 4/5] GDB/testsuite: Add `-nonl' option to `gdb_test' In-Reply-To: Message-ID: References: User-Agent: Alpine 2.20 (DEB 67 2015-01-07) MIME-Version: 1.0 X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP 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.29 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 Sender: "Gdb-patches" Add a `-nonl' option to `gdb_test' making it possible to match output from commands such as `output' that do not produce a new line sequence at the end, e.g.: (gdb) output 0 0(gdb) --- gdb/testsuite/lib/gdb.exp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) gdb-test-nonl.diff Index: src/gdb/testsuite/lib/gdb.exp =================================================================== --- src.orig/gdb/testsuite/lib/gdb.exp +++ src/gdb/testsuite/lib/gdb.exp @@ -1395,6 +1395,8 @@ proc gdb_test_multiline { name args } { # have any effect if -prompt is specified. # -lbl specifies that line-by-line matching will be used. # -nopass specifies that a PASS should not be issued. +# -nonl specifies that no \r\n sequence is expected between PATTERN +# and the gdb prompt. # # Returns: # 1 if the test failed, @@ -1410,6 +1412,7 @@ proc gdb_test { args } { {no-prompt-anchor} {lbl} {nopass} + {nonl} } lassign $args command pattern message question response @@ -1424,12 +1427,13 @@ proc gdb_test { args } { } set prompt [fill_in_default_prompt $prompt [expr !${no-prompt-anchor}]] + set nl [expr ${nonl} ? {""} : {"\[\r\n\]+"}] set saw_question 0 set user_code {} lappend user_code { - -re "\[\r\n\]*(?:$pattern)\[\r\n\]+$prompt" { + -re "\[\r\n\]*(?:$pattern)$nl$prompt" { if { $question != "" & !$saw_question} { fail $message } elseif {!$nopass} { From patchwork Thu Jan 12 09:02:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Maciej W. Rozycki" X-Patchwork-Id: 63092 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 D0B5A385B800 for ; Thu, 12 Jan 2023 09:02:58 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-lf1-x12b.google.com (mail-lf1-x12b.google.com [IPv6:2a00:1450:4864:20::12b]) by sourceware.org (Postfix) with ESMTPS id 89895385439F for ; Thu, 12 Jan 2023 09:02:31 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 89895385439F Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-lf1-x12b.google.com with SMTP id cf42so27499140lfb.1 for ; Thu, 12 Jan 2023 01:02:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=mime-version:user-agent:references:message-id:in-reply-to:subject :cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=8YyuAwoYafdNPICIDhn1IL+ri5Q91UPNn8gT9wHw38w=; b=NhtXb39dIbcvJ2+PsHWjZznERUbr7fZLW0+cqHPvSDsYpyVzfnFkAn3YqfucE0R6Dt nazp21L+2r7uDP62Ydik7Iq7oB+3b7OkobIuKdKGHTAEv3gseSJWHzy4VkQRRd9sE46+ yxuLhWs00LIhMQD4WVw1futEig+96uU1qkSplH+lImJeyi+STDVc56CzQfUOVxUM4DeX UuFJOMjwVJYZRsbsJVI2rzCxPtvrhRjkedFHDUaEI5v8xlrc1sd/1TOkJkkfFxcje7tO N8CN5n5zBzU/Ud+FzWNMzWMytrE4QZ4O9tNzKXMNODZcDhfL/e20lRBnUcTho+qEeK2Q UL7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:references:message-id:in-reply-to:subject :cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=8YyuAwoYafdNPICIDhn1IL+ri5Q91UPNn8gT9wHw38w=; b=iou9RmYJGu7IA854sQ4ePStO6G9ifpQffvNPJpN3/q6T97ahkXDIDcEMA0HVd+/CBC N3aiC6Seo41hB/fyf5pXDeqlE8IGNX+uAx/0z8/SlCTKGuygPj3M/QRkadkbB0CoZZ7g 6Tupg2zL0cIsio32oWlBYjjYtbKm5CXN5SNVofrNTxrJcw4upi/2YuJjMfWnEJ4t+2GC Jm+u9RP+Ucgstw4W+bfQ2onRScXLxj/wINIl3WOyS06nT1CgpoC2hsmPQA7W96vwoRaJ c38PoYvubSGQliEUw7spSjWVGMZBcp7S4wXRRKqdwMp2sqUfJ+71Mpf2I2K1ERm8E403 FxPQ== X-Gm-Message-State: AFqh2kpjr0sbViC22IYHoC1KmIlQ6DaHsuYO6eia0/XSB36O7Js0+ZIP QqMOidSrA3TQIXT1dn9lsvse1c/M08iyliGT X-Google-Smtp-Source: AMrXdXv3W8XVyE2OdO0BKjOBPW78MlaezPjXtfmZr3HgkATOVnh9EndoeKqXvIcsjN2PFC2+4sMvsQ== X-Received: by 2002:a19:f513:0:b0:4c5:a0b4:336b with SMTP id j19-20020a19f513000000b004c5a0b4336bmr2973927lfb.1.1673514149659; Thu, 12 Jan 2023 01:02:29 -0800 (PST) Received: from [192.168.219.3] ([78.8.192.131]) by smtp.gmail.com with ESMTPSA id o13-20020ac24e8d000000b004a25bb4494fsm3161266lfr.178.2023.01.12.01.02.24 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 12 Jan 2023 01:02:29 -0800 (PST) Date: Thu, 12 Jan 2023 09:02:23 +0000 (GMT) From: "Maciej W. Rozycki" To: gdb-patches@sourceware.org cc: Andrew Burgess , Tom Tromey , Richard Bunt Subject: [PATCH v2 5/5] GDB: Introduce limited array lengths while printing values In-Reply-To: Message-ID: References: User-Agent: Alpine 2.20 (DEB 67 2015-01-07) MIME-Version: 1.0 X-Spam-Status: No, score=1.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, KAM_ASCII_DIVIDERS, KAM_SHORT, RCVD_IN_DNSWL_NONE, SCC_10_SHORT_WORD_LINES, SCC_20_SHORT_WORD_LINES, SCC_35_SHORT_WORD_LINES, SCC_5_SHORT_WORD_LINES, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=no autolearn_force=no version=3.4.6 X-Spam-Level: * 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.29 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 Sender: "Gdb-patches" From: Andrew Burgess This commit introduces the idea of loading only part of an array in order to print it, what I call "limited length" arrays. The motivation behind this work is to make it possible to print slices of very large arrays, where very large means bigger than `max-value-size'. Consider this GDB session with the current GDB: (gdb) set max-value-size 100 (gdb) p large_1d_array value requires 400 bytes, which is more than max-value-size (gdb) p -elements 10 -- large_1d_array value requires 400 bytes, which is more than max-value-size notice that the request to print 10 elements still fails, even though 10 elements should be less than the max-value-size. With a patched version of GDB: (gdb) p -elements 10 -- large_1d_array $1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9...} So now the print has succeeded. It also has loaded `max-value-size' worth of data into value history, so the recorded value can be accessed consistently: (gdb) p -elements 10 -- $1 $2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9...} (gdb) p $1 $3 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, } (gdb) Accesses with other languages work similarly, although for Ada only C-style [] array element/dimension accesses use history. For both Ada and Fortran () array element/dimension accesses go straight to the inferior, bypassing the value history just as with C pointers. Co-Authored-By: Maciej W. Rozycki --- Changes from v1: - Load `max-value-size' worth data into the value history for limited length accesses and mark the area beyond unavailable. - Handle the `output' command. - Expand test coverage. --- gdb/NEWS | 6 gdb/doc/gdb.texinfo | 9 gdb/f-valprint.c | 32 ++- gdb/printcmd.c | 16 + gdb/testsuite/gdb.ada/limited-length.exp | 266 +++++++++++++++++++++++++++ gdb/testsuite/gdb.ada/limited-length/foo.adb | 37 +++ gdb/testsuite/gdb.ada/limited-length/pck.adb | 25 ++ gdb/testsuite/gdb.ada/limited-length/pck.ads | 21 ++ gdb/testsuite/gdb.base/limited-length.c | 48 ++++ gdb/testsuite/gdb.base/limited-length.exp | 242 ++++++++++++++++++++++++ gdb/testsuite/gdb.fortran/limited-length.exp | 222 ++++++++++++++++++++++ gdb/testsuite/gdb.fortran/limited-length.f90 | 39 +++ gdb/valprint.c | 10 - gdb/value.c | 201 ++++++++++++++++++-- gdb/value.h | 17 + 15 files changed, 1165 insertions(+), 26 deletions(-) create mode 100644 gdb/testsuite/gdb.ada/limited-length.exp create mode 100644 gdb/testsuite/gdb.ada/limited-length/foo.adb create mode 100644 gdb/testsuite/gdb.ada/limited-length/pck.adb create mode 100644 gdb/testsuite/gdb.ada/limited-length/pck.ads create mode 100644 gdb/testsuite/gdb.base/limited-length.c create mode 100644 gdb/testsuite/gdb.base/limited-length.exp create mode 100644 gdb/testsuite/gdb.fortran/limited-length.exp create mode 100644 gdb/testsuite/gdb.fortran/limited-length.f90 gdb-aburgess-limited-length-array.diff Index: src/gdb/NEWS =================================================================== --- src.orig/gdb/NEWS +++ src/gdb/NEWS @@ -354,6 +354,12 @@ GDB now supports floating-point on Loong Disabling this can cause a performance penalty when there are a lot of symbols to load, but is useful for debugging purposes. +* The 'set print elements' setting now helps when printing large arrays. + If an array would otherwise exceed max-value-size, but 'print elements' + is set such that the number of elements to print is less than or equal + to 'max-value-size', GDB will now still print the array, however only + 'max-value-size' worth of data will be added into the value history. + * New commands maint set backtrace-on-fatal-signal on|off Index: src/gdb/doc/gdb.texinfo =================================================================== --- src.orig/gdb/doc/gdb.texinfo +++ src/gdb/doc/gdb.texinfo @@ -11756,6 +11756,14 @@ When @value{GDBN} starts, this limit is Setting @var{number-of-elements} to @code{unlimited} or zero means that the number of elements to print is unlimited. +When printing very large arrays, whose size is greater than +@code{max-value-size} (@pxref{set max-value-size,,max-value-size}), +if the @code{print elements} is set such that the size of the elements +being printed is less than or equal to @code{max-value-size}, then +@value{GDBN} will print the array (up to the @code{print elements} limit), +and only @code{max-value-size} worth of data will be added into the value +history (@pxref{Value History, ,Value History}). + @item show print elements Display the number of elements of a large array that @value{GDBN} will print. @@ -14171,6 +14179,7 @@ may indicate a value that is incorrectly @value{GDBN} to try and allocate an overly large amount of memory. @table @code +@anchor{set max-value-size} @kindex set max-value-size @item set max-value-size @var{bytes} @itemx set max-value-size unlimited Index: src/gdb/f-valprint.c =================================================================== --- src.orig/gdb/f-valprint.c +++ src/gdb/f-valprint.c @@ -261,10 +261,20 @@ class fortran_array_printer_impl : publi size_t dim_indx = m_dimension - 1; struct type *elt_type_prev = m_elt_type_prev; LONGEST elt_off_prev = m_elt_off_prev; - bool repeated = (m_options->repeat_count_threshold < UINT_MAX - && elt_type_prev != nullptr - && value_contents_eq (m_val, elt_off_prev, m_val, elt_off, - elt_type->length ())); + bool repeated = false; + + if (m_options->repeat_count_threshold < UINT_MAX + && elt_type_prev != nullptr) + { + struct value *e_val = value_from_component (m_val, elt_type, elt_off); + struct value *e_prev = value_from_component (m_val, elt_type, + elt_off_prev); + repeated = ((value_entirely_available (e_prev) + && value_entirely_available (e_val) + && value_contents_eq (e_prev, e_val)) + || (value_entirely_unavailable (e_prev) + && value_entirely_unavailable (e_val))); + } if (repeated) m_nrepeats++; @@ -333,7 +343,7 @@ class fortran_array_printer_impl : publi have been sliced and we do not want to compare any memory contents present between the slices requested. */ bool - dimension_contents_eq (const struct value *val, struct type *type, + dimension_contents_eq (struct value *val, struct type *type, LONGEST offset1, LONGEST offset2) { if (type->code () == TYPE_CODE_ARRAY @@ -362,8 +372,16 @@ class fortran_array_printer_impl : publi return true; } else - return value_contents_eq (val, offset1, val, offset2, - type->length ()); + { + struct value *e_val1 = value_from_component (val, type, offset1); + struct value *e_val2 = value_from_component (val, type, offset2); + + return ((value_entirely_available (e_val1) + && value_entirely_available (e_val2) + && value_contents_eq (e_val1, e_val2)) + || (value_entirely_unavailable (e_val1) + && value_entirely_unavailable (e_val2))); + } } /* The number of elements printed so far. */ Index: src/gdb/printcmd.c =================================================================== --- src.orig/gdb/printcmd.c +++ src/gdb/printcmd.c @@ -1242,6 +1242,11 @@ print_command_parse_format (const char * void print_value (value *val, const value_print_options &opts) { + /* This setting allows large arrays to be printed by limiting the + number of elements that are loaded into GDB's memory; we only + need to load as many array elements as we plan to print. */ + scoped_array_length_limiting limit_large_arrays (opts.print_max); + int histindex = record_latest_value (val); annotate_value_history_begin (histindex, value_type (val)); @@ -1301,6 +1306,11 @@ process_print_command_args (const char * if (exp != nullptr && *exp) { + /* This setting allows large arrays to be printed by limiting the + number of elements that are loaded into GDB's memory; we only + need to load as many array elements as we plan to print. */ + scoped_array_length_limiting limit_large_arrays (print_opts->print_max); + /* VOIDPRINT is true to indicate that we do want to print a void value, so invert it for parse_expression. */ expression_up expr = parse_expression (exp, nullptr, !voidprint); @@ -1489,6 +1499,12 @@ output_command (const char *exp, int fro get_formatted_print_options (&opts, format); opts.raw = fmt.raw; + + /* This setting allows large arrays to be printed by limiting the + number of elements that are loaded into GDB's memory; we only + need to load as many array elements as we plan to print. */ + scoped_array_length_limiting limit_large_arrays (opts.print_max); + print_formatted (val, fmt.size, &opts, gdb_stdout); annotate_value_end (); Index: src/gdb/testsuite/gdb.ada/limited-length.exp =================================================================== --- /dev/null +++ src/gdb/testsuite/gdb.ada/limited-length.exp @@ -0,0 +1,266 @@ +# 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 . + +load_lib "ada.exp" + +if {[skip_ada_tests]} { + return -1 +} + +standard_ada_testfile foo + +if {[gdb_compile_ada "${srcfile}" "${binfile}" executable \ + [list debug ]] != "" } { + return -1 +} + +clean_restart ${testfile} + +set bp_location [gdb_get_line_number "STOP" ${testdir}/foo.adb] +if {![runto "foo.adb:$bp_location"]} { + perror "Couldn't run ${testfile}" + return +} + +with_test_prefix "with standard max-value size" { + gdb_test "print Large_1d_Array" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,\ + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,\ + 61, 62, 63, 64\\)" + gdb_test -nonl "output Large_1d_Array" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,\ + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,\ + 61, 62, 63, 64\\)" + gdb_test "print Large_3d_Array" \ + " = \\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33, 34, 35, 36\\), \\(37, 38, 39, 40\\),\ + \\(41, 42, 43, 44\\), \\(45, 46, 47, 48\\)\\),\ + \\(\\(49, 50, 51, 52\\), \\(53, 54, 55, 56\\),\ + \\(57, 58, 59, 60\\), \\(61, 62, 63, 64\\)\\)\\)" + gdb_test -nonl "output Large_3d_Array" \ + "\\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33, 34, 35, 36\\), \\(37, 38, 39, 40\\),\ + \\(41, 42, 43, 44\\), \\(45, 46, 47, 48\\)\\),\ + \\(\\(49, 50, 51, 52\\), \\(53, 54, 55, 56\\),\ + \\(57, 58, 59, 60\\), \\(61, 62, 63, 64\\)\\)\\)" +} + +# Set the max-value-size so we can only print 33 elements. +set elements 33 +set elem_size [get_valueof "/d" "(Large_1d_Array(1)'Size + 7) / 8" "*unknown*"] +gdb_test_no_output "set max-value-size [expr $elem_size * $elements]" + +with_test_prefix "with reduced max-value size" { + gdb_test "print Large_1d_Array" \ + "value of type `.*' requires $decimal bytes,\ + which is more than max-value-size" + gdb_test "output Large_1d_Array" \ + "value of type `.*' requires $decimal bytes,\ + which is more than max-value-size" + gdb_test "print Large_3d_Array" \ + "value of type `.*' requires $decimal bytes,\ + which is more than max-value-size" + gdb_test "output Large_3d_Array" \ + "value of type `.*' requires $decimal bytes,\ + which is more than max-value-size" +} + +with_test_prefix "with reduced print -elements flag" { + gdb_test "print -elements 2 -- Large_1d_Array" \ + " = \\(1, 2\\.\\.\\.\\)" + gdb_test "print -elements 2 -- Large_3d_Array" \ + " = \\(\\(\\(1, 2\\.\\.\\.\\), \\(5, 6\\.\\.\\.\\)\\.\\.\\.\\),\ + \\(\\(17, 18\\.\\.\\.\\),\ + \\(21, 22\\.\\.\\.\\)\\.\\.\\.\\)\\.\\.\\.\\)" +} + +gdb_test_no_output "set print elements 2" + +with_test_prefix "with reduced print elements" { + gdb_test "print Large_1d_Array" \ + " = \\(1, 2\\.\\.\\.\\)" + gdb_test -nonl "output Large_1d_Array" \ + "\\(1, 2\\.\\.\\.\\)" + + gdb_test "print \$" \ + " = \\(1, 2\\.\\.\\.\\)" \ + "print Large_1d_Array from history" + gdb_test -nonl "output \$\$" \ + "\\(1, 2\\.\\.\\.\\)" \ + "output Large_1d_Array from history" + + gdb_test "print Large_3d_Array" \ + " = \\(\\(\\(1, 2\\.\\.\\.\\), \\(5, 6\\.\\.\\.\\)\\.\\.\\.\\),\ + \\(\\(17, 18\\.\\.\\.\\),\ + \\(21, 22\\.\\.\\.\\)\\.\\.\\.\\)\\.\\.\\.\\)" + gdb_test -nonl "output Large_3d_Array" \ + "\\(\\(\\(1, 2\\.\\.\\.\\), \\(5, 6\\.\\.\\.\\)\\.\\.\\.\\),\ + \\(\\(17, 18\\.\\.\\.\\),\ + \\(21, 22\\.\\.\\.\\)\\.\\.\\.\\)\\.\\.\\.\\)" + + gdb_test "print \$" \ + " = \\(\\(\\(1, 2\\.\\.\\.\\), \\(5, 6\\.\\.\\.\\)\\.\\.\\.\\),\ + \\(\\(17, 18\\.\\.\\.\\),\ + \\(21, 22\\.\\.\\.\\)\\.\\.\\.\\)\\.\\.\\.\\)" \ + "print Large_3d_Array from history" + gdb_test -nonl "output \$\$" \ + "\\(\\(\\(1, 2\\.\\.\\.\\), \\(5, 6\\.\\.\\.\\)\\.\\.\\.\\),\ + \\(\\(17, 18\\.\\.\\.\\),\ + \\(21, 22\\.\\.\\.\\)\\.\\.\\.\\)\\.\\.\\.\\)" \ + "output Large_3d_Array from history" +} + +gdb_test_no_output "set print elements $elements" + +with_test_prefix "with print elements matching max-value size" { + gdb_test "print \$\$2" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33\\.\\.\\.\\)" \ + "print Large_1d_Array from history" + gdb_test -nonl "output \$\$3" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33\\.\\.\\.\\)" \ + "output Large_1d_Array from history" + + gdb_test "print \$\$2" \ + " = \\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33(?:, )\{3\}\\)(?:,\ + \\((?:, )\{3\}\\))\{3\}\\),\ + \\(\\((?:, )\{3\}\\)(?:,\ + \\((?:, )\{3\}\\))\{3\}\\)\\)" \ + "print Large_3d_Array from history" + gdb_test -nonl "output \$\$3" \ + "\\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33(?:, )\{3\}\\)(?:,\ + \\((?:, )\{3\}\\))\{3\}\\),\ + \\(\\((?:, )\{3\}\\)(?:,\ + \\((?:, )\{3\}\\))\{3\}\\)\\)" \ + "output Large_3d_Array from history" +} + +gdb_test_no_output "set max-value-size unlimited" +gdb_test_no_output "set print elements unlimited" +gdb_test_no_output "set print repeats 2" + +with_test_prefix "with unlimited print elements" { + gdb_test "print \$\$" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33,\ + \\)" \ + "print Large_1d_Array from history" + gdb_test -nonl "output \$\$2" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,\ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\ + 25, 26, 27, 28, 29, 30, 31, 32, 33,\ + \\)" \ + "output Large_1d_Array from history" + + gdb_test "print \$\$" \ + " = \\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33, \\),\ + \\( \\) \\),\ + \\(\\( \\)\ + \\)\\)" \ + "print Large_3d_Array from history" + gdb_test -nonl "output \$\$2" \ + "\\(\\(\\(1, 2, 3, 4\\), \\(5, 6, 7, 8\\),\ + \\(9, 10, 11, 12\\), \\(13, 14, 15, 16\\)\\),\ + \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\),\ + \\(\\(33, \\),\ + \\( \\) \\),\ + \\(\\( \\) \\)\\)" \ + "output Large_3d_Array from history" + + gdb_test "print \$\[2\]" \ + " = \\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\)" \ + "print available Large_3d_Array row from history" + gdb_test -nonl "output \$\$\[2\]" \ + "\\(\\(17, 18, 19, 20\\), \\(21, 22, 23, 24\\),\ + \\(25, 26, 27, 28\\), \\(29, 30, 31, 32\\)\\)" \ + "output available Large_3d_Array row from history" + + gdb_test "print \$\$\[3\]" \ + " = \\(\\(33, \\),\ + \\( \\) \\)" \ + "print partially available Large_3d_Array row from history" + gdb_test -nonl "output \$\$2\[3\]" \ + "\\(\\(33, \\),\ + \\( \\) \\)" \ + "output partially available Large_3d_Array row from history" + + # These go straigth to the inferior. + gdb_test "print \$\$2(3)" \ + " = \\(\\(33, 34, 35, 36\\), \\(37, 38, 39, 40\\),\ + \\(41, 42, 43, 44\\), \\(45, 46, 47, 48\\)\\)" \ + "print partially available Large_3d_Array row bypassing history" + gdb_test -nonl "output \$\$3(3)" \ + "\\(\\(33, 34, 35, 36\\), \\(37, 38, 39, 40\\),\ + \\(41, 42, 43, 44\\), \\(45, 46, 47, 48\\)\\)" \ + "output partially available Large_3d_Array row bypassing history" + + gdb_test "print \$\$3\[4\]" \ + " = " \ + "print unavailable Large_3d_Array row from history" + gdb_test -nonl "output \$\$4\[4\]" \ + "" \ + "output unavailable Large_3d_Array row from history" + + gdb_test "print \$\$4\[3\]\[1\]\[1\]" \ + " = 33" \ + "print available Large_3d_Array element from history" + gdb_test -nonl "output \$\$5\[3\]\[1\]\[1\]" \ + "33" \ + "output available Large_3d_Array element from history" + + gdb_test "print \$\$5\[3\]\[1\]\[2\]" \ + " = " \ + "print unavailable Large_3d_Array element from history" + gdb_test -nonl "output \$\$6\[3\]\[1\]\[2\]" \ + "" \ + "output unavailable Large_3d_Array element from history" + + gdb_test "print \$\$6\[3\]\[1\]\[1\] + \$\$6\[3\]\[1\]\[2\]" \ + "value is not available" \ + "print expression referring unavailable element from history" + gdb_test "output \$\$6\[3\]\[1\]\[1\] + \$\$6\[3\]\[1\]\[2\]" \ + "value is not available" \ + "output expression referring unavailable element from history" +} Index: src/gdb/testsuite/gdb.ada/limited-length/foo.adb =================================================================== --- /dev/null +++ src/gdb/testsuite/gdb.ada/limited-length/foo.adb @@ -0,0 +1,37 @@ +-- This testcase is part of GDB, the GNU debugger. +-- +-- 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 . + +with Pck; use Pck; + +procedure Foo is + Large_1d_Array : array (1..64) of Integer; + Large_3d_Array : array (1..4,1..4,1..4) of Integer; + Count : Integer := 1; +begin + for i in 1 .. 4 loop + for j in 1 .. 4 loop + for k in 1 .. 4 loop + Large_1d_Array (Count) := Count; + Large_3d_Array (i,j,k) := Count; + Count := Count + 1; + end loop; + end loop; + end loop; + Do_Nothing (Large_1d_Array'Address); + Do_Nothing (Large_3d_Array'Address); -- STOP +end Foo; + Index: src/gdb/testsuite/gdb.ada/limited-length/pck.adb =================================================================== --- /dev/null +++ src/gdb/testsuite/gdb.ada/limited-length/pck.adb @@ -0,0 +1,25 @@ +-- This testcase is part of GDB, the GNU debugger. +-- +-- 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 . + +package body Pck is + + procedure Do_Nothing (A : System.Address) is + begin + null; + end Do_Nothing; + +end Pck; Index: src/gdb/testsuite/gdb.ada/limited-length/pck.ads =================================================================== --- /dev/null +++ src/gdb/testsuite/gdb.ada/limited-length/pck.ads @@ -0,0 +1,21 @@ +-- This testcase is part of GDB, the GNU debugger. +-- +-- 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 . + +with System; +package Pck is + procedure Do_Nothing (A : System.Address); +end Pck; Index: src/gdb/testsuite/gdb.base/limited-length.c =================================================================== --- /dev/null +++ src/gdb/testsuite/gdb.base/limited-length.c @@ -0,0 +1,48 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright (C) 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 large_1d_array[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 +}; + +int large_2d_array[][10] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, + {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, + {20, 21, 22, 23, 24, 25, 26, 27, 28, 29}, + {30, 31, 32, 33, 34, 35, 36, 37, 38, 39}, + {40, 41, 42, 43, 44, 45, 46, 47, 48, 49}, + {50, 51, 52, 53, 54, 55, 56, 57, 58, 59}, + {60, 61, 62, 63, 64, 65, 66, 67, 68, 69}, + {70, 71, 72, 73, 74, 75, 76, 77, 78, 79}, + {80, 81, 82, 83, 84, 85, 86, 87, 88, 89}, + {90, 91, 92, 93, 94, 95, 96, 97, 98, 99} +}; + +int +main () +{ + return 0; +} Index: src/gdb/testsuite/gdb.base/limited-length.exp =================================================================== --- /dev/null +++ src/gdb/testsuite/gdb.base/limited-length.exp @@ -0,0 +1,242 @@ +# 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 GDB's limited array printing. + +standard_testfile + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} { + return -1 +} + +if {![runto_main]} { + perror "couldn't run to breakpoint" + continue +} + +with_test_prefix "with standard max-value size" { + gdb_test "print large_1d_array" \ + " = \\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,\ + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,\ + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,\ + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,\ + 96, 97, 98, 99\\\}" + gdb_test -nonl "output large_1d_array" \ + "\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,\ + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,\ + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,\ + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,\ + 96, 97, 98, 99\\\}" + gdb_test "print large_2d_array" \ + " = \\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59\\\},\ + \\\{60, 61, 62, 63, 64, 65, 66, 67, 68, 69\\\},\ + \\\{70, 71, 72, 73, 74, 75, 76, 77, 78, 79\\\},\ + \\\{80, 81, 82, 83, 84, 85, 86, 87, 88, 89\\\},\ + \\\{90, 91, 92, 93, 94, 95, 96, 97, 98, 99\\\}\\\}" + gdb_test -nonl "output large_2d_array" \ + "\\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59\\\},\ + \\\{60, 61, 62, 63, 64, 65, 66, 67, 68, 69\\\},\ + \\\{70, 71, 72, 73, 74, 75, 76, 77, 78, 79\\\},\ + \\\{80, 81, 82, 83, 84, 85, 86, 87, 88, 89\\\},\ + \\\{90, 91, 92, 93, 94, 95, 96, 97, 98, 99\\\}\\\}" +} + +# Set the max-value-size so we can only print 51 elements. +set elements 51 +set int_size [get_valueof "/d" "sizeof(large_1d_array\[0\])" "*unknown*"] +gdb_test_no_output "set max-value-size [expr $int_size * $elements]" + +with_test_prefix "with reduced max-value size" { + gdb_test "print large_1d_array" \ + "\r\nvalue requires $decimal bytes, which is more than max-value-size" + gdb_test "output large_1d_array" \ + "\r\nvalue requires $decimal bytes, which is more than max-value-size" + gdb_test "print large_2d_array" \ + "\r\nvalue requires $decimal bytes, which is more than max-value-size" + gdb_test "output large_2d_array" \ + "\r\nvalue requires $decimal bytes, which is more than max-value-size" +} + +gdb_test_no_output "set print elements 3" + +with_test_prefix "with reduced print elements" { + gdb_test "print large_1d_array" \ + " = \\\{0, 1, 2\\.\\.\\.\\\}" + gdb_test -nonl "output large_1d_array" \ + "\\\{0, 1, 2\\.\\.\\.\\\}" + + gdb_test "print \$" \ + " = \\\{0, 1, 2\\.\\.\\.\\\}" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$" \ + "\\\{0, 1, 2\\.\\.\\.\\\}" \ + "output large_1d_array from history" + + gdb_test "print large_2d_array" \ + " = \\\{\\\{0, 1, 2\\.\\.\\.\\\}, \\\{10, 11, 12\\.\\.\\.\\\},\ + \\\{20, 21, 22\\.\\.\\.\\\}\\.\\.\\.\\\}" + gdb_test -nonl "output large_2d_array" \ + "\\\{\\\{0, 1, 2\\.\\.\\.\\\}, \\\{10, 11, 12\\.\\.\\.\\\},\ + \\\{20, 21, 22\\.\\.\\.\\\}\\.\\.\\.\\\}" + + gdb_test "print \$" \ + " = \\\{\\\{0, 1, 2\\.\\.\\.\\\}, \\\{10, 11, 12\\.\\.\\.\\\},\ + \\\{20, 21, 22\\.\\.\\.\\\}\\.\\.\\.\\\}" \ + "print large_2d_array from history" + gdb_test -nonl "output \$\$" \ + "\\\{\\\{0, 1, 2\\.\\.\\.\\\}, \\\{10, 11, 12\\.\\.\\.\\\},\ + \\\{20, 21, 22\\.\\.\\.\\\}\\.\\.\\.\\\}" \ + "output large_2d_array from history" +} + +gdb_test_no_output "set print elements $elements" + +with_test_prefix "with print elements matching max-value size" { + gdb_test "print \$\$2" \ + " = \\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50\\.\\.\\.\\\}" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$3" \ + "\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50\\.\\.\\.\\\}" \ + "output large_1d_array from history" + + gdb_test "print \$\$2" \ + " = \\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50(?:, )\{9\}\\\}(?:,\ + \\\{(?:, )\{9\}\\\})\{4\}\\\}" \ + "print large_2d_array from history" + gdb_test -nonl "output \$\$3" \ + "\\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50(?:, )\{9\}\\\}(?:,\ + \\\{(?:, )\{9\}\\\})\{4\}\\\}" \ + "output large_2d_array from history" +} + +gdb_test_no_output "set max-value-size unlimited" +gdb_test_no_output "set print elements unlimited" +gdb_test_no_output "set print repeats 3" + +with_test_prefix "with unlimited print elements" { + gdb_test "print \$\$" \ + " = \\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50, \\\}" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$2" \ + "\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\ + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\ + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\ + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\ + 48, 49, 50, \\\}" \ + "output large_1d_array from history" + + gdb_test "print \$\$" \ + " = \\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50, \\\},\ + \\\{ \\\}\ + \\\}" \ + "print large_2d_array from history" + gdb_test -nonl "output \$\$2" \ + "\\\{\\\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\\\},\ + \\\{10, 11, 12, 13, 14, 15, 16, 17, 18, 19\\\},\ + \\\{20, 21, 22, 23, 24, 25, 26, 27, 28, 29\\\},\ + \\\{30, 31, 32, 33, 34, 35, 36, 37, 38, 39\\\},\ + \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\},\ + \\\{50, \\\},\ + \\\{ \\\}\ + \\\}" \ + "output large_2d_array from history" + + gdb_test "print \$\[4\]" \ + " = \\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\}" \ + "print available large_2d_array row from history" + gdb_test -nonl "output \$\$\[4\]" \ + "\\\{40, 41, 42, 43, 44, 45, 46, 47, 48, 49\\\}" \ + "output available large_2d_array row from history" + + gdb_test "print \$\$\[5\]" \ + " = \\\{50, \\\}" \ + "print partially available large_2d_array row from history" + gdb_test -nonl "output \$\$2\[5\]" \ + "\\\{50, \\\}" \ + "output partially available large_2d_array row from history" + + gdb_test "print \$\$2\[6\]" \ + " = " \ + "print unavailable large_2d_array row from history" + gdb_test -nonl "output \$\$3\[6\]" \ + "" \ + "output unavailable large_2d_array row from history" + + gdb_test "print \$\$3\[5\]\[0\]" \ + " = 50" \ + "print available large_2d_array element from history" + gdb_test -nonl "output \$\$4\[5\]\[0\]" \ + "50" \ + "output available large_2d_array element from history" + + gdb_test "print \$\$4\[5\]\[1\]" \ + " = " \ + "print unavailable large_2d_array element from history" + gdb_test -nonl "output \$\$5\[5\]\[1\]" \ + "" \ + "output unavailable large_2d_array element from history" + + gdb_test "print \$\$5\[5\]\[0\] + \$\$5\[5\]\[1\]" \ + "value is not available" \ + "print expression referring unavailable element from history" + gdb_test "output \$\$5\[5\]\[0\] + \$\$5\[5\]\[1\]" \ + "value is not available" \ + "output expression referring unavailable element from history" +} Index: src/gdb/testsuite/gdb.fortran/limited-length.exp =================================================================== --- /dev/null +++ src/gdb/testsuite/gdb.fortran/limited-length.exp @@ -0,0 +1,222 @@ +# 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 . + +# This file tests GDB's limited length array printing. + +load_lib "fortran.exp" + +if {[skip_fortran_tests]} { + continue +} + +standard_testfile .f90 + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug f90}]} { + return -1 +} + +if {![fortran_runto_main]} { + perror "Could not run to main." + continue +} + +gdb_breakpoint [gdb_get_line_number "Break Here"] +gdb_continue_to_breakpoint "stop-here" ".*Break Here.*" + +with_test_prefix "with standard max-value size" { + gdb_test "print large_4d_array" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, 51\\) \\(52, 53, 54\\)\\)\\)\ + \\(\\(\\(55, 56, 57\\) \\(58, 59, 60\\) \\(61, 62, 63\\)\\)\ + \\(\\(64, 65, 66\\) \\(67, 68, 69\\) \\(70, 71, 72\\)\\)\ + \\(\\(73, 74, 75\\) \\(76, 77, 78\\)\ + \\(79, 80, 81\\)\\)\\)\\)" + gdb_test -nonl "output large_4d_array" \ + "\\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, 51\\) \\(52, 53, 54\\)\\)\\)\ + \\(\\(\\(55, 56, 57\\) \\(58, 59, 60\\) \\(61, 62, 63\\)\\)\ + \\(\\(64, 65, 66\\) \\(67, 68, 69\\) \\(70, 71, 72\\)\\)\ + \\(\\(73, 74, 75\\) \\(76, 77, 78\\) \\(79, 80, 81\\)\\)\\)\\)" + gdb_test "print large_1d_array" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, 51, 52, 53, 54,\ + 55, 56, 57, 58, 59, 60, 61, 62, 63,\ + 64, 65, 66, 67, 68, 69, 70, 71, 72,\ + 73, 74, 75, 76, 77, 78, 79, 80, 81\\)" + gdb_test -nonl "output large_1d_array" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, 51, 52, 53, 54,\ + 55, 56, 57, 58, 59, 60, 61, 62, 63,\ + 64, 65, 66, 67, 68, 69, 70, 71, 72,\ + 73, 74, 75, 76, 77, 78, 79, 80, 81\\)" +} + +# Set the max-value-size so we can only print 50 elements. +set elements 50 +set elem_size [get_valueof "/d" "sizeof(large_1d_array(1))" "*unknown*"] +gdb_test_no_output "set max-value-size [expr $elem_size * $elements]" + +with_test_prefix "with reduced max-value size" { + gdb_test "print large_4d_array" \ + "value requires $decimal bytes, which is more than max-value-size" + gdb_test "output large_4d_array" \ + "value requires $decimal bytes, which is more than max-value-size" + gdb_test "print large_1d_array" \ + "value requires $decimal bytes, which is more than max-value-size" + gdb_test "output large_1d_array" \ + "value requires $decimal bytes, which is more than max-value-size" +} + +with_test_prefix "with reduced print -elements flag" { + gdb_test "print -elements 5 -- large_4d_array" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, \\.\\.\\.\\)\ + \\.\\.\\.\\) \\.\\.\\.\\) \\.\\.\\.\\)" + gdb_test "print -elements 5 -- large_1d_array" \ + " = \\(1, 2, 3, 4, 5, \\.\\.\\.\\)" +} + +gdb_test_no_output "set print elements 5" + +with_test_prefix "with reduced print elements" { + gdb_test "print large_4d_array" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, \\.\\.\\.\\)\ + \\.\\.\\.\\) \\.\\.\\.\\) \\.\\.\\.\\)" + gdb_test -nonl "output large_4d_array" \ + "\\(\\(\\(\\(1, 2, 3\\) \\(4, 5, \\.\\.\\.\\)\ + \\.\\.\\.\\) \\.\\.\\.\\) \\.\\.\\.\\)" + + gdb_test "print \$" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, \\.\\.\\.\\)\ + \\.\\.\\.\\) \\.\\.\\.\\) \\.\\.\\.\\)" \ + "print large_4d_array from history" + gdb_test -nonl "output \$\$" \ + "\\(\\(\\(\\(1, 2, 3\\) \\(4, 5, \\.\\.\\.\\)\ + \\.\\.\\.\\) \\.\\.\\.\\) \\.\\.\\.\\)" \ + "output large_4d_array from history" + + gdb_test "print large_1d_array" \ + " = \\(1, 2, 3, 4, 5, \\.\\.\\.\\)" + gdb_test -nonl "output large_1d_array" \ + "\\(1, 2, 3, 4, 5, \\.\\.\\.\\)" + + gdb_test "print \$" \ + " = \\(1, 2, 3, 4, 5, \\.\\.\\.\\)" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$" \ + "\\(1, 2, 3, 4, 5, \\.\\.\\.\\)" \ + "output large_1d_array from history" +} + +gdb_test_no_output "set print elements $elements" + +with_test_prefix "with print elements matching max-value size" { + gdb_test "print \$\$2" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, \\.\\.\\.\\) \\.\\.\\.\\)\\)\ + \\.\\.\\.\\)" \ + "print large_4d_array from history" + gdb_test -nonl "output \$\$3" \ + "\\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, \\.\\.\\.\\) \\.\\.\\.\\)\\)\ + \\.\\.\\.\\)" \ + "output large_4d_array from history" + + gdb_test "print \$\$2" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, \\.\\.\\.\\)" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$2" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, \\.\\.\\.\\)" \ + "output large_1d_array from history" +} + +gdb_test_no_output "set max-value-size unlimited" +gdb_test_no_output "set print elements unlimited" +gdb_test_no_output "set print repeats 2" + +with_test_prefix "with unlimited print elements" { + gdb_test "print \$\$" \ + " = \\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, \\)\ + \\(, \\)\\)\\)\ + \\(\\(\\(, \\)\ + \\) \\)\\)" \ + "print large_4d_array from history" + gdb_test -nonl "output \$\$2" \ + "\\(\\(\\(\\(1, 2, 3\\) \\(4, 5, 6\\) \\(7, 8, 9\\)\\)\ + \\(\\(10, 11, 12\\) \\(13, 14, 15\\) \\(16, 17, 18\\)\\)\ + \\(\\(19, 20, 21\\) \\(22, 23, 24\\) \\(25, 26, 27\\)\\)\\)\ + \\(\\(\\(28, 29, 30\\) \\(31, 32, 33\\) \\(34, 35, 36\\)\\)\ + \\(\\(37, 38, 39\\) \\(40, 41, 42\\) \\(43, 44, 45\\)\\)\ + \\(\\(46, 47, 48\\) \\(49, 50, \\)\ + \\(, \\)\\)\\)\ + \\(\\(\\(, \\)\ + \\) \\)\\)" \ + "output large_4d_array from history" + + gdb_test "print \$\$" \ + " = \\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, , \\)" \ + "print large_1d_array from history" + gdb_test -nonl "output \$\$2" \ + "\\(1, 2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13, 14, 15, 16, 17, 18,\ + 19, 20, 21, 22, 23, 24, 25, 26, 27,\ + 28, 29, 30, 31, 32, 33, 34, 35, 36,\ + 37, 38, 39, 40, 41, 42, 43, 44, 45,\ + 46, 47, 48, 49, 50, , \\)" \ + "output large_1d_array from history" +} Index: src/gdb/testsuite/gdb.fortran/limited-length.f90 =================================================================== --- /dev/null +++ src/gdb/testsuite/gdb.fortran/limited-length.f90 @@ -0,0 +1,39 @@ +! This testcase is part of GDB, the GNU debugger. +! +! 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 2 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 . + +program main + integer(kind=8), dimension (3, 3, 3, 3) :: large_4d_array = reshape ((/ & + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, & + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, & + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, & + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, & + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, & + 78, 79, 80, 81/), (/3, 3, 3, 3/)) + + integer(kind=8), dimension (81) :: large_1d_array = reshape ((/ & + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, & + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, & + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, & + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, & + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, & + 78, 79, 80, 81/), (/81/)) + + print *, "" + print *, "" ! Break Here + print *, large_4d_array + print *, large_1d_array +end program main Index: src/gdb/valprint.c =================================================================== --- src.orig/gdb/valprint.c +++ src/gdb/valprint.c @@ -2018,13 +2018,21 @@ value_print_array_elements (struct value UINT_MAX (unlimited). */ if (options->repeat_count_threshold < UINT_MAX) { + bool unavailable = value_entirely_unavailable (element); + bool available = value_entirely_available (element); + while (rep1 < len) { struct value *rep_elt = value_from_component_bitsize (val, elttype, rep1 * bit_stride, bit_stride); - if (!value_contents_eq (element, rep_elt)) + bool repeated = ((available + && value_entirely_available (rep_elt) + && value_contents_eq (element, rep_elt)) + || (unavailable + && value_entirely_unavailable (rep_elt))); + if (!repeated) break; ++reps; ++rep1; Index: src/gdb/value.c =================================================================== --- src.orig/gdb/value.c +++ src/gdb/value.c @@ -369,6 +369,14 @@ struct value treated pretty much the same, except not-saved registers have a different string representation and related error strings. */ std::vector optimized_out; + + /* This is only non-zero for values of TYPE_CODE_ARRAY and if the size of + the array in inferior memory is greater than max_value_size. If these + conditions are met then, when the value is loaded from the inferior + GDB will only load a portion of the array into memory, and + limited_length will be set to indicate the length in octets that were + loaded from the inferior. */ + ULONGEST limited_length = 0; }; /* See value.h. */ @@ -1046,6 +1054,93 @@ check_type_length_before_alloc (const st } } +/* When this has a value, it is used to limit the number of array elements + of an array that are loaded into memory when an array value is made + non-lazy. */ +static gdb::optional array_length_limiting_element_count; + +/* See value.h. */ +scoped_array_length_limiting::scoped_array_length_limiting (int elements) +{ + m_old_value = array_length_limiting_element_count; + array_length_limiting_element_count.emplace (elements); +} + +/* See value.h. */ +scoped_array_length_limiting::~scoped_array_length_limiting () +{ + array_length_limiting_element_count = m_old_value; +} + +/* Find the inner element type for ARRAY_TYPE. */ + +static struct type * +find_array_element_type (struct type *array_type) +{ + array_type = check_typedef (array_type); + gdb_assert (array_type->code () == TYPE_CODE_ARRAY); + + if (current_language->la_language == language_fortran) + while (array_type->code () == TYPE_CODE_ARRAY) + { + array_type = array_type->target_type (); + array_type = check_typedef (array_type); + } + else + { + array_type = array_type->target_type (); + array_type = check_typedef (array_type); + } + + return array_type; +} + +/* Return the limited length of ARRAY_TYPE, which must be of + TYPE_CODE_ARRAY. This function can only be called when the global + ARRAY_LENGTH_LIMITING_ELEMENT_COUNT has a value. + + The limited length of an array is the smallest of either (1) the total + size of the array type, or (2) the array target type multiplies by the + array_length_limiting_element_count. */ + +static ULONGEST +calculate_limited_array_length (struct type *array_type) +{ + gdb_assert (array_length_limiting_element_count.has_value ()); + + array_type = check_typedef (array_type); + gdb_assert (array_type->code () == TYPE_CODE_ARRAY); + + struct type *elm_type = find_array_element_type (array_type); + ULONGEST len = (elm_type->length () + * (*array_length_limiting_element_count)); + len = std::min (len, array_type->length ()); + + return len; +} + +/* Try to limit ourselves to only fetching the limited number of + elements. However, if this limited number of elements still + puts us over max_value_size, then we still throw an error. */ + +static bool +set_limited_array_length (struct value *val) +{ + ULONGEST limit = val->limited_length; + ULONGEST len = value_type (val)->length (); + + if (array_length_limiting_element_count.has_value ()) + len = calculate_limited_array_length (value_type (val)); + + if (limit != 0 && len > limit) + len = limit; + if (len > max_value_size) + return false; + + val->limited_length = max_value_size; + return true; +} + /* Allocate the contents of VAL if it has not been allocated yet. If CHECK_SIZE is true, then apply the usual max-value-size checks. */ @@ -1054,10 +1149,26 @@ allocate_value_contents (struct value *v { if (!val->contents) { + struct type *enclosing_type = value_enclosing_type (val); + ULONGEST len = enclosing_type->length (); + if (check_size) - check_type_length_before_alloc (val->enclosing_type); - val->contents.reset - ((gdb_byte *) xzalloc (val->enclosing_type->length ())); + { + /* If we are allocating the contents of an array, which + is greater in size than max_value_size, and there is + an element limit in effect, then we can possibly try + to load only a sub-set of the array contents into + GDB's memory. */ + if (value_type (val) == enclosing_type + && value_type (val)->code () == TYPE_CODE_ARRAY + && len > max_value_size + && set_limited_array_length (val)) + len = val->limited_length; + else + check_type_length_before_alloc (enclosing_type); + } + + val->contents.reset ((gdb_byte *) xzalloc (len)); } } @@ -1789,10 +1900,7 @@ value_copy (const value *arg, bool check struct type *encl_type = value_enclosing_type (arg); struct value *val; - if (value_lazy (arg)) - val = allocate_value_lazy (encl_type); - else - val = allocate_value (encl_type, check_size); + val = allocate_value_lazy (encl_type); val->type = arg->type; VALUE_LVAL (val) = arg->lval; val->location = arg->location; @@ -1808,17 +1916,41 @@ value_copy (const value *arg, bool check val->initialized = arg->initialized; val->unavailable = arg->unavailable; val->optimized_out = arg->optimized_out; + val->parent = arg->parent; + val->limited_length = arg->limited_length; - if (!value_lazy (val) && !value_entirely_optimized_out (val)) + if (!value_lazy (val) + && !(value_entirely_optimized_out (val) + || value_entirely_unavailable (val))) { gdb_assert (arg->contents != nullptr); - ULONGEST length = value_enclosing_type (arg)->length (); + allocate_value_contents (val, check_size); + + /* We need to handle the case where the new VAL has its content + buffer limited, but to a different length, than the original + ARG value. This all gets rather messy. */ + ULONGEST src_len, dst_len; + if (val->limited_length > 0) + dst_len = val->limited_length; + else + dst_len = value_enclosing_type (val)->length (); + + if (arg->limited_length > 0) + src_len = val->limited_length; + else + src_len = value_enclosing_type (arg)->length (); + + ULONGEST len = std::min (src_len, dst_len); + gdb::array_view val_contents + = value_contents_all_raw (val).slice (0, len); const auto &arg_view - = gdb::make_array_view (arg->contents.get (), length); - copy (arg_view, value_contents_all_raw (val)); + = gdb::make_array_view (arg->contents.get (), len); + copy (arg_view, val_contents); + + if (dst_len < src_len) + mark_value_bytes_unavailable (val, dst_len, (src_len - dst_len)); } - val->parent = arg->parent; if (VALUE_LVAL (val) == lval_computed) { const struct lval_funcs *funcs = val->location.computed.funcs; @@ -1961,20 +2093,40 @@ set_value_component_location (struct val int record_latest_value (struct value *val) { + struct type *enclosing_type = value_enclosing_type (val); + struct type *type = value_type (val); + /* We don't want this value to have anything to do with the inferior anymore. In particular, "set $1 = 50" should not affect the variable from which the value was taken, and fast watchpoints should be able to assume that a value on the value history never changes. */ if (value_lazy (val)) - value_fetch_lazy (val); + { + /* We know that this is a _huge_ array, any attempt to fetch this + is going to cause GDB to throw an error. However, to allow + the array to still be displayed we fetch its contents up to + `max_value_size' and mark anything beyond "unavailable" in + the history. */ + if (type->code () == TYPE_CODE_ARRAY + && type->length () > max_value_size + && array_length_limiting_element_count.has_value () + && enclosing_type == type + && calculate_limited_array_length (type) <= max_value_size) + val->limited_length = max_value_size; + + value_fetch_lazy (val); + } /* Don't pretend we have anything available there in the history beyond the boundaries of the value recorded. It's not like inferior memory where there is actual stuff underneath. */ - ULONGEST length = value_enclosing_type (val)->length (); + ULONGEST length = enclosing_type->length (); mark_value_bits_unavailable (val, LONGEST_MIN, 0 ^ LONGEST_MIN); mark_value_bits_unavailable (val, length * TARGET_CHAR_BIT, LONGEST_MAX - length * TARGET_CHAR_BIT); + if (val->limited_length != 0) + mark_value_bytes_unavailable (val, val->limited_length, + length - val->limited_length); /* We preserve VALUE_LVAL so that the user can find out where it was fetched from. This is a bit dubious, because then *&$1 does not just return $1 @@ -4071,10 +4223,23 @@ value_fetch_lazy_memory (struct value *v CORE_ADDR addr = value_address (val); struct type *type = check_typedef (value_enclosing_type (val)); - if (type->length ()) - read_value_memory (val, 0, value_stack (val), - addr, value_contents_all_raw (val).data (), - type_length_units (type)); + /* Figure out how much we should copy from memory. Usually, this is just + the size of the type, but, for arrays, we might only be loading a + small part of the array (this is only done for very large arrays). */ + int len = 0; + if (val->limited_length > 0) + { + gdb_assert (value_type (val)->code () == TYPE_CODE_ARRAY); + len = val->limited_length; + } + else if (type->length () > 0) + len = type_length_units (type); + + gdb_assert (len >= 0); + + if (len > 0) + read_value_memory (val, 0, value_stack (val), addr, + value_contents_all_raw (val).data (), len); } /* Helper for value_fetch_lazy when the value is in a register. */ Index: src/gdb/value.h =================================================================== --- src.orig/gdb/value.h +++ src/gdb/value.h @@ -1235,4 +1235,21 @@ extern void finalize_values (); of floating-point, fixed-point, or integer type. */ extern gdb_mpq value_to_gdb_mpq (struct value *value); +/* While an instance of this class is live, and array values that are + created, that are larger than max_value_size, will be restricted in size + to a particular number of elements. */ + +struct scoped_array_length_limiting +{ + /* Limit any large array values to only contain ELEMENTS elements. */ + scoped_array_length_limiting (int elements); + + /* Restore the previous array value limit. */ + ~scoped_array_length_limiting (); + +private: + /* Used to hold the previous array value element limit. */ + gdb::optional m_old_value; +}; + #endif /* !defined (VALUE_H) */