From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id WPJAExg5Pmqp9RgAWB0awg (envelope-from ) for ; Fri, 26 Jun 2026 04:32:24 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=SuEZr/J4; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 3269B1E024; Fri, 26 Jun 2026 04:32:24 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,HTML_MESSAGE, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [IPv6:2620:52:6:3111::32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id E45B01E024 for ; Fri, 26 Jun 2026 04:32:18 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5136B4BA2E0B for ; Fri, 26 Jun 2026 08:32:17 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5136B4BA2E0B Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=SuEZr/J4 Received: from mail-yw1-x112b.google.com (mail-yw1-x112b.google.com [IPv6:2607:f8b0:4864:20::112b]) by sourceware.org (Postfix) with ESMTPS id 599A84BA2E3E for ; Fri, 26 Jun 2026 08:31:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 599A84BA2E3E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 599A84BA2E3E Authentication-Results: sourceware.org; arc=pass smtp.remote-ip=2607:f8b0:4864:20::112b ARC-Seal: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1782462701; cv=pass; b=hE5MAQckwck0sPmSuPcExzS4hqxLue0TI8Uo4IJFQyU5awaeHaWQZ1My7JREEcZvyNCDchNwvpLhfPbbCRTCvXuiMEO2Iu/hnd+yy+PA3MwsW9qCZz+B6JzHAaViBfeu4N9O5nPe7gNzp1807+CkiOoW4+QlsVbC5T6Z+7M9c/E= ARC-Message-Signature: i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1782462701; c=relaxed/simple; bh=Z4nlFY1DUUkBA4buhr4wMl/VGRYtENc2RUg6ry/Yj3M=; h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To; b=D7npmpTLbGmgeCt0ALKHUmJOwLRxzVBG0XaH64TPu+TkKLHpgyuK1Z0HBimVL6gOvlxcNm1mRs2TUZmvWLB3fu0EX/cuquxuanie83Epw3wMWsVVtnQD7ENzj+192Se1QGpxVVoJ+1Dz9tRXwNDSweAoFSh3HB7iAO8j0OkvQI4= ARC-Authentication-Results: i=2; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=SuEZr/J4 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 599A84BA2E3E Received: by mail-yw1-x112b.google.com with SMTP id 00721157ae682-8001478c58fso577307b3.0 for ; Fri, 26 Jun 2026 01:31:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1782462701; cv=none; d=google.com; s=arc-20260327; b=AXatiOvxrAX5PlWZ/O0M2a9S20fLtx9V2uEvjY9CSid6kkYb962wntvBKQgUMP0fbu rfrlfogrJHI+F8gR6gzwwLCxF5RwNQSzxvjxUuVt/9f4V/bLhfIWiJpQKRTbC1b+W+I9 qLnArNaJv7D3TX+vqpRYHeuJmwIZNwNc8GLs+/z/3LkfjN/Y+Rr/dH5r4/HWBSg0cOoc PFju654WPcPQf9zEOyI9LiiiRkNo7wXS5l6u6H41aUGa2vunenukxgcbjVdA6tUhjgYr sU/QBnapbJjQUBnQkw+5Mh6qY3p42qhlNFb2SjaQiJg5w5jeEmr9HjvVL1aKtVobl8Sy 7xvA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=WU5n0U87o6Gbl63P0ylrftR0IoMbImTRQWHYX2S0Udw=; fh=sRq5/Xeu92++YwWMSb5Q6jMFpkzo3sGKjlz/5Ldi3sE=; b=mWpZKHQQz2WTS9AB8XpI43CvGbAKnrLBxY5rUXHdTTCO0hbtjlYG5lgEfrb33owN5o Y1XX8aUTnPHu6TQ7ccmCv88h36RUeCMS/NsZwovtdQF0QW4d68Xh9R0MMgKuB87euEVD qPnUIgpX/UtWjiMY3/MwBTXF+drzDgVp6jHZ4lO7F3nPbVVrjzXlHjqlDEfSPXivrdg5 XEmvC1EESMUBD44D3qJxpVCtJwy7VtXQOgFmorLQXCjgEAu+gqMsR3oAVmsruhgWlOLY xXgbn+1Rb72DFKxuVbMGkLd31eClNJqf7u8KV2fabxYQ40vpoOqHNojSygVDO2uRRJm8 NnKQ==; darn=sourceware.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1782462701; x=1783067501; darn=sourceware.org; h=content-type:cc:to:subject:message-id:date:from:in-reply-to :references:mime-version:from:to:cc:subject:date:message-id:reply-to :content-type; bh=WU5n0U87o6Gbl63P0ylrftR0IoMbImTRQWHYX2S0Udw=; b=SuEZr/J4VA4n9qsXZ++Iiz115Jfk4SUE+FGLXqspDJtEaoJOc3IU07Shx6Cz5Ppp3o qs5GjFLSdx1o8MXzV1RV+2tILrdKKM8yTNCS342mOfzDF4M0ePYjLldEA302LtR8wbZ/ G+R2JmjMTieudeVEd7JmsPFq6KWU20JaEgHlFK6zxkz46YulQdkRpHWNLzSJmkhaZvf1 wDdCz3O8AiG2SzZuSbwNAY/7O39WaQRAhhhL4OVpP/JxT5hb4lGjLd4BADBVReQDmpTY 3a7dY7J2lLObieKqb+KAx6PVIndDDcvWmZN0odPt0GMzHG6hlPYD63wDaD+wdPo8YxGo 3vDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782462701; x=1783067501; h=content-type:cc:to:subject:message-id:date:from:in-reply-to :references:mime-version:x-gm-gg:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to:content-type; bh=WU5n0U87o6Gbl63P0ylrftR0IoMbImTRQWHYX2S0Udw=; b=ENsjoRvWSc3cSWKChNI5dAALv0Fz2suFg3m4PRMAZCyywBlEV6ujp1IBmAK22myzXQ /lG+U6klvV+op7UGxL/9CWO6qWYmlT4Rq+tXfckFaM+Qu9jq4LqeMHkWYvqaEypchaSM CrkNoET0BUdTPE2W3lzHtn5UQynVZbBRukfejnpmqZhJ/gaJNcUAqslTuWYXHiJoMr8p 1rNuny1UfA5xh5ZvfhM5AmH+vXfmaxgDspPMkRUB0rhkeCviC8jn88MCMa6WZB0YTN0Z 8OKqGXyajD7Y5RfXjAQa1RCHw2d+cxS+lUDFF5hGZ5PI+gBi2kMK7EW7iuTmPaiAAzo8 15Nw== X-Gm-Message-State: AOJu0YzP6QffeIpld5tWA4sN51bJT4U/AAqazK7cHN3CZdpaBY2skDJT kFEooD7kkMCqGE5Ou8yy0x5gPXPuH6jhtz0mTbBLEVBiE78DsytsvRPNK8MEdJF6oyUD7OBTT4i Tu4pTB10eb1cEq0QDriPJ9+LiYUbGzpY= X-Gm-Gg: AfdE7ckdAAYE1LMTJ0EyA04Z5DGxVd9RFvxRZFNr293ocWxesK8iFIIJe8JWpIbFXjn r35gDtC8AVR0ciACr/91gHoIWi4XjrMxPbhO1vSp/2NqO7ItO6AzMwAjOzIyqylTdS8GsSDc/FD XOdlP5o7HT22bBDkkou9NkPC+8zMdlRd/Ys14KT6vwCgQYYZgmKoTLkGHsgnmPVf9oXR+d8v2db IDnbc6anKNUbsCdVcyt83xC7lU/PHwWteSZTN7oL9AAwgXuNMd5m88cVQcfdG1PW/rL1e3AiCU= X-Received: by 2002:a05:690c:c4f9:b0:7d1:bbf7:c3c2 with SMTP id 00721157ae682-80a6b1a6f6fmr37743807b3.8.1782462699962; Fri, 26 Jun 2026 01:31:39 -0700 (PDT) MIME-Version: 1.0 References: <20260618180158.2893540-1-firmiana402@gmail.com> In-Reply-To: From: Firmiana Date: Fri, 26 Jun 2026 16:31:29 +0800 X-Gm-Features: AVVi8CcaDLFq2DsRvzUlJmf8i8A4CVpVzDqyUEcCQVQTSQVcCpvJtAeUAOK9cm0 Message-ID: Subject: Re: [PATCH][PR gdb/34239][PR gdb/34299] gdb: Check bounds before reading DWARF expression operands To: Guinevere Larsen Cc: gdb-patches@sourceware.org Content-Type: multipart/alternative; boundary="0000000000000e82f5065523f0a3" X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org --0000000000000e82f5065523f0a3 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi, Thanks for the review and for testing the patch. Before preparing v2, I would like to respond to a few points. About the safe_read_* helper implementation: yes, your understanding is right. The helper saves the original pointer, advances through safe_skip_bytes to validate that the requested byte range is available, and only then calls extract_*_integer on the saved pointer. I agree that this was not obvious enough, so I will make the helper comments and/or implementation clearer in v2. On the question of reading into `uoffset` and then assigning to the real destination: that was mainly done to mirror the nearby safe_read_uleb128/safe_read_sleb128 helper style, which uses fixed output types and output pointer parameters. Based on your comment and the other review, I plan to change the new fixed-width helpers to use references, probably templated, so many call sites can read directly into `result`, `this->m_len`, or the relevant field. For DW_OP_deref_size / DW_OP_deref_type: the v1 code is intended to be equivalent to: addr_size =3D *op_ptr; op_ptr++; but with a bounds check first. safe_read_unsigned_integer keeps the original pointer for extract_unsigned_integer and uses safe_skip_bytes to validate and compute the next pointer. Since this was confusing, I will rewrite the branch more explicitly in v2. I will also switch the testcase loop to foreach_with_prefix. Thanks, Jielun On Wed, Jun 24, 2026 at 2:56=E2=80=AFAM Guinevere Larsen wrote: > On 6/18/26 3:01 PM, Jielun Wu wrote: > > Some DWARF expression opcodes read fixed-width operands or block payloa= ds > > from the expression buffer before checking that the bytes are available= . > > With a malformed expression, this can read past the end of the expressi= on > > buffer. > > > > Add helpers that validate fixed-width integer reads and block payload > > skips, and use them in dwarf_expr_context::execute_stack_op. Also guar= d > > the nested DW_OP_entry_value parser before reading the following opcode= . > > > > Add a DWARF assembler test that exercises truncated operands for these > > opcodes. > > > > Tested on x86_64-linux. > > > > Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=3D34239 > > Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=3D34299 > > --- > > Hi! Thanks for working on this! > > I'm not too familiar with the dwarf parser, so I can only do a > superficial review. Most of my comments are questions and nitpicks, I > don't think you necessarily need to send a new version just from this > review. > > I have tested this and see no regressions, so feel free to add my test > tag to the git trailers > > Tested-By: Guinevere Larsen > > > gdb/dwarf2/expr.c | 166 +++++++++------ > > .../gdb.dwarf2/dw2-bad-dwarf-expr-bounds.exp | 190 +++++++++++++++++= + > > 2 files changed, 300 insertions(+), 56 deletions(-) > > create mode 100644 > gdb/testsuite/gdb.dwarf2/dw2-bad-dwarf-expr-bounds.exp > > > > diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c > > index c71d4725b03..ead918388a4 100644 > > --- a/gdb/dwarf2/expr.c > > +++ b/gdb/dwarf2/expr.c > > @@ -1370,7 +1370,45 @@ safe_skip_leb128 (const gdb_byte *buf, const > gdb_byte *buf_end) > > error (_("DWARF expression error: ran off end of buffer reading > leb128 value")); > > return buf; > > } > > - > > + > > +/* Helper to skip BYTES bytes or throw an error. */ > > + > > +static const gdb_byte * > > +safe_skip_bytes (const gdb_byte *buf, const gdb_byte *buf_end, > > + ULONGEST bytes) > > +{ > > + if (buf > buf_end || bytes > (ULONGEST) (buf_end - buf)) > > + error (_("DWARF expression error: ran off end of buffer reading > bytes")); > > + return buf + bytes; > > +} > > + > > +/* Helper to read a fixed-width unsigned integer or throw an error. *= / > > + > > +static const gdb_byte * > > +safe_read_unsigned_integer (const gdb_byte *buf, const gdb_byte > *buf_end, > > + int len, bfd_endian byte_order, uint64_t *r) > > +{ > > + gdb_assert (len >=3D 0); > > + > > + const gdb_byte *data =3D buf; > > + buf =3D safe_skip_bytes (buf, buf_end, len); > > + *r =3D extract_unsigned_integer (data, len, byte_order); > > + return buf; > > Oh, ok, it took me a while of thinking but I think I now understand why > you wrote it like this. > > You advance the buffer first to use that as a check that it is possible > to read that many bytes from the buffer, instead of needing to double up > on the if condition, right? > > If so, I think it would be nice to have a comment explaining it, because > I went through 2 incorrect explanations before reaching that conclusion. > > > +} > > + > > +/* Helper to read a fixed-width signed integer or throw an error. */ > > + > > +static const gdb_byte * > > +safe_read_signed_integer (const gdb_byte *buf, const gdb_byte *buf_end= , > > + int len, bfd_endian byte_order, int64_t *r) > > +{ > > + gdb_assert (len >=3D 0); > > + > > + const gdb_byte *data =3D buf; > > + buf =3D safe_skip_bytes (buf, buf_end, len); > > + *r =3D extract_signed_integer (data, len, byte_order); > > + return buf; > Similar comment as above > > +} > > > > /* Check that the current operator is either at the end of an > > expression, or that it is followed by a composition operator or by > > @@ -1478,7 +1516,7 @@ dwarf_block_to_dwarf_reg_deref > (gdb::array_view block, > > if (buf =3D=3D NULL) > > return -1; > > if ((int) dwarf_reg !=3D dwarf_reg) > > - return -1; > > + return -1; > > } > > else > > return -1; > > @@ -1488,6 +1526,8 @@ dwarf_block_to_dwarf_reg_deref > (gdb::array_view block, > > return -1; > > if (offset !=3D 0) > > return -1; > > + if (buf >=3D buf_end) > > + return -1; > > > > if (*buf =3D=3D DW_OP_deref) > > { > > @@ -1498,7 +1538,7 @@ dwarf_block_to_dwarf_reg_deref > (gdb::array_view block, > > { > > buf++; > > if (buf >=3D buf_end) > > - return -1; > > + return -1; > > *deref_size_return =3D *buf++; > > } > > else > > @@ -1688,9 +1728,10 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > break; > > > > case DW_OP_addr: > > - result =3D extract_unsigned_integer (op_ptr, > > - this->m_addr_size, > byte_order); > > - op_ptr +=3D this->m_addr_size; > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, > > + this->m_addr_size, > > + byte_order, &uoffset); > > Why not just send "&result" as the parameter here, instead of &uoffset > > Same question for all the occurrences below > > > + result =3D uoffset; > > /* Some versions of GCC emit DW_OP_addr before > > DW_OP_GNU_push_tls_address. In this case the value is an > > index, not an address. We don't support things like > > @@ -1723,44 +1764,52 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > break; > > > > case DW_OP_const1u: > > - result =3D extract_unsigned_integer (op_ptr, 1, byte_order); > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, 1, > > + byte_order, &uoffset); > > + result =3D uoffset; > > result_val =3D value_from_ulongest (address_type, result); > > - op_ptr +=3D 1; > > break; > > case DW_OP_const1s: > > - result =3D extract_signed_integer (op_ptr, 1, byte_order); > > + op_ptr =3D safe_read_signed_integer (op_ptr, op_end, 1, > > + byte_order, &offset); > > + result =3D offset; > > result_val =3D value_from_ulongest (address_type, result); > > - op_ptr +=3D 1; > > break; > > case DW_OP_const2u: > > - result =3D extract_unsigned_integer (op_ptr, 2, byte_order); > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, 2, > > + byte_order, &uoffset); > > + result =3D uoffset; > > result_val =3D value_from_ulongest (address_type, result); > > - op_ptr +=3D 2; > > break; > > case DW_OP_const2s: > > - result =3D extract_signed_integer (op_ptr, 2, byte_order); > > + op_ptr =3D safe_read_signed_integer (op_ptr, op_end, 2, > > + byte_order, &offset); > > + result =3D offset; > > result_val =3D value_from_ulongest (address_type, result); > > - op_ptr +=3D 2; > > break; > > case DW_OP_const4u: > > - result =3D extract_unsigned_integer (op_ptr, 4, byte_order); > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, 4, > > + byte_order, &uoffset); > > + result =3D uoffset; > > result_val =3D value_from_ulongest (address_type, result); > > - op_ptr +=3D 4; > > break; > > case DW_OP_const4s: > > - result =3D extract_signed_integer (op_ptr, 4, byte_order); > > + op_ptr =3D safe_read_signed_integer (op_ptr, op_end, 4, > > + byte_order, &offset); > > + result =3D offset; > > result_val =3D value_from_ulongest (address_type, result); > > - op_ptr +=3D 4; > > break; > > case DW_OP_const8u: > > - result =3D extract_unsigned_integer (op_ptr, 8, byte_order); > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, 8, > > + byte_order, &uoffset); > > + result =3D uoffset; > > result_val =3D value_from_ulongest (address_type, result); > > - op_ptr +=3D 8; > > break; > > case DW_OP_const8s: > > - result =3D extract_signed_integer (op_ptr, 8, byte_order); > > + op_ptr =3D safe_read_signed_integer (op_ptr, op_end, 8, > > + byte_order, &offset); > > + result =3D offset; > > result_val =3D value_from_ulongest (address_type, result); > > - op_ptr +=3D 8; > > break; > > case DW_OP_constu: > > op_ptr =3D safe_read_uleb128 (op_ptr, op_end, &uoffset); > > @@ -1836,12 +1885,10 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > uint64_t len; > > > > op_ptr =3D safe_read_uleb128 (op_ptr, op_end, &len); > > - if (op_ptr + len > op_end) > > - error (_("DW_OP_implicit_value: too few bytes available."))= ; > > this->m_len =3D len; > > this->m_data =3D op_ptr; > > this->m_location =3D DWARF_VALUE_LITERAL; > > - op_ptr +=3D len; > > + op_ptr =3D safe_skip_bytes (op_ptr, op_end, len); > > dwarf_expr_require_composition (op_ptr, op_end, > > "DW_OP_implicit_value"); > > } > > @@ -1861,9 +1908,10 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > int ref_addr_size =3D this->m_per_cu->ref_addr_size (); > > > > /* The referred-to DIE of sect_offset kind. */ > > - this->m_len =3D extract_unsigned_integer (op_ptr, ref_addr_si= ze, > > - byte_order); > > - op_ptr +=3D ref_addr_size; > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, > > + ref_addr_size, byte_orde= r, > > + &uoffset); > > + this->m_len =3D uoffset; > Again, why not send "&this->m_len" ? > > > > /* The byte offset into the data. */ > > op_ptr =3D safe_read_sleb128 (op_ptr, op_end, &len); > > @@ -1972,7 +2020,9 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > goto no_push; > > > > case DW_OP_pick: > > - offset =3D *op_ptr++; > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, 1, > > + byte_order, &uoffset); > > + offset =3D uoffset; > > result_val =3D fetch (offset); > > in_stack_memory =3D fetch_in_stack_memory (offset); > > break; > > @@ -2016,7 +2066,13 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > case DW_OP_deref_type: > > case DW_OP_GNU_deref_type: > > { > > - int addr_size =3D (op =3D=3D DW_OP_deref ? this->m_addr_size = : > *op_ptr++); > > + int addr_size =3D this->m_addr_size; > > + if (op !=3D DW_OP_deref) > > + { > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, 1, > > + byte_order, &uoffset= ); > > + addr_size =3D uoffset; > > Maybe I'm missing something, but this seems like an incorrect change? > > It seems like you should call safe_skip_bytes instead of > read_unsigned_integer, and assign addr_size to *op_ptr? > > > + } > > CORE_ADDR addr =3D fetch_address (0); > > struct type *type; > > > > @@ -2249,8 +2305,8 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > break; > > > > case DW_OP_skip: > > - offset =3D extract_signed_integer (op_ptr, 2, byte_order); > > - op_ptr +=3D 2; > > + op_ptr =3D safe_read_signed_integer (op_ptr, op_end, 2, byte_or= der, > > + &offset); > > op_ptr +=3D offset; > This should also use safe_skip_bytes > > goto no_push; > > > > @@ -2258,8 +2314,8 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > { > > struct value *val; > > > > - offset =3D extract_signed_integer (op_ptr, 2, byte_order); > > - op_ptr +=3D 2; > > + op_ptr =3D safe_read_signed_integer (op_ptr, op_end, 2, > byte_order, > > + &offset); > > val =3D fetch (0); > > dwarf_require_integral (val->type ()); > > if (value_as_long (val) !=3D 0) > > @@ -2313,18 +2369,18 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > > > case DW_OP_call2: > > { > > - cu_offset cu_off > > - =3D (cu_offset) extract_unsigned_integer (op_ptr, 2, > byte_order); > > - op_ptr +=3D 2; > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, 2, > > + byte_order, &uoffset); > > + cu_offset cu_off =3D (cu_offset) uoffset; > > this->dwarf_call (cu_off); > > } > > goto no_push; > > > > case DW_OP_call4: > > { > > - cu_offset cu_off > > - =3D (cu_offset) extract_unsigned_integer (op_ptr, 4, > byte_order); > > - op_ptr +=3D 4; > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, 4, > > + byte_order, &uoffset); > > + cu_offset cu_off =3D (cu_offset) uoffset; > > this->dwarf_call (cu_off); > > } > > goto no_push; > > @@ -2334,11 +2390,10 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > ensure_have_per_cu (this->m_per_cu, > "DW_OP_GNU_variable_value"); > > int ref_addr_size =3D this->m_per_cu->ref_addr_size (); > > > > - sect_offset sect_off > > - =3D (sect_offset) extract_unsigned_integer (op_ptr, > > - ref_addr_size, > > - byte_order); > > - op_ptr +=3D ref_addr_size; > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, > > + ref_addr_size, byte_orde= r, > > + &uoffset); > > + sect_offset sect_off =3D (sect_offset) uoffset; > > result_val =3D sect_variable_value (sect_off, this->m_per_cu, > > this->m_per_objfile); > > result_val =3D value_cast (address_type, result_val); > > @@ -2353,15 +2408,13 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > union call_site_parameter_u kind_u; > > > > op_ptr =3D safe_read_uleb128 (op_ptr, op_end, &len); > > - if (op_ptr + len > op_end) > > - error (_("DW_OP_entry_value: too few bytes available.")); > > + const gdb_byte *expr_ptr =3D op_ptr; > > + op_ptr =3D safe_skip_bytes (op_ptr, op_end, len); > > > > - auto entry_value_expr =3D gdb::make_array_view (op_ptr, len); > > + auto entry_value_expr =3D gdb::make_array_view (expr_ptr, len= ); > > kind_u.dwarf_reg =3D dwarf_block_to_dwarf_reg (entry_value_ex= pr); > > if (kind_u.dwarf_reg !=3D -1) > > { > > - op_ptr +=3D len; > > - > > if (trivial_entry_value (this->m_frame)) > > { > > /* We can assume that DW_OP_entry_value (expr) =3D=3D= expr. > > @@ -2384,7 +2437,6 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > { > > if (deref_size =3D=3D -1) > > deref_size =3D this->m_addr_size; > > - op_ptr +=3D len; > > > > if (trivial_entry_value (this->m_frame)) > > { > > @@ -2410,9 +2462,9 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > { > > union call_site_parameter_u kind_u; > > > > - kind_u.param_cu_off > > - =3D (cu_offset) extract_unsigned_integer (op_ptr, 4, > byte_order); > > - op_ptr +=3D 4; > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, 4, > > + byte_order, &uoffset); > > + kind_u.param_cu_off =3D (cu_offset) uoffset; > > this->push_dwarf_reg_entry_value > (CALL_SITE_PARAMETER_PARAM_OFFSET, > > kind_u, > > -1 /* deref_size */); > > @@ -2429,9 +2481,11 @@ dwarf_expr_context::execute_stack_op > (gdb::array_view expr) > > op_ptr =3D safe_read_uleb128 (op_ptr, op_end, &uoffset); > > cu_offset type_die_cu_off =3D (cu_offset) uoffset; > > > > - n =3D *op_ptr++; > > + op_ptr =3D safe_read_unsigned_integer (op_ptr, op_end, 1, > byte_order, > > + &uoffset); > > + n =3D uoffset; > > data =3D op_ptr; > > - op_ptr +=3D n; > > + op_ptr =3D safe_skip_bytes (op_ptr, op_end, n); > > > > type =3D get_base_type (type_die_cu_off); > > > > diff --git a/gdb/testsuite/gdb.dwarf2/dw2-bad-dwarf-expr-bounds.exp > b/gdb/testsuite/gdb.dwarf2/dw2-bad-dwarf-expr-bounds.exp > > new file mode 100644 > > index 00000000000..7f5fa22388d > > --- /dev/null > > +++ b/gdb/testsuite/gdb.dwarf2/dw2-bad-dwarf-expr-bounds.exp > > @@ -0,0 +1,190 @@ > > +# Copyright 2026 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 malformed DWARF expressions whose opcodes have truncated > operands. > > + > > +load_lib dwarf.exp > > + > > +require dwarf2_support > > + > > +standard_testfile main.c -dw.S > > + > > +set asm_file [standard_output_file $srcfile2] > > +Dwarf::assemble $asm_file { > > + global srcfile > > + > > + declare_labels int_label > > + > > + cu {label cu_label} { > > + DW_TAG_compile_unit { > > + DW_AT_name $srcfile > > + DW_AT_language @DW_LANG_C > > + } { > > + int_label: DW_TAG_base_type { > > + DW_AT_name "int" > > + DW_AT_encoding @DW_ATE_signed > > + DW_AT_byte_size 4 DW_FORM_sdata > > + } > > + > > + foreach {var op} { > > + truncated_addr DW_OP_addr > > + truncated_const1u DW_OP_const1u > > + truncated_const1s DW_OP_const1s > > + truncated_const2u DW_OP_const2u > > + truncated_const2s DW_OP_const2s > > + truncated_const4u DW_OP_const4u > > + truncated_const4s DW_OP_const4s > > + truncated_const8u DW_OP_const8u > > + truncated_const8s DW_OP_const8s > > + truncated_implicit_pointer DW_OP_implicit_pointer > > + truncated_gnu_implicit_pointer DW_OP_GNU_implicit_pointer > > + truncated_pick DW_OP_pick > > + truncated_deref_size DW_OP_deref_size > > + truncated_deref_type DW_OP_deref_type > > + truncated_gnu_deref_type DW_OP_GNU_deref_type > > + truncated_skip DW_OP_skip > > + truncated_bra DW_OP_bra > > + truncated_parameter_ref DW_OP_GNU_parameter_ref > > + } { > > + DW_TAG_variable { > > + DW_AT_name $var > > + DW_AT_type :$int_label > > + DW_AT_location { > > + _op .byte $Dwarf::_constants($op) $op > > + } SPECIAL_expr > > + } > > + } > > + > > + DW_TAG_variable { > > + DW_AT_name "truncated_implicit_value" > > + DW_AT_type :$int_label > > + DW_AT_location { > > + _op .byte $Dwarf::_constants(DW_OP_implicit_value) \ > > + DW_OP_implicit_value > > + _op .uleb128 4 "implicit value length" > > + _op .2byte 0 "truncated implicit value bytes" > > + } SPECIAL_expr > > + } > > + > > + DW_TAG_variable { > > + DW_AT_name "truncated_entry_value" > > + DW_AT_type :$int_label > > + DW_AT_location { > > + _op .byte $Dwarf::_constants(DW_OP_entry_value) \ > > + DW_OP_entry_value > > + _op .uleb128 4 "entry value expression length" > > + _op .2byte 0 "truncated entry value expression" > > + } SPECIAL_expr > > + } > > + > > + DW_TAG_variable { > > + DW_AT_name "truncated_gnu_entry_value" > > + DW_AT_type :$int_label > > + DW_AT_location { > > + _op .byte $Dwarf::_constants(DW_OP_GNU_entry_value) \ > > + DW_OP_GNU_entry_value > > + _op .uleb128 4 "entry value expression length" > > + _op .2byte 0 "truncated entry value expression" > > + } SPECIAL_expr > > + } > > + > > + DW_TAG_variable { > > + DW_AT_name "truncated_const_type_size" > > + DW_AT_type :$int_label > > + DW_AT_location { > > + _op .byte $Dwarf::_constants(DW_OP_const_type) \ > > + DW_OP_const_type > > + _op .uleb128 "$int_label - $cu_label" "type DIE offse= t" > > + } SPECIAL_expr > > + } > > + > > + DW_TAG_variable { > > + DW_AT_name "truncated_const_type_payload" > > + DW_AT_type :$int_label > > + DW_AT_location { > > + _op .byte $Dwarf::_constants(DW_OP_const_type) \ > > + DW_OP_const_type > > + _op .uleb128 "$int_label - $cu_label" "type DIE offse= t" > > + _op .byte 4 "constant block length" > > + _op .2byte 0 "truncated constant block" > > + } SPECIAL_expr > > + } > > + > > + DW_TAG_variable { > > + DW_AT_name "truncated_gnu_const_type_size" > > + DW_AT_type :$int_label > > + DW_AT_location { > > + _op .byte $Dwarf::_constants(DW_OP_GNU_const_type) \ > > + DW_OP_GNU_const_type > > + _op .uleb128 "$int_label - $cu_label" "type DIE offse= t" > > + } SPECIAL_expr > > + } > > + > > + DW_TAG_variable { > > + DW_AT_name "truncated_gnu_const_type_payload" > > + DW_AT_type :$int_label > > + DW_AT_location { > > + _op .byte $Dwarf::_constants(DW_OP_GNU_const_type) \ > > + DW_OP_GNU_const_type > > + _op .uleb128 "$int_label - $cu_label" "type DIE offse= t" > > + _op .byte 4 "constant block length" > > + _op .2byte 0 "truncated constant block" > > + } SPECIAL_expr > > + } > > + } > > + } > > +} > > + > > +if {[prepare_for_testing "failed to prepare" ${testfile} \ > > + [list $srcfile $asm_file] nodebug]} { > > + return > > +} > > + > > +if {![runto_main]} { > > + return > > +} > > + > > +foreach var { > > + truncated_addr > > + truncated_const1u > > + truncated_const1s > > + truncated_const2u > > + truncated_const2s > > + truncated_const4u > > + truncated_const4s > > + truncated_const8u > > + truncated_const8s > > + truncated_implicit_value > > + truncated_implicit_pointer > > + truncated_gnu_implicit_pointer > > + truncated_pick > > + truncated_deref_size > > + truncated_deref_type > > + truncated_gnu_deref_type > > + truncated_skip > > + truncated_bra > > + truncated_entry_value > > + truncated_gnu_entry_value > > + truncated_parameter_ref > > + truncated_const_type_size > > + truncated_const_type_payload > > + truncated_gnu_const_type_size > > + truncated_gnu_const_type_payload > > +} { > > + with_test_prefix $var { > There exists a "foreach_with_prefix", that does basically what you did > here. > > + gdb_test "print $var" \ > > + ".*DWARF expression error: ran off end of buffer reading .*" > > + } > > +} > > > -- > Cheers, > Guinevere Larsen > it/its > she/her (deprecated) > > --0000000000000e82f5065523f0a3 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable

Hi,

Thanks for the review and for testing the p= atch.

Before preparing v2, I would like to respond to a few points.<= br>
About the safe_read_* helper implementation: yes, your understanding= is
right.=C2=A0 The helper saves the original pointer, advances through=
safe_skip_bytes to validate that the requested byte range is available,=
and only then calls extract_*_integer on the saved pointer.=C2=A0 I agr= ee that
this was not obvious enough, so I will make the helper comments = and/or
implementation clearer in v2.

On the question of reading i= nto `uoffset` and then assigning to the real
destination: that was mainl= y done to mirror the nearby
safe_read_uleb128/safe_read_sleb128 helper s= tyle, which uses fixed output
types and output pointer parameters.=C2=A0= Based on your comment and the other
review, I plan to change the new fi= xed-width helpers to use references,
probably templated, so many call si= tes can read directly into `result`,
`this->m_len`, or the relevant f= ield.

For DW_OP_deref_size / DW_OP_deref_type: the v1 code is intend= ed to be
equivalent to:

=C2=A0 addr_size =3D *op_ptr;
=C2=A0 o= p_ptr++;

but with a bounds check first. =C2=A0safe_read_unsigned_int= eger keeps the
original pointer for extract_unsigned_integer and uses sa= fe_skip_bytes to
validate and compute the next pointer.=C2=A0 Since this= was confusing, I will
rewrite the branch more explicitly in v2.

= I will also switch the testcase loop to foreach_wit= h_prefix.

Thanks,
Jielun


On Wed, Jun= 24, 2026 at 2:56=E2=80=AFAM Guinevere Larsen <guinevere@redhat.com> wrote:
On 6/18/26 3:01 PM, Jielun Wu wrote:
> Some DWARF expression opcodes read fixed-width operands or block paylo= ads
> from the expression buffer before checking that the bytes are availabl= e.
> With a malformed expression, this can read past the end of the express= ion
> buffer.
>
> Add helpers that validate fixed-width integer reads and block payload<= br> > skips, and use them in dwarf_expr_context::execute_stack_op.=C2=A0 Als= o guard
> the nested DW_OP_entry_value parser before reading the following opcod= e.
>
> Add a DWARF assembler test that exercises truncated operands for these=
> opcodes.
>
> Tested on x86_64-linux.
>
> Bug: https://sourceware.org/bugzilla/sho= w_bug.cgi?id=3D34239
> Bug: https://sourceware.org/bugzilla/sho= w_bug.cgi?id=3D34299
> ---

Hi! Thanks for working on this!

I'm not too familiar with the dwarf parser, so I can only do a
superficial review. Most of my comments are questions and nitpicks, I
don't think you necessarily need to send a new version just from this <= br> review.

I have tested this and see no regressions, so feel free to add my test
tag to the git trailers

Tested-By: Guinevere Larsen <guinevere@redhat.com>

>=C2=A0 =C2=A0gdb/dwarf2/expr.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| 166 ++++++= +++------
>=C2=A0 =C2=A0.../gdb.dwarf2/dw2-bad-dwarf-expr-bounds.exp=C2=A0 | 190 += +++++++++++++++++
>=C2=A0 =C2=A02 files changed, 300 insertions(+), 56 deletions(-)
>=C2=A0 =C2=A0create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-bad-dwarf-= expr-bounds.exp
>
> diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
> index c71d4725b03..ead918388a4 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -1370,7 +1370,45 @@ safe_skip_leb128 (const gdb_byte *buf, const gd= b_byte *buf_end)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0error (_("DWARF expression error: ran o= ff end of buffer reading leb128 value"));
>=C2=A0 =C2=A0 =C2=A0return buf;
>=C2=A0 =C2=A0}
> -=0C
> +
> +/* Helper to skip BYTES bytes or throw an error.=C2=A0 */
> +
> +static const gdb_byte *
> +safe_skip_bytes (const gdb_byte *buf, const gdb_byte *buf_end,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ULONGEST bytes)
> +{
> +=C2=A0 if (buf > buf_end || bytes > (ULONGEST) (buf_end - buf))=
> +=C2=A0 =C2=A0 error (_("DWARF expression error: ran off end of b= uffer reading bytes"));
> +=C2=A0 return buf + bytes;
> +}
> +
> +/* Helper to read a fixed-width unsigned integer or throw an error.= =C2=A0 */
> +
> +static const gdb_byte *
> +safe_read_unsigned_integer (const gdb_byte *buf, const gdb_byte *buf_= end,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0int len, bfd_endian byte_order, uint64_t *r)
> +{
> +=C2=A0 gdb_assert (len >=3D 0);
> +
> +=C2=A0 const gdb_byte *data =3D buf;
> +=C2=A0 buf =3D safe_skip_bytes (buf, buf_end, len);
> +=C2=A0 *r =3D extract_unsigned_integer (data, len, byte_order);
> +=C2=A0 return buf;

Oh, ok, it took me a while of thinking but I think I now understand why you wrote it like this.

You advance the buffer first to use that as a check that it is possible to read that many bytes from the buffer, instead of needing to double up on the if condition, right?

If so, I think it would be nice to have a comment explaining it, because I went through 2 incorrect explanations before reaching that conclusion.
> +}
> +
> +/* Helper to read a fixed-width signed integer or throw an error.=C2= =A0 */
> +
> +static const gdb_byte *
> +safe_read_signed_integer (const gdb_byte *buf, const gdb_byte *buf_en= d,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0int len, bfd_endian byte_order, int64_t *r)
> +{
> +=C2=A0 gdb_assert (len >=3D 0);
> +
> +=C2=A0 const gdb_byte *data =3D buf;
> +=C2=A0 buf =3D safe_skip_bytes (buf, buf_end, len);
> +=C2=A0 *r =3D extract_signed_integer (data, len, byte_order);
> +=C2=A0 return buf;
Similar comment as above
> +}
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0/* Check that the current operator is either at the end of= an
>=C2=A0 =C2=A0 =C2=A0 expression, or that it is followed by a compositio= n operator or by
> @@ -1478,7 +1516,7 @@ dwarf_block_to_dwarf_reg_deref (gdb::array_view&= lt;const gdb_byte> block,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (buf =3D=3D NULL)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if ((int) dwarf_reg !=3D dwarf_reg) > -=C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
> +=C2=A0 =C2=A0 =C2=A0return -1;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0 =C2=A0else
>=C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
> @@ -1488,6 +1526,8 @@ dwarf_block_to_dwarf_reg_deref (gdb::array_view&= lt;const gdb_byte> block,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
>=C2=A0 =C2=A0 =C2=A0if (offset !=3D 0)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
> +=C2=A0 if (buf >=3D buf_end)
> +=C2=A0 =C2=A0 return -1;
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0if (*buf =3D=3D DW_OP_deref)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0{
> @@ -1498,7 +1538,7 @@ dwarf_block_to_dwarf_reg_deref (gdb::array_view&= lt;const gdb_byte> block,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0{
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0buf++;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (buf >=3D buf_end)
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0return -1;
> +=C2=A0 =C2=A0 =C2=A0return -1;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*deref_size_return =3D *buf++;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0 =C2=A0else
> @@ -1688,9 +1728,10 @@ dwarf_expr_context::execute_stack_op (gdb::arra= y_view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_addr:
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D extract_unsigned_integer (op_pt= r,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 this->m_addr_size, byte_order);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D this->m_addr_size;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integer (op_= ptr, op_end,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 this->m_addr_size,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 byte_order, &uoffset);

Why not just send "&result" as the parameter here, instead of= &uoffset

Same question for all the occurrences below

> +=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D uoffset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Some versions of GCC emit DW_OP_ad= dr before
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 DW_OP_GNU_push_tls_address.= =C2=A0 In this case the value is an
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 index, not an address.=C2=A0 = We don't support things like
> @@ -1723,44 +1764,52 @@ dwarf_expr_context::execute_stack_op (gdb::arr= ay_view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_const1u:
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D extract_unsigned_integer (op_pt= r, 1, byte_order);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integer (op_= ptr, op_end, 1,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 byte_order, &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D uoffset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result_val =3D value_from_ulongest (a= ddress_type, result);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 1;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_const1s:
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D extract_signed_integer (op_ptr,= 1, byte_order);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_signed_integer (op_pt= r, op_end, 1,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 byte_order, &offset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D offset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result_val =3D value_from_ulongest (a= ddress_type, result);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 1;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_const2u:
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D extract_unsigned_integer (op_pt= r, 2, byte_order);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integer (op_= ptr, op_end, 2,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 byte_order, &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D uoffset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result_val =3D value_from_ulongest (a= ddress_type, result);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 2;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_const2s:
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D extract_signed_integer (op_ptr,= 2, byte_order);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_signed_integer (op_pt= r, op_end, 2,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 byte_order, &offset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D offset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result_val =3D value_from_ulongest (a= ddress_type, result);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 2;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_const4u:
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D extract_unsigned_integer (op_pt= r, 4, byte_order);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integer (op_= ptr, op_end, 4,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 byte_order, &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D uoffset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result_val =3D value_from_ulongest (a= ddress_type, result);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 4;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_const4s:
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D extract_signed_integer (op_ptr,= 4, byte_order);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_signed_integer (op_pt= r, op_end, 4,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 byte_order, &offset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D offset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result_val =3D value_from_ulongest (a= ddress_type, result);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 4;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_const8u:
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D extract_unsigned_integer (op_pt= r, 8, byte_order);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integer (op_= ptr, op_end, 8,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 byte_order, &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D uoffset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result_val =3D value_from_ulongest (a= ddress_type, result);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 8;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_const8s:
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D extract_signed_integer (op_ptr,= 8, byte_order);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_signed_integer (op_pt= r, op_end, 8,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 byte_order, &offset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0result =3D offset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result_val =3D value_from_ulongest (a= ddress_type, result);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 8;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_constu:
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_uleb128 (op_ptr,= op_end, &uoffset);
> @@ -1836,12 +1885,10 @@ dwarf_expr_context::execute_stack_op (gdb::arr= ay_view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint64_t len;
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_uleb128 (= op_ptr, op_end, &len);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (op_ptr + len > op_end)
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error (_("DW_OP_implici= t_value: too few bytes available."));
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0this->m_len =3D len;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0this->m_data =3D op_ptr; >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0this->m_location =3D DWARF_= VALUE_LITERAL;
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D len;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_skip_bytes (op_ptr,= op_end, len);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dwarf_expr_require_composition= (op_ptr, op_end,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0"DW_OP_implicit_value");
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> @@ -1861,9 +1908,10 @@ dwarf_expr_context::execute_stack_op (gdb::arra= y_view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int ref_addr_size =3D this->= ;m_per_cu->ref_addr_size ();
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* The referred-to DIE of sect= _offset kind.=C2=A0 */
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0this->m_len =3D extract_unsigned= _integer (op_ptr, ref_addr_size,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0byte_order);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D ref_addr_size;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integ= er (op_ptr, op_end,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 ref_addr_size, byte_order,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0this->m_len =3D uoffset;
Again, why not send "&this->m_len" ?
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* The byte offset into the da= ta.=C2=A0 */
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_sleb128 (= op_ptr, op_end, &len);
> @@ -1972,7 +2020,9 @@ dwarf_expr_context::execute_stack_op (gdb::array= _view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto no_push;
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_pick:
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0offset =3D *op_ptr++;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integer (op_= ptr, op_end, 1,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 byte_order, &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0offset =3D uoffset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result_val =3D fetch (offset);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0in_stack_memory =3D fetch_in_stack_me= mory (offset);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
> @@ -2016,7 +2066,13 @@ dwarf_expr_context::execute_stack_op (gdb::arra= y_view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_deref_type:
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_GNU_deref_type:
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int addr_size =3D (op =3D=3D DW_OP_= deref ? this->m_addr_size : *op_ptr++);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int addr_size =3D this->m_addr_s= ize;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (op !=3D DW_OP_deref)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_= unsigned_integer (op_ptr, op_end, 1,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 byte_order, &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0addr_size =3D uoffset= ;

Maybe I'm missing something, but this seems like an incorrect change?
It seems like you should call safe_skip_bytes instead of
read_unsigned_integer, and assign addr_size to *op_ptr?

> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0CORE_ADDR addr =3D fetch_addre= ss (0);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct type *type;
>=C2=A0 =C2=A0
> @@ -2249,8 +2305,8 @@ dwarf_expr_context::execute_stack_op (gdb::array= _view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_skip:
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0offset =3D extract_signed_integer (op_ptr,= 2, byte_order);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 2;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_signed_integer (op_pt= r, op_end, 2, byte_order,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 &offset);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D offset;
This should also use safe_skip_bytes
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto no_push;
>=C2=A0 =C2=A0
> @@ -2258,8 +2314,8 @@ dwarf_expr_context::execute_stack_op (gdb::array= _view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct value *val;
>=C2=A0 =C2=A0
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0offset =3D extract_signed_integer (= op_ptr, 2, byte_order);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 2;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_signed_integer= (op_ptr, op_end, 2, byte_order,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 &offset);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D fetch (0);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dwarf_require_integral (val-&g= t;type ());
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (value_as_long (val) !=3D 0= )
> @@ -2313,18 +2369,18 @@ dwarf_expr_context::execute_stack_op (gdb::arr= ay_view<const gdb_byte> expr)
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_call2:
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cu_offset cu_off
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D (cu_offset) extract_unsi= gned_integer (op_ptr, 2, byte_order);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 2;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integ= er (op_ptr, op_end, 2,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 byte_order, &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cu_offset cu_off =3D (cu_offset) uo= ffset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0this->dwarf_call (cu_off);<= br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto no_push;
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0case DW_OP_call4:
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cu_offset cu_off
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D (cu_offset) extract_unsi= gned_integer (op_ptr, 4, byte_order);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 4;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integ= er (op_ptr, op_end, 4,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 byte_order, &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cu_offset cu_off =3D (cu_offset) uo= ffset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0this->dwarf_call (cu_off);<= br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto no_push;
> @@ -2334,11 +2390,10 @@ dwarf_expr_context::execute_stack_op (gdb::arr= ay_view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ensure_have_per_cu (this->m= _per_cu, "DW_OP_GNU_variable_value");
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int ref_addr_size =3D this->= ;m_per_cu->ref_addr_size ();
>=C2=A0 =C2=A0
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sect_offset sect_off
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D (sect_offset) extract_un= signed_integer (op_ptr,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ref_addr_size,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0byte_order);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D ref_addr_size;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integ= er (op_ptr, op_end,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 ref_addr_size, byte_order,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sect_offset sect_off =3D (sect_offs= et) uoffset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result_val =3D sect_variable_v= alue (sect_off, this->m_per_cu,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0this->m_per_objfile);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0result_val =3D value_cast (add= ress_type, result_val);
> @@ -2353,15 +2408,13 @@ dwarf_expr_context::execute_stack_op (gdb::arr= ay_view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0union call_site_parameter_u ki= nd_u;
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_uleb128 (= op_ptr, op_end, &len);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (op_ptr + len > op_end)
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error (_("DW_OP_entry_v= alue: too few bytes available."));
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0const gdb_byte *expr_ptr =3D op_ptr= ;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_skip_bytes (op_ptr,= op_end, len);
>=C2=A0 =C2=A0
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0auto entry_value_expr =3D gdb::make= _array_view (op_ptr, len);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0auto entry_value_expr =3D gdb::make= _array_view (expr_ptr, len);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0kind_u.dwarf_reg =3D dwarf_blo= ck_to_dwarf_reg (entry_value_expr);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (kind_u.dwarf_reg !=3D -1)<= br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D len;
> -
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (trivial_entr= y_value (this->m_frame))
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/*= We can assume that DW_OP_entry_value (expr) =3D=3D expr.
> @@ -2384,7 +2437,6 @@ dwarf_expr_context::execute_stack_op (gdb::array= _view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (deref_size = =3D=3D -1)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0deref_siz= e =3D this->m_addr_size;
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D len;
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (trivial_entr= y_value (this->m_frame))
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{
> @@ -2410,9 +2462,9 @@ dwarf_expr_context::execute_stack_op (gdb::array= _view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0union call_site_parameter_u ki= nd_u;
>=C2=A0 =C2=A0
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0kind_u.param_cu_off
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D (cu_offset) extract_unsi= gned_integer (op_ptr, 4, byte_order);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D 4;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integ= er (op_ptr, op_end, 4,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 byte_order, &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0kind_u.param_cu_off =3D (cu_offset)= uoffset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0this->push_dwarf_reg_entry_= value (CALL_SITE_PARAMETER_PARAM_OFFSET,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0kind_u,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0-1 /* deref_size */);
> @@ -2429,9 +2481,11 @@ dwarf_expr_context::execute_stack_op (gdb::arra= y_view<const gdb_byte> expr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_uleb128 (= op_ptr, op_end, &uoffset);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cu_offset type_die_cu_off =3D = (cu_offset) uoffset;
>=C2=A0 =C2=A0
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0n =3D *op_ptr++;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_read_unsigned_integ= er (op_ptr, op_end, 1, byte_order,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 &uoffset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0n =3D uoffset;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0data =3D op_ptr;
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr +=3D n;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0op_ptr =3D safe_skip_bytes (op_ptr,= op_end, n);
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0type =3D get_base_type (type_d= ie_cu_off);
>=C2=A0 =C2=A0
> diff --git a/gdb/testsuite/gdb.dwarf2/dw2-bad-dwarf-expr-bounds.exp b/= gdb/testsuite/gdb.dwarf2/dw2-bad-dwarf-expr-bounds.exp
> new file mode 100644
> index 00000000000..7f5fa22388d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.dwarf2/dw2-bad-dwarf-expr-bounds.exp
> @@ -0,0 +1,190 @@
> +# Copyright 2026 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modif= y
> +# it under the terms of the GNU General Public License as published b= y
> +# 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.=C2=A0 See the<= br> > +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License > +# along with this program.=C2=A0 If not, see <http://www.gnu.or= g/licenses/>.
> +
> +# Test malformed DWARF expressions whose opcodes have truncated opera= nds.
> +
> +load_lib dwarf.exp
> +
> +require dwarf2_support
> +
> +standard_testfile main.c -dw.S
> +
> +set asm_file [standard_output_file $srcfile2]
> +Dwarf::assemble $asm_file {
> +=C2=A0 =C2=A0 global srcfile
> +
> +=C2=A0 =C2=A0 declare_labels int_label
> +
> +=C2=A0 =C2=A0 cu {label cu_label} {
> +=C2=A0 =C2=A0 =C2=A0DW_TAG_compile_unit {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_name $srcfile
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_language @DW_LANG_C
> +=C2=A0 =C2=A0 =C2=A0} {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int_label: DW_TAG_base_type {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_name "int&= quot;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_encoding @DW_AT= E_signed
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_byte_size 4 DW_= FORM_sdata
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0foreach {var op} {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_addr DW_OP_= addr
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_const1u DW_= OP_const1u
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_const1s DW_= OP_const1s
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_const2u DW_= OP_const2u
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_const2s DW_= OP_const2s
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_const4u DW_= OP_const4u
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_const4s DW_= OP_const4s
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_const8u DW_= OP_const8u
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_const8s DW_= OP_const8s
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_implicit_po= inter DW_OP_implicit_pointer
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_gnu_implici= t_pointer DW_OP_GNU_implicit_pointer
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_pick DW_OP_= pick
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_deref_size = DW_OP_deref_size
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_deref_type = DW_OP_deref_type
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_gnu_deref_t= ype DW_OP_GNU_deref_type
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_skip DW_OP_= skip
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_bra DW_OP_b= ra
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0truncated_parameter_r= ef DW_OP_GNU_parameter_ref
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_TAG_variable {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_n= ame $var
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_t= ype :$int_label
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_l= ocation {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0_op .byte $Dwarf::_constants($op) $op
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} SPECI= AL_expr
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_TAG_variable {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_name "trun= cated_implicit_value"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_type :$int_labe= l
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_location {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .by= te $Dwarf::_constants(DW_OP_implicit_value) \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0DW_OP_implicit_value
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .ul= eb128 4 "implicit value length"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .2b= yte 0 "truncated implicit value bytes"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} SPECIAL_expr
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_TAG_variable {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_name "trun= cated_entry_value"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_type :$int_labe= l
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_location {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .by= te $Dwarf::_constants(DW_OP_entry_value) \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0DW_OP_entry_value
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .ul= eb128 4 "entry value expression length"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .2b= yte 0 "truncated entry value expression"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} SPECIAL_expr
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_TAG_variable {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_name "trun= cated_gnu_entry_value"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_type :$int_labe= l
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_location {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .by= te $Dwarf::_constants(DW_OP_GNU_entry_value) \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0DW_OP_GNU_entry_value
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .ul= eb128 4 "entry value expression length"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .2b= yte 0 "truncated entry value expression"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} SPECIAL_expr
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_TAG_variable {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_name "trun= cated_const_type_size"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_type :$int_labe= l
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_location {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .by= te $Dwarf::_constants(DW_OP_const_type) \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0DW_OP_const_type
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .ul= eb128 "$int_label - $cu_label" "type DIE offset"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} SPECIAL_expr
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_TAG_variable {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_name "trun= cated_const_type_payload"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_type :$int_labe= l
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_location {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .by= te $Dwarf::_constants(DW_OP_const_type) \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0DW_OP_const_type
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .ul= eb128 "$int_label - $cu_label" "type DIE offset"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .by= te 4 "constant block length"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .2b= yte 0 "truncated constant block"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} SPECIAL_expr
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_TAG_variable {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_name "trun= cated_gnu_const_type_size"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_type :$int_labe= l
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_location {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .by= te $Dwarf::_constants(DW_OP_GNU_const_type) \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0DW_OP_GNU_const_type
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .ul= eb128 "$int_label - $cu_label" "type DIE offset"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} SPECIAL_expr
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_TAG_variable {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_name "trun= cated_gnu_const_type_payload"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_type :$int_labe= l
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DW_AT_location {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .by= te $Dwarf::_constants(DW_OP_GNU_const_type) \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0DW_OP_GNU_const_type
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .ul= eb128 "$int_label - $cu_label" "type DIE offset"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .by= te 4 "constant block length"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0_op .2b= yte 0 "truncated constant block"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} SPECIAL_expr
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 }
> +}
> +
> +if {[prepare_for_testing "failed to prepare" ${testfile} \<= br> > +=C2=A0 =C2=A0 =C2=A0 [list $srcfile $asm_file] nodebug]} {
> +=C2=A0 =C2=A0 return
> +}
> +
> +if {![runto_main]} {
> +=C2=A0 =C2=A0 return
> +}
> +
> +foreach var {
> +=C2=A0 =C2=A0 truncated_addr
> +=C2=A0 =C2=A0 truncated_const1u
> +=C2=A0 =C2=A0 truncated_const1s
> +=C2=A0 =C2=A0 truncated_const2u
> +=C2=A0 =C2=A0 truncated_const2s
> +=C2=A0 =C2=A0 truncated_const4u
> +=C2=A0 =C2=A0 truncated_const4s
> +=C2=A0 =C2=A0 truncated_const8u
> +=C2=A0 =C2=A0 truncated_const8s
> +=C2=A0 =C2=A0 truncated_implicit_value
> +=C2=A0 =C2=A0 truncated_implicit_pointer
> +=C2=A0 =C2=A0 truncated_gnu_implicit_pointer
> +=C2=A0 =C2=A0 truncated_pick
> +=C2=A0 =C2=A0 truncated_deref_size
> +=C2=A0 =C2=A0 truncated_deref_type
> +=C2=A0 =C2=A0 truncated_gnu_deref_type
> +=C2=A0 =C2=A0 truncated_skip
> +=C2=A0 =C2=A0 truncated_bra
> +=C2=A0 =C2=A0 truncated_entry_value
> +=C2=A0 =C2=A0 truncated_gnu_entry_value
> +=C2=A0 =C2=A0 truncated_parameter_ref
> +=C2=A0 =C2=A0 truncated_const_type_size
> +=C2=A0 =C2=A0 truncated_const_type_payload
> +=C2=A0 =C2=A0 truncated_gnu_const_type_size
> +=C2=A0 =C2=A0 truncated_gnu_const_type_payload
> +} {
> +=C2=A0 =C2=A0 with_test_prefix $var {
There exists a "foreach_with_prefix", that does basically what yo= u did
here.
> +=C2=A0 =C2=A0 =C2=A0gdb_test "print $var" \
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0".*DWARF expression error: ran= off end of buffer reading .*"
> +=C2=A0 =C2=A0 }
> +}


--
Cheers,
Guinevere Larsen
it/its
she/her (deprecated)

--0000000000000e82f5065523f0a3--