Blame SOURCES/gdb-test-for-rhbz1976887.patch

b94e32
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
b94e32
From: =?UTF-8?q?Alexandra=20H=C3=A1jkov=C3=A1?= <ahajkova@redhat.com>
b94e32
Date: Wed, 29 Sep 2021 11:14:51 +0200
b94e32
Subject: gdb-test-for-rhbz1976887.patch
b94e32
b94e32
;; Backport test for RHBZ 1976887 (Kevin Buettner).
b94e32
b94e32
Test case reproducing PR28030 bug
b94e32
b94e32
The original reproducer for PR28030 required use of a specific
b94e32
compiler version - gcc-c++-11.1.1-3.fc34 is mentioned in the PR,
b94e32
though it seems probable that other gcc versions might also be able to
b94e32
reproduce the bug as well.  This commit introduces a test case which,
b94e32
using the DWARF assembler, provides a reproducer which is independent
b94e32
of the compiler version.  (Well, it'll work with whatever compilers
b94e32
the DWARF assembler works with.)
b94e32
b94e32
To the best of my knowledge, it's also the first test case which uses
b94e32
the DWARF assembler to provide debug info for a shared object.  That
b94e32
being the case, I provided more than the usual commentary which should
b94e32
allow this case to be used as a template when a combo shared
b94e32
library / DWARF assembler test case is required in the future.
b94e32
b94e32
I provide some details regarding the bug in a comment near the
b94e32
beginning of locexpr-dml.exp.
b94e32
b94e32
This problem was difficult to reproduce; I found myself constantly
b94e32
referring to the backtrace while trying to figure out what (else) I
b94e32
might be missing while trying to create a reproducer.  Below is a
b94e32
partial backtrace which I include for posterity.
b94e32
b94e32
 #0  internal_error (
b94e32
    file=0xc50110 "/ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/gdbtypes.c", line=5575,
b94e32
    fmt=0xc520c0 "Unexpected type field location kind: %d")
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdbsupport/errors.cc:51
b94e32
 #1  0x00000000006ef0c5 in copy_type_recursive (objfile=0x1635930,
b94e32
    type=0x274c260, copied_types=0x30bb290)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/gdbtypes.c:5575
b94e32
 #2  0x00000000006ef382 in copy_type_recursive (objfile=0x1635930,
b94e32
    type=0x274ca10, copied_types=0x30bb290)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/gdbtypes.c:5602
b94e32
 #3  0x0000000000a7409a in preserve_one_value (value=0x24269f0,
b94e32
    objfile=0x1635930, copied_types=0x30bb290)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/value.c:2529
b94e32
 #4  0x000000000072012a in gdbscm_preserve_values (
b94e32
    extlang=0xc55720 <extension_language_guile>, objfile=0x1635930,
b94e32
    copied_types=0x30bb290)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/guile/scm-value.c:94
b94e32
 #5  0x00000000006a3f82 in preserve_ext_lang_values (objfile=0x1635930,
b94e32
    copied_types=0x30bb290)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/extension.c:568
b94e32
 #6  0x0000000000a7428d in preserve_values (objfile=0x1635930)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/value.c:2579
b94e32
 #7  0x000000000082d514 in objfile::~objfile (this=0x1635930,
b94e32
    __in_chrg=<optimized out>)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/objfiles.c:549
b94e32
 #8  0x0000000000831cc8 in std::_Sp_counted_ptr<objfile*, (__gnu_cxx::_Lock_policy)2>::_M_dispose (this=0x1654580)
b94e32
    at /usr/include/c++/11/bits/shared_ptr_base.h:348
b94e32
 #9  0x00000000004e6617 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x1654580) at /usr/include/c++/11/bits/shared_ptr_base.h:168
b94e32
 #10 0x00000000004e1d2f in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x190bb88, __in_chrg=<optimized out>)
b94e32
    at /usr/include/c++/11/bits/shared_ptr_base.h:705
b94e32
 #11 0x000000000082feee in std::__shared_ptr<objfile, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0x190bb80, __in_chrg=<optimized out>)
b94e32
    at /usr/include/c++/11/bits/shared_ptr_base.h:1154
b94e32
 #12 0x000000000082ff0a in std::shared_ptr<objfile>::~shared_ptr (
b94e32
    this=0x190bb80, __in_chrg=<optimized out>)
b94e32
    at /usr/include/c++/11/bits/shared_ptr.h:122
b94e32
 #13 0x000000000085ed7e in __gnu_cxx::new_allocator<std::_List_node<std::shared_ptr<objfile> > >::destroy<std::shared_ptr<objfile> > (this=0x114bc00,
b94e32
    __p=0x190bb80) at /usr/include/c++/11/ext/new_allocator.h:168
b94e32
 #14 0x000000000085e88d in std::allocator_traits<std::allocator<std::_List_node<std::shared_ptr<objfile> > > >::destroy<std::shared_ptr<objfile> > (__a=...,
b94e32
    __p=0x190bb80) at /usr/include/c++/11/bits/alloc_traits.h:531
b94e32
 #15 0x000000000085e50c in std::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::_M_erase (this=0x114bc00, __position=
b94e32
  std::shared_ptr<objfile> (expired, weak count 1) = {get() = 0x1635930})
b94e32
    at /usr/include/c++/11/bits/stl_list.h:1925
b94e32
 #16 0x000000000085df0e in std::__cxx11::list<std::shared_ptr<objfile>, std::allocator<std::shared_ptr<objfile> > >::erase (this=0x114bc00, __position=
b94e32
  std::shared_ptr<objfile> (expired, weak count 1) = {get() = 0x1635930})
b94e32
    at /usr/include/c++/11/bits/list.tcc:158
b94e32
 #17 0x000000000085c748 in program_space::remove_objfile (this=0x114bbc0,
b94e32
    objfile=0x1635930)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/progspace.c:210
b94e32
 #18 0x000000000082d3ae in objfile::unlink (this=0x1635930)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/objfiles.c:487
b94e32
 #19 0x000000000082e68c in objfile_purge_solibs ()
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/objfiles.c:875
b94e32
 #20 0x000000000092dd37 in no_shared_libraries (ignored=0x0, from_tty=1)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/solib.c:1236
b94e32
 #21 0x00000000009a37fe in target_pre_inferior (from_tty=1)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/target.c:2496
b94e32
 #22 0x00000000007454d6 in run_command_1 (args=0x0, from_tty=1,
b94e32
    run_how=RUN_NORMAL)
b94e32
    at /ironwood1/sourceware-git/f34-pr28030/bld/../../worktree-pr28030/gdb/infcmd.c:437
b94e32
b94e32
I'll note a few points regarding this backtrace:
b94e32
b94e32
Frame #1 is where the internal error occurs.  It's caused by an
b94e32
unhandled case for FIELD_LOC_KIND_DWARF_BLOCK.  The fix for this bug
b94e32
adds support for this case.
b94e32
b94e32
Frame #22 - it's a partial backtrace - shows that GDB is attempting to
b94e32
(re)run the program.  You can see the exact command sequence that was
b94e32
used for reproducing this problem in the PR (at
b94e32
https://sourceware.org/bugzilla/show_bug.cgi?id=28030), but in a
b94e32
nutshell, after starting the program and advancing to the appropriate
b94e32
source line, GDB was asked to step into libstdc++; a "finish" command
b94e32
was issued, returning a value.  The fact that a value was returned is
b94e32
very important.  GDB was then used to step back into libstdc++.  A
b94e32
breakpoint was set on a source line in the library after which a "run"
b94e32
command was issued.
b94e32
b94e32
Frame #19 shows a call to objfile_purge_solibs.  It's aptly named.
b94e32
b94e32
Frame #7 is a call to the destructor for one of the objfile solibs; it
b94e32
turned out to be the one for libstdc++.
b94e32
b94e32
Frames #6 thru #3 show various value preservation frames.  If you look
b94e32
at preserve_values() in gdb/value.c, the value history is preserved
b94e32
first, followed by internal variables, followed by values for the
b94e32
extension languages (python and guile).
b94e32
b94e32
diff --git a/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location-lib.c b/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location-lib.c
b94e32
new file mode 100644
b94e32
--- /dev/null
b94e32
+++ b/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location-lib.c
b94e32
@@ -0,0 +1,48 @@
b94e32
+/* Copyright (C) 2021 Free Software Foundation, Inc.
b94e32
+
b94e32
+   This file is part of GDB.
b94e32
+
b94e32
+   This program is free software; you can redistribute it and/or modify
b94e32
+   it under the terms of the GNU General Public License as published by
b94e32
+   the Free Software Foundation; either version 3 of the License, or
b94e32
+   (at your option) any later version.
b94e32
+
b94e32
+   This program is distributed in the hope that it will be useful,
b94e32
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
b94e32
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
b94e32
+   GNU General Public License for more details.
b94e32
+
b94e32
+   You should have received a copy of the GNU General Public License
b94e32
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
b94e32
+
b94e32
+#include "locexpr-data-member-location.h"
b94e32
+
b94e32
+struct A g_A = {3, 4};
b94e32
+struct B g_B = { {8, 9}, 10, 11 };
b94e32
+
b94e32
+B *
b94e32
+foo ()
b94e32
+{						/* foo prologue */
b94e32
+  asm ("foo_label: .globl foo_label");
b94e32
+  return &g_;;					/* foo return */
b94e32
+}						/* foo end */
b94e32
+
b94e32
+B *
b94e32
+bar (B *v)
b94e32
+{						/* bar prologue */
b94e32
+  asm ("bar_label: .globl bar_label");
b94e32
+  return v;					/* bar return */
b94e32
+}						/* bar end */
b94e32
+
b94e32
+/* Some of the DWARF assembler procs (e.g. function_range) compile
b94e32
+   this file, expecting it to be a complete program with a main()
b94e32
+   function.  When IS_SHAREDLIB is NOT defined, we have main() as
b94e32
+   defined below.  */
b94e32
+
b94e32
+#ifndef IS_SHAREDLIB
b94e32
+int
b94e32
+main ()
b94e32
+{
b94e32
+  B *b = foo ();
b94e32
+}
b94e32
+#endif
b94e32
diff --git a/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location-main.c b/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location-main.c
b94e32
new file mode 100644
b94e32
--- /dev/null
b94e32
+++ b/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location-main.c
b94e32
@@ -0,0 +1,27 @@
b94e32
+/* Copyright (C) 2021 Free Software Foundation, Inc.
b94e32
+
b94e32
+   This file is part of GDB.
b94e32
+
b94e32
+   This program is free software; you can redistribute it and/or modify
b94e32
+   it under the terms of the GNU General Public License as published by
b94e32
+   the Free Software Foundation; either version 3 of the License, or
b94e32
+   (at your option) any later version.
b94e32
+
b94e32
+   This program is distributed in the hope that it will be useful,
b94e32
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
b94e32
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
b94e32
+   GNU General Public License for more details.
b94e32
+
b94e32
+   You should have received a copy of the GNU General Public License
b94e32
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
b94e32
+
b94e32
+#include "locexpr-data-member-location.h"
b94e32
+
b94e32
+int
b94e32
+main (void)
b94e32
+{
b94e32
+  B *v1;
b94e32
+  v1 = bar (foo ());
b94e32
+
b94e32
+  return 0;
b94e32
+}
b94e32
diff --git a/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location.exp b/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location.exp
b94e32
new file mode 100644
b94e32
--- /dev/null
b94e32
+++ b/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location.exp
b94e32
@@ -0,0 +1,349 @@
b94e32
+# Copyright 2021 Free Software Foundation, Inc.
b94e32
+
b94e32
+# This program is free software; you can redistribute it and/or modify
b94e32
+# it under the terms of the GNU General Public License as published by
b94e32
+# the Free Software Foundation; either version 3 of the License, or
b94e32
+# (at your option) any later version.
b94e32
+#
b94e32
+# This program is distributed in the hope that it will be useful,
b94e32
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
b94e32
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
b94e32
+# GNU General Public License for more details.
b94e32
+#
b94e32
+# You should have received a copy of the GNU General Public License
b94e32
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
b94e32
+
b94e32
+# This test case uses the DWARF assembler to reproduce the problem
b94e32
+# described by PR28030.  The bug turned out to be that
b94e32
+# FIELD_LOC_KIND_DWARF_BLOCK was not handled when recursively copying
b94e32
+# a value's type when preserving the value history during the freeing
b94e32
+# up of objfiles associated with a shared object.  (Yes, figuring out
b94e32
+# how to make this happen in a concise test case turned out to be
b94e32
+# challenging.)
b94e32
+#
b94e32
+# The following elements proved to be necessary for reproducing the
b94e32
+# problem:
b94e32
+#
b94e32
+# 1) A location expression needed to be used with
b94e32
+#    DW_AT_data_member_location rather than a simple offset.
b94e32
+#    Moreover, this location expression needed to use opcodes
b94e32
+#    which GDB's DWARF reader could not convert to a simple
b94e32
+#    offset.  (Note, however, that GDB could probably be improved
b94e32
+#    to handle the opcodes chosen for this test; if decode_locdesc()
b94e32
+#    in dwarf2/read.c is ever updated to handle both DW_OP_pick and
b94e32
+#    DW_OP_drop, then this test could end up passing even if
b94e32
+#    the bug it's intended to test has not been fixed.)
b94e32
+#
b94e32
+# 2) The debug info containing the above DWARF info needed
b94e32
+#    to be associated with a shared object since the problem
b94e32
+#    occurred while GDB was preserving values during the
b94e32
+#    purging of shared objects.
b94e32
+#
b94e32
+# 3) After performing some simple gdb commands, the program is
b94e32
+#    run again.  In the course of running the objfile destructor
b94e32
+#    associated with the shared object, values are preserved
b94e32
+#    along with their types.  As noted earlier, it was during
b94e32
+#    the recursive type copy that the bug was observed.
b94e32
+#
b94e32
+# Therefore, due to #2 above, this test case creates debug info
b94e32
+# which is then used by a shared object.
b94e32
+
b94e32
+# This test can't be run on targets lacking shared library support.
b94e32
+if [skip_shlib_tests] {
b94e32
+    return 0
b94e32
+}
b94e32
+
b94e32
+load_lib dwarf.exp
b94e32
+
b94e32
+# This test can only be run on targets which support DWARF-2 and use gas.
b94e32
+if ![dwarf2_support] {
b94e32
+    return 0
b94e32
+}
b94e32
+
b94e32
+# gdb_test_file_name is the name of this file without the .exp
b94e32
+# extension.  Use it to form basenames for the main program
b94e32
+# and shared object.
b94e32
+set main_basename ${::gdb_test_file_name}-main
b94e32
+set lib_basename ${::gdb_test_file_name}-lib
b94e32
+
b94e32
+# We're generating DWARF assembly for the shared object; therefore,
b94e32
+# the source file for the library / shared object must be listed first
b94e32
+# (in the standard_testfile invocation) since ${srcfile} is used by
b94e32
+# get_func_info (for determining the start, end, and length of a
b94e32
+# function).
b94e32
+#
b94e32
+# The output of Dwarf::assemble will be placed in $lib_basename.S
b94e32
+# which will be ${srcfile3} after the execution of standard_testfile.
b94e32
+
b94e32
+standard_testfile $lib_basename.c $main_basename.c $lib_basename.S
b94e32
+
b94e32
+set libsrc "${::srcdir}/${::subdir}/${::srcfile}"
b94e32
+set lib_so [standard_output_file ${lib_basename}.so]
b94e32
+set asm_file [standard_output_file ${::srcfile3}]
b94e32
+
b94e32
+# We need to know the size of some types in order to write some of the
b94e32
+# debugging info that we're about to generate.  For that, we ask GDB
b94e32
+# by debugging the shared object associated with this test case.
b94e32
+
b94e32
+# Compile the shared library: -DIS_SHAREDLIB prevents main() from
b94e32
+# being defined.  Note that debugging symbols will be present for
b94e32
+# this compilation.
b94e32
+if {[gdb_compile_shlib $libsrc $lib_so \
b94e32
+                       {additional_flags=-DIS_SHAREDLIB debug}] != ""} {
b94e32
+    untested "failed to compile shared library"
b94e32
+    return
b94e32
+}
b94e32
+
b94e32
+# Start a fresh GDB and load the shared library.
b94e32
+clean_restart $lib_so
b94e32
+
b94e32
+# Using our running GDB session, determine sizes of several types.
b94e32
+set long_size [get_sizeof "long" -1]
b94e32
+set addr_size [get_sizeof "void *" -1]
b94e32
+set struct_A_size [get_sizeof "g_A" -1]
b94e32
+set struct_B_size [get_sizeof "g_B" -1]
b94e32
+
b94e32
+if { $long_size == -1 || $addr_size == -1 \
b94e32
+     || $struct_A_size == -1 || $struct_B_size == -1} {
b94e32
+    perror "Can't determine type sizes"
b94e32
+    return
b94e32
+}
b94e32
+
b94e32
+# Retrieve struct offset of MBR in struct TP
b94e32
+proc get_offsetof { tp mbr } {
b94e32
+    return [get_integer_valueof "&((${tp} *) 0)->${mbr}" -1]
b94e32
+}
b94e32
+
b94e32
+# Use running GDB session to get struct offsets
b94e32
+set A_a [get_offsetof A a]
b94e32
+set A_x [get_offsetof A x]
b94e32
+set B_a [get_offsetof B a]
b94e32
+set B_b [get_offsetof B b]
b94e32
+set B_x2 [get_offsetof B x2]
b94e32
+
b94e32
+# Create the DWARF.
b94e32
+Dwarf::assemble ${asm_file} {
b94e32
+    declare_labels L
b94e32
+
b94e32
+    # Find start, end, and length of functions foo and bar.
b94e32
+    # These calls to get_func_info will create and set variables
b94e32
+    # foo_start, bar_start, foo_end, bar_end, foo_len, and
b94e32
+    # bar_len.
b94e32
+    #
b94e32
+    # In order to get the right answers, get_func_info (and,
b94e32
+    # underneath, function_range) should use the same compiler flags
b94e32
+    # as those used to make a shared object.  For any targets that get
b94e32
+    # this far, -fpic is probably correct.
b94e32
+    #
b94e32
+    # Also, it should be noted that IS_SHAREDLIB is NOT defined as one
b94e32
+    # of the additional flags.  Not defining IS_SHAREDLIB will cause a
b94e32
+    # main() to be defined for the compilation of the shared library
b94e32
+    # source file which happens as a result of using get_func_info;
b94e32
+    # this is currently required in order to this facility.
b94e32
+    set flags {additional_flags=-fpic debug}
b94e32
+    get_func_info foo $flags
b94e32
+    get_func_info bar $flags
b94e32
+
b94e32
+    cu {} {
b94e32
+	DW_TAG_compile_unit {
b94e32
+	    {DW_AT_language @DW_LANG_C_plus_plus}
b94e32
+	    {name ${::srcfile}}
b94e32
+	    {stmt_list $L DW_FORM_sec_offset}
b94e32
+        } {
b94e32
+	    declare_labels int_label class_A_label class_B_label \
b94e32
+	                   B_ptr_label
b94e32
+
b94e32
+	    int_label: DW_TAG_base_type {
b94e32
+		{DW_AT_byte_size ${::long_size} DW_FORM_udata}
b94e32
+		{DW_AT_encoding @DW_ATE_signed}
b94e32
+		{DW_AT_name "int"}
b94e32
+	    }
b94e32
+
b94e32
+	    class_A_label: DW_TAG_class_type {
b94e32
+		{DW_AT_name "A"}
b94e32
+		{DW_AT_byte_size ${::struct_A_size} DW_FORM_sdata}
b94e32
+	    } {
b94e32
+		DW_TAG_member {
b94e32
+		    {DW_AT_name "a"}
b94e32
+		    {DW_AT_type :$int_label}
b94e32
+		    {DW_AT_data_member_location ${::A_a} DW_FORM_udata}
b94e32
+		}
b94e32
+		DW_TAG_member {
b94e32
+		    {DW_AT_name "x"}
b94e32
+		    {DW_AT_type :$int_label}
b94e32
+		    {DW_AT_data_member_location ${::A_x} DW_FORM_udata}
b94e32
+		}
b94e32
+	    }
b94e32
+
b94e32
+	    class_B_label: DW_TAG_class_type {
b94e32
+		{DW_AT_name "B"}
b94e32
+		{DW_AT_byte_size ${::struct_B_size} DW_FORM_sdata}
b94e32
+	    } {
b94e32
+		# While there are easier / better ways to specify an
b94e32
+		# offset used by DW_AT_data_member_location than that
b94e32
+		# used below, we need a location expression here in
b94e32
+		# order to reproduce the bug.  Moreover, this location
b94e32
+		# expression needs to use opcodes that aren't handled
b94e32
+		# by decode_locdesc() in dwarf2/read.c; if we use
b94e32
+		# opcodes that _are_ handled by that function, the
b94e32
+		# location expression will be converted into a simple
b94e32
+		# offset - which will then (again) not reproduce the
b94e32
+		# bug.  At the time that this test was written,
b94e32
+		# neither DW_OP_pick nor DW_OP_drop were being handled
b94e32
+		# by decode_locdesc(); this is why those opcodes were
b94e32
+		# chosen.
b94e32
+		DW_TAG_inheritance {
b94e32
+		    {DW_AT_type :$class_A_label}
b94e32
+		    {DW_AT_data_member_location {
b94e32
+			DW_OP_constu ${::B_a}
b94e32
+			DW_OP_plus
b94e32
+			DW_OP_pick 0
b94e32
+			DW_OP_drop} SPECIAL_expr}
b94e32
+		    {DW_AT_accessibility 1 DW_FORM_data1}
b94e32
+		}
b94e32
+		DW_TAG_member {
b94e32
+		    {DW_AT_name "b"}
b94e32
+		    {DW_AT_type :$int_label}
b94e32
+		    {DW_AT_data_member_location ${::B_b} DW_FORM_udata}
b94e32
+		}
b94e32
+		DW_TAG_member {
b94e32
+		    {DW_AT_name "x2"}
b94e32
+		    {DW_AT_type :$int_label}
b94e32
+		    {DW_AT_data_member_location ${::B_x2} DW_FORM_udata}
b94e32
+		}
b94e32
+	    }
b94e32
+
b94e32
+	    B_ptr_label: DW_TAG_pointer_type {
b94e32
+		{DW_AT_type :$class_B_label}
b94e32
+		{DW_AT_byte_size ${::addr_size} DW_FORM_sdata}
b94e32
+	    }
b94e32
+
b94e32
+	    DW_TAG_variable {
b94e32
+		{DW_AT_name "g_A"}
b94e32
+		{DW_AT_type :$class_A_label}
b94e32
+		{DW_AT_external 1 flag}
b94e32
+		{DW_AT_location {DW_OP_addr [gdb_target_symbol "g_A"]} \
b94e32
+		                 SPECIAL_expr}
b94e32
+	    }
b94e32
+
b94e32
+	    DW_TAG_variable {
b94e32
+		{DW_AT_name "g_B"}
b94e32
+		{DW_AT_type :$class_B_label}
b94e32
+		{DW_AT_external 1 flag}
b94e32
+		{DW_AT_location {DW_OP_addr [gdb_target_symbol "g_B"]} \
b94e32
+		                 SPECIAL_expr}
b94e32
+	    }
b94e32
+
b94e32
+	    # We can't use MACRO_AT for the definitions of foo and bar
b94e32
+	    # because it doesn't provide a way to pass the appropriate
b94e32
+	    # flags.  Therefore, we list the name, low_pc, and high_pc
b94e32
+	    # explicitly.
b94e32
+	    DW_TAG_subprogram {
b94e32
+		{DW_AT_name foo}
b94e32
+		{DW_AT_low_pc $foo_start DW_FORM_addr}
b94e32
+		{DW_AT_high_pc $foo_end DW_FORM_addr}
b94e32
+		{DW_AT_type :${B_ptr_label}}
b94e32
+		{DW_AT_external 1 flag}
b94e32
+	    }
b94e32
+
b94e32
+	    DW_TAG_subprogram {
b94e32
+		{DW_AT_name bar}
b94e32
+		{DW_AT_low_pc $bar_start DW_FORM_addr}
b94e32
+		{DW_AT_high_pc $bar_end DW_FORM_addr}
b94e32
+		{DW_AT_type :${B_ptr_label}}
b94e32
+		{DW_AT_external 1 flag}
b94e32
+	    } {
b94e32
+		DW_TAG_formal_parameter {
b94e32
+		    {DW_AT_name v}
b94e32
+		    {DW_AT_type :${B_ptr_label}}
b94e32
+		}
b94e32
+	    }
b94e32
+	}
b94e32
+    }
b94e32
+
b94e32
+    lines {version 2} L {
b94e32
+	include_dir "${::srcdir}/${::subdir}"
b94e32
+	file_name "${::srcfile}" 1
b94e32
+
b94e32
+	# Generate a line table program.
b94e32
+	program {
b94e32
+	    {DW_LNE_set_address $foo_start}
b94e32
+	    {line [gdb_get_line_number "foo prologue"]}
b94e32
+	    {DW_LNS_copy}
b94e32
+	    {DW_LNE_set_address foo_label}
b94e32
+	    {line [gdb_get_line_number "foo return"]}
b94e32
+	    {DW_LNS_copy}
b94e32
+	    {line [gdb_get_line_number "foo end"]}
b94e32
+	    {DW_LNS_copy}
b94e32
+	    {DW_LNE_set_address $foo_end}
b94e32
+	    {DW_LNS_advance_line 1}
b94e32
+	    {DW_LNS_copy}
b94e32
+	    {DW_LNE_end_sequence}
b94e32
+
b94e32
+	    {DW_LNE_set_address $bar_start}
b94e32
+	    {line [gdb_get_line_number "bar prologue"]}
b94e32
+	    {DW_LNS_copy}
b94e32
+	    {DW_LNE_set_address bar_label}
b94e32
+	    {line [gdb_get_line_number "bar return"]}
b94e32
+	    {DW_LNS_copy}
b94e32
+	    {line [gdb_get_line_number "bar end"]}
b94e32
+	    {DW_LNS_copy}
b94e32
+	    {DW_LNE_set_address $bar_end}
b94e32
+	    {DW_LNS_advance_line 1}
b94e32
+	    {DW_LNS_copy}
b94e32
+	    {DW_LNE_end_sequence}
b94e32
+	}
b94e32
+    }
b94e32
+}
b94e32
+
b94e32
+# Compile the shared object again, but this time include / use the
b94e32
+# DWARF info that we've created above.  Note that (again)
b94e32
+# -DIS_SHAREDLIB is used to prevent inclusion of main() in the shared
b94e32
+# object.  Also note the use of the "nodebug" option.  Any debugging
b94e32
+# information that we need will be provided by the DWARF info created
b94e32
+# above.
b94e32
+if {[gdb_compile_shlib [list $libsrc $asm_file] $lib_so \
b94e32
+                       {additional_flags=-DIS_SHAREDLIB nodebug}] != ""} {
b94e32
+    untested "failed to compile shared library"
b94e32
+    return
b94e32
+}
b94e32
+
b94e32
+# Compile the main program for use with the shared object.
b94e32
+if [prepare_for_testing "failed to prepare" ${testfile} \
b94e32
+                        ${::srcfile2} [list debug shlib=$lib_so]] {
b94e32
+    return -1
b94e32
+}
b94e32
+
b94e32
+# Do whatever is necessary to make sure that the shared library is
b94e32
+# loaded for remote targets.
b94e32
+gdb_load_shlib ${lib_so}
b94e32
+
b94e32
+if ![runto_main] then {
b94e32
+    fail "can't run to main"
b94e32
+    return
b94e32
+}
b94e32
+
b94e32
+# Step into foo so that we can finish out of it.
b94e32
+gdb_test "step" "foo .. at .* foo end.*" "step into foo"
b94e32
+
b94e32
+# Finishing out of foo will create a value that will later need to
b94e32
+# be preserved when restarting the program.
b94e32
+gdb_test "finish" "= \\(class B \\*\\) ${::hex} .*" "finish out of foo"
b94e32
+
b94e32
+# Dereferencing and printing the return value isn't necessary
b94e32
+# for reproducing the bug, but we should make sure that the
b94e32
+# return value is what we expect it to be.
b94e32
+gdb_test "p *$" { = { = {a = 8, x = 9}, b = 10, x2 = 11}} \
b94e32
+         "dereference return value"
b94e32
+
b94e32
+# The original PR28030 reproducer stepped back into the shared object,
b94e32
+# so we'll do the same here:
b94e32
+gdb_test "step" "bar \\(.*" "step into bar"
b94e32
+
b94e32
+# We don't want a clean restart here since that will be too clean.
b94e32
+# The original reproducer for PR28030 set a breakpoint in the shared
b94e32
+# library and then restarted via "run".  The command below does roughly
b94e32
+# the same thing.  It's at this step that an internal error would
b94e32
+# occur for PR28030.  The "message" argument tells runto to turn on
b94e32
+# the printing of PASSes while runto is doing its job.
b94e32
+runto "bar" message
b94e32
diff --git a/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location.h b/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location.h
b94e32
new file mode 100644
b94e32
--- /dev/null
b94e32
+++ b/gdb/testsuite/gdb.dwarf2/locexpr-data-member-location.h
b94e32
@@ -0,0 +1,30 @@
b94e32
+/* Copyright (C) 2021 Free Software Foundation, Inc.
b94e32
+
b94e32
+   This file is part of GDB.
b94e32
+
b94e32
+   This program is free software; you can redistribute it and/or modify
b94e32
+   it under the terms of the GNU General Public License as published by
b94e32
+   the Free Software Foundation; either version 3 of the License, or
b94e32
+   (at your option) any later version.
b94e32
+
b94e32
+   This program is distributed in the hope that it will be useful,
b94e32
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
b94e32
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
b94e32
+   GNU General Public License for more details.
b94e32
+
b94e32
+   You should have received a copy of the GNU General Public License
b94e32
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
b94e32
+
b94e32
+typedef struct A {
b94e32
+    long a;
b94e32
+    long x;
b94e32
+} A;
b94e32
+
b94e32
+typedef struct B {
b94e32
+    A a;
b94e32
+    long b;
b94e32
+    long x2;
b94e32
+} B;
b94e32
+
b94e32
+extern B *foo ();
b94e32
+extern B *bar (B *v);