data, data + size, per_cu, per_objfile);
 }
 
-\f
-/* Helper functions and baton for dwarf2_loc_desc_get_symbol_read_needs.  */
+/* Compute the correct symbol_needs_kind value for the location
+   expression in EXPR.
+
+   Implemented by traversing the logical control flow graph of the
+   expression.  */
 
-class symbol_needs_eval_context : public dwarf_expr_context
+static enum symbol_needs_kind
+dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
+                             dwarf2_per_cu_data *per_cu,
+                             dwarf2_per_objfile *per_objfile,
+                             bfd_endian byte_order,
+                             int addr_size,
+                             int ref_addr_size,
+                             int depth = 0)
 {
-public:
-  symbol_needs_eval_context (dwarf2_per_objfile *per_objfile)
-    : dwarf_expr_context (per_objfile)
-  {}
+  enum symbol_needs_kind symbol_needs = SYMBOL_NEEDS_NONE;
 
-  enum symbol_needs_kind needs;
-  struct dwarf2_per_cu_data *per_cu;
+  /* If the expression is empty, we have nothing to do.  */
+  if (expr.empty ())
+    return symbol_needs;
 
-  /* Reads from registers do require a frame.  */
-  CORE_ADDR read_addr_from_reg (int regnum) override
-  {
-    needs = SYMBOL_NEEDS_FRAME;
-    return 1;
-  }
+  const gdb_byte *expr_end = expr.data () + expr.size ();
 
-  /* "get_reg_value" callback: Reads from registers do require a
-     frame.  */
+  /* List of operations to visit.  Operations in this list are not visited yet,
+     so are not in VISITED_OPS (and vice-versa).  */
+  std::vector<const gdb_byte *> ops_to_visit;
 
-  struct value *get_reg_value (struct type *type, int regnum) override
-  {
-    needs = SYMBOL_NEEDS_FRAME;
-    return value_zero (type, not_lval);
-  }
+  /* Operations already visited.  */
+  std::unordered_set<const gdb_byte *> visited_ops;
 
-  /* Reads from memory do not require a frame.  */
-  void read_mem (gdb_byte *buf, CORE_ADDR addr, size_t len) override
-  {
-    memset (buf, 0, len);
-  }
+  /* Insert OP in OPS_TO_VISIT if it is within the expression's range and
+     hasn't been visited yet.  */
+  auto insert_in_ops_to_visit
+    = [expr_end, &visited_ops, &ops_to_visit] (const gdb_byte *op_ptr)
+      {
+       if (op_ptr >= expr_end)
+         return;
 
-  /* Frame-relative accesses do require a frame.  */
-  void get_frame_base (const gdb_byte **start, size_t *length) override
-  {
-    static gdb_byte lit0 = DW_OP_lit0;
+       if (visited_ops.find (op_ptr) != visited_ops.end ())
+         return;
 
-    *start = &lit0;
-    *length = 1;
+       ops_to_visit.push_back (op_ptr);
+      };
 
-    needs = SYMBOL_NEEDS_FRAME;
-  }
+  /* Expressions can invoke other expressions with DW_OP_call*.  Protect against
+     a loop of calls.  */
+  const int max_depth = 256;
 
-  /* CFA accesses require a frame.  */
-  CORE_ADDR get_frame_cfa () override
-  {
-    needs = SYMBOL_NEEDS_FRAME;
-    return 1;
-  }
+  if (depth > max_depth)
+    error (_("DWARF-2 expression error: Loop detected."));
 
-  CORE_ADDR get_frame_pc () override
-  {
-    needs = SYMBOL_NEEDS_FRAME;
-    return 1;
-  }
+  depth++;
 
-  /* Thread-local accesses require registers, but not a frame.  */
-  CORE_ADDR get_tls_address (CORE_ADDR offset) override
-  {
-    if (needs <= SYMBOL_NEEDS_REGISTERS)
-      needs = SYMBOL_NEEDS_REGISTERS;
-    return 1;
-  }
+  /* Initialize the to-visit list with the first operation.  */
+  insert_in_ops_to_visit (&expr[0]);
 
-  /* Helper interface of per_cu_dwarf_call for
-     dwarf2_loc_desc_get_symbol_read_needs.  */
+  while (!ops_to_visit.empty ())
+    {
+      /* Pop one op to visit, mark it as visited.  */
+      const gdb_byte *op_ptr = ops_to_visit.back ();
+      ops_to_visit.pop_back ();
+      gdb_assert (visited_ops.find (op_ptr) == visited_ops.end ());
+      visited_ops.insert (op_ptr);
 
-  void dwarf_call (cu_offset die_offset) override
-  {
-    per_cu_dwarf_call (this, die_offset, per_cu, per_objfile);
-  }
+      dwarf_location_atom op = (dwarf_location_atom) *op_ptr;
 
-  /* Helper interface of sect_variable_value for
-     dwarf2_loc_desc_get_symbol_read_needs.  */
+      /* Most operations have a single possible following operation
+        (they are not conditional branches).  The code below updates
+        OP_PTR to point to that following operation, which is pushed
+        back to OPS_TO_VISIT, if needed, at the bottom.  Here, leave
+        OP_PTR pointing just after the operand.  */
+      op_ptr++;
 
-  struct value *dwarf_variable_value (sect_offset sect_off) override
-  {
-    return sect_variable_value (this, sect_off, per_cu, per_objfile);
-  }
+      /* The DWARF expression might have a bug causing an infinite
+        loop.  In that case, quitting is the only way out.  */
+      QUIT;
 
-  /* DW_OP_entry_value accesses require a caller, therefore a
-     frame.  */
+      switch (op)
+       {
+       case DW_OP_lit0:
+       case DW_OP_lit1:
+       case DW_OP_lit2:
+       case DW_OP_lit3:
+       case DW_OP_lit4:
+       case DW_OP_lit5:
+       case DW_OP_lit6:
+       case DW_OP_lit7:
+       case DW_OP_lit8:
+       case DW_OP_lit9:
+       case DW_OP_lit10:
+       case DW_OP_lit11:
+       case DW_OP_lit12:
+       case DW_OP_lit13:
+       case DW_OP_lit14:
+       case DW_OP_lit15:
+       case DW_OP_lit16:
+       case DW_OP_lit17:
+       case DW_OP_lit18:
+       case DW_OP_lit19:
+       case DW_OP_lit20:
+       case DW_OP_lit21:
+       case DW_OP_lit22:
+       case DW_OP_lit23:
+       case DW_OP_lit24:
+       case DW_OP_lit25:
+       case DW_OP_lit26:
+       case DW_OP_lit27:
+       case DW_OP_lit28:
+       case DW_OP_lit29:
+       case DW_OP_lit30:
+       case DW_OP_lit31:
+       case DW_OP_stack_value:
+       case DW_OP_dup:
+       case DW_OP_drop:
+       case DW_OP_swap:
+       case DW_OP_over:
+       case DW_OP_rot:
+       case DW_OP_deref:
+       case DW_OP_abs:
+       case DW_OP_neg:
+       case DW_OP_not:
+       case DW_OP_and:
+       case DW_OP_div:
+       case DW_OP_minus:
+       case DW_OP_mod:
+       case DW_OP_mul:
+       case DW_OP_or:
+       case DW_OP_plus:
+       case DW_OP_shl:
+       case DW_OP_shr:
+       case DW_OP_shra:
+       case DW_OP_xor:
+       case DW_OP_le:
+       case DW_OP_ge:
+       case DW_OP_eq:
+       case DW_OP_lt:
+       case DW_OP_gt:
+       case DW_OP_ne:
+       case DW_OP_GNU_push_tls_address:
+       case DW_OP_nop:
+       case DW_OP_GNU_uninit:
+       case DW_OP_push_object_address:
+         break;
 
-  void push_dwarf_reg_entry_value (enum call_site_parameter_kind kind,
-                                  union call_site_parameter_u kind_u,
-                                  int deref_size) override
-  {
-    needs = SYMBOL_NEEDS_FRAME;
+       case DW_OP_form_tls_address:
+         if (symbol_needs <= SYMBOL_NEEDS_REGISTERS)
+           symbol_needs = SYMBOL_NEEDS_REGISTERS;
+         break;
 
-    /* The expression may require some stub values on DWARF stack.  */
-    push_address (0, 0);
-  }
+       case DW_OP_convert:
+       case DW_OP_GNU_convert:
+       case DW_OP_reinterpret:
+       case DW_OP_GNU_reinterpret:
+       case DW_OP_addrx:
+       case DW_OP_GNU_addr_index:
+       case DW_OP_GNU_const_index:
+       case DW_OP_constu:
+       case DW_OP_plus_uconst:
+       case DW_OP_piece:
+         op_ptr = safe_skip_leb128 (op_ptr, expr_end);
+         break;
 
-  /* DW_OP_addrx and DW_OP_GNU_addr_index doesn't require a frame.  */
+       case DW_OP_consts:
+         op_ptr = safe_skip_leb128 (op_ptr, expr_end);
+         break;
 
-  CORE_ADDR get_addr_index (unsigned int index) override
-  {
-    /* Nothing to do.  */
-    return 1;
-  }
+       case DW_OP_bit_piece:
+         op_ptr = safe_skip_leb128 (op_ptr, expr_end);
+         op_ptr = safe_skip_leb128 (op_ptr, expr_end);
+         break;
 
-  /* DW_OP_push_object_address has a frame already passed through.  */
+       case DW_OP_deref_type:
+       case DW_OP_GNU_deref_type:
+         op_ptr++;
+         op_ptr = safe_skip_leb128 (op_ptr, expr_end);
+         break;
 
-  CORE_ADDR get_object_address () override
-  {
-    /* Nothing to do.  */
-    return 1;
-  }
-};
+       case DW_OP_addr:
+         op_ptr += addr_size;
+         break;
 
-/* Compute the correct symbol_needs_kind value for the location
-   expression at DATA (length SIZE).  */
+       case DW_OP_const1u:
+       case DW_OP_const1s:
+         op_ptr += 1;
+         break;
 
-static enum symbol_needs_kind
-dwarf2_loc_desc_get_symbol_read_needs (const gdb_byte *data, size_t size,
-                                      dwarf2_per_cu_data *per_cu,
-                                      dwarf2_per_objfile *per_objfile)
-{
-  scoped_value_mark free_values;
+       case DW_OP_const2u:
+       case DW_OP_const2s:
+         op_ptr += 2;
+         break;
 
-  symbol_needs_eval_context ctx (per_objfile);
+       case DW_OP_const4s:
+       case DW_OP_const4u:
+         op_ptr += 4;
+         break;
 
-  ctx.needs = SYMBOL_NEEDS_NONE;
-  ctx.per_cu = per_cu;
-  ctx.gdbarch = per_objfile->objfile->arch ();
-  ctx.addr_size = per_cu->addr_size ();
-  ctx.ref_addr_size = per_cu->ref_addr_size ();
+       case DW_OP_const8s:
+       case DW_OP_const8u:
+         op_ptr += 8;
+         break;
+
+       case DW_OP_reg0:
+       case DW_OP_reg1:
+       case DW_OP_reg2:
+       case DW_OP_reg3:
+       case DW_OP_reg4:
+       case DW_OP_reg5:
+       case DW_OP_reg6:
+       case DW_OP_reg7:
+       case DW_OP_reg8:
+       case DW_OP_reg9:
+       case DW_OP_reg10:
+       case DW_OP_reg11:
+       case DW_OP_reg12:
+       case DW_OP_reg13:
+       case DW_OP_reg14:
+       case DW_OP_reg15:
+       case DW_OP_reg16:
+       case DW_OP_reg17:
+       case DW_OP_reg18:
+       case DW_OP_reg19:
+       case DW_OP_reg20:
+       case DW_OP_reg21:
+       case DW_OP_reg22:
+       case DW_OP_reg23:
+       case DW_OP_reg24:
+       case DW_OP_reg25:
+       case DW_OP_reg26:
+       case DW_OP_reg27:
+       case DW_OP_reg28:
+       case DW_OP_reg29:
+       case DW_OP_reg30:
+       case DW_OP_reg31:
+       case DW_OP_regx:
+       case DW_OP_breg0:
+       case DW_OP_breg1:
+       case DW_OP_breg2:
+       case DW_OP_breg3:
+       case DW_OP_breg4:
+       case DW_OP_breg5:
+       case DW_OP_breg6:
+       case DW_OP_breg7:
+       case DW_OP_breg8:
+       case DW_OP_breg9:
+       case DW_OP_breg10:
+       case DW_OP_breg11:
+       case DW_OP_breg12:
+       case DW_OP_breg13:
+       case DW_OP_breg14:
+       case DW_OP_breg15:
+       case DW_OP_breg16:
+       case DW_OP_breg17:
+       case DW_OP_breg18:
+       case DW_OP_breg19:
+       case DW_OP_breg20:
+       case DW_OP_breg21:
+       case DW_OP_breg22:
+       case DW_OP_breg23:
+       case DW_OP_breg24:
+       case DW_OP_breg25:
+       case DW_OP_breg26:
+       case DW_OP_breg27:
+       case DW_OP_breg28:
+       case DW_OP_breg29:
+       case DW_OP_breg30:
+       case DW_OP_breg31:
+       case DW_OP_bregx:
+       case DW_OP_fbreg:
+       case DW_OP_call_frame_cfa:
+       case DW_OP_entry_value:
+       case DW_OP_GNU_entry_value:
+       case DW_OP_GNU_parameter_ref:
+       case DW_OP_regval_type:
+       case DW_OP_GNU_regval_type:
+         symbol_needs = SYMBOL_NEEDS_FRAME;
+         break;
+
+       case DW_OP_implicit_value:
+         {
+           uint64_t uoffset;
+           op_ptr = safe_read_uleb128 (op_ptr, expr_end, &uoffset);
+           op_ptr += uoffset;
+           break;
+         }
+
+       case DW_OP_implicit_pointer:
+       case DW_OP_GNU_implicit_pointer:
+         op_ptr += ref_addr_size;
+         op_ptr = safe_skip_leb128 (op_ptr, expr_end);
+         break;
+
+       case DW_OP_deref_size:
+       case DW_OP_pick:
+         op_ptr++;
+         break;
+
+       case DW_OP_skip:
+         {
+           int64_t offset = extract_signed_integer (op_ptr, 2, byte_order);
+           op_ptr += 2;
+           op_ptr += offset;
+           break;
+         }
+
+       case DW_OP_bra:
+         {
+           /* This is the only operation that pushes two operations in
+              the to-visit list, so handle it all here.  */
+           LONGEST offset = extract_signed_integer (op_ptr, 2, byte_order);
+           op_ptr += 2;
+
+           insert_in_ops_to_visit (op_ptr + offset);
+           insert_in_ops_to_visit (op_ptr);
+           continue;
+         }
 
-  ctx.eval (data, size);
+       case DW_OP_call2:
+       case DW_OP_call4:
+         {
+           unsigned int len = op == DW_OP_call2 ? 2 : 4;
+           cu_offset cu_off
+             = (cu_offset) extract_unsigned_integer (op_ptr, len, byte_order);
+           op_ptr += len;
 
-  bool in_reg = ctx.location == DWARF_VALUE_REGISTER;
+           auto get_frame_pc = [&symbol_needs] ()
+             {
+               symbol_needs = SYMBOL_NEEDS_FRAME;
+               return 0;
+             };
 
-  /* If the location has several pieces, and any of them are in
-     registers, then we will need a frame to fetch them from.  */
-  for (dwarf_expr_piece &p : ctx.pieces)
-    if (p.location == DWARF_VALUE_REGISTER)
-      in_reg = true;
+           struct dwarf2_locexpr_baton baton
+             = dwarf2_fetch_die_loc_cu_off (cu_off, per_cu,
+                                            per_objfile,
+                                            get_frame_pc);
 
-  if (in_reg)
-    ctx.needs = SYMBOL_NEEDS_FRAME;
+           /* If SYMBOL_NEEDS_FRAME is returned from the previous call,
+              we dont have to check the baton content.  */
+           if (symbol_needs != SYMBOL_NEEDS_FRAME)
+             {
+               gdbarch *arch = baton.per_objfile->objfile->arch ();
+               gdb::array_view<const gdb_byte> sub_expr (baton.data,
+                                                         baton.size);
+               symbol_needs
+                 = dwarf2_get_symbol_read_needs (sub_expr,
+                                                 baton.per_cu,
+                                                 baton.per_objfile,
+                                                 gdbarch_byte_order (arch),
+                                                 baton.per_cu->addr_size (),
+                                                 baton.per_cu->ref_addr_size (),
+                                                 depth);
+             }
+           break;
+         }
 
-  return ctx.needs;
+       case DW_OP_GNU_variable_value:
+         {
+           sect_offset sect_off
+             = (sect_offset) extract_unsigned_integer (op_ptr,
+                                                       ref_addr_size,
+                                                       byte_order);
+           op_ptr += ref_addr_size;
+
+           struct type *die_type
+             = dwarf2_fetch_die_type_sect_off (sect_off, per_cu,
+                                               per_objfile);
+
+           if (die_type == NULL)
+             error (_("Bad DW_OP_GNU_variable_value DIE."));
+
+           /* Note: Things still work when the following test is
+              removed.  This test and error is here to conform to the
+              proposed specification.  */
+           if (die_type->code () != TYPE_CODE_INT
+              && die_type->code () != TYPE_CODE_PTR)
+             error (_("Type of DW_OP_GNU_variable_value DIE must be "
+                      "an integer or pointer."));
+
+           auto get_frame_pc = [&symbol_needs] ()
+             {
+               symbol_needs = SYMBOL_NEEDS_FRAME;
+               return 0;
+             };
+
+           struct dwarf2_locexpr_baton baton
+             = dwarf2_fetch_die_loc_sect_off (sect_off, per_cu,
+                                              per_objfile,
+                                              get_frame_pc, true);
+
+           /* If SYMBOL_NEEDS_FRAME is returned from the previous call,
+              we dont have to check the baton content.  */
+           if (symbol_needs != SYMBOL_NEEDS_FRAME)
+             {
+               gdbarch *arch = baton.per_objfile->objfile->arch ();
+               gdb::array_view<const gdb_byte> sub_expr (baton.data,
+                                                         baton.size);
+               symbol_needs
+                 = dwarf2_get_symbol_read_needs (sub_expr,
+                                                 baton.per_cu,
+                                                 baton.per_objfile,
+                                                 gdbarch_byte_order (arch),
+                                                 baton.per_cu->addr_size (),
+                                                 baton.per_cu->ref_addr_size (),
+                                                 depth);
+             }
+           break;
+         }
+
+       case DW_OP_const_type:
+       case DW_OP_GNU_const_type:
+         {
+           uint64_t uoffset;
+           op_ptr = safe_read_uleb128 (op_ptr, expr_end, &uoffset);
+           gdb_byte offset = *op_ptr++;
+           op_ptr += offset;
+           break;
+         }
+
+       default:
+         error (_("Unhandled DWARF expression opcode 0x%x"), op);
+       }
+
+      /* If it is known that a frame information is
+        needed we can stop parsing the expression.  */
+      if (symbol_needs == SYMBOL_NEEDS_FRAME)
+       break;
+
+      insert_in_ops_to_visit (op_ptr);
+    }
+
+  return symbol_needs;
 }
 
 /* A helper function that throws an unimplemented error mentioning a
   struct dwarf2_locexpr_baton *dlbaton
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
 
-  return dwarf2_loc_desc_get_symbol_read_needs (dlbaton->data, dlbaton->size,
-                                               dlbaton->per_cu,
-                                               dlbaton->per_objfile);
+  gdbarch *arch = dlbaton->per_objfile->objfile->arch ();
+  gdb::array_view<const gdb_byte> expr (dlbaton->data, dlbaton->size);
+
+  return dwarf2_get_symbol_read_needs (expr,
+                                      dlbaton->per_cu,
+                                      dlbaton->per_objfile,
+                                      gdbarch_byte_order (arch),
+                                      dlbaton->per_cu->addr_size (),
+                                      dlbaton->per_cu->ref_addr_size ());
 }
 
 /* Return true if DATA points to the end of a piece.  END is one past
 
--- /dev/null
+# Copyright 2017-2020 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 <http://www.gnu.org/licenses/>.
+
+# Test the symbol needs check mechanism if it assumes that faking
+# reads from a target is a safe thing to do.
+#
+# In particular, the test uses a relative branch DWARF operation to
+# hide a register read. If the target reads are indeed faked, the
+# result returned will be wrong.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+# Choose suitable integer registers for the test.
+
+set dwarf_regnum 0
+
+if { [is_aarch64_target] } {
+    set regname x0
+} elseif { [is_aarch32_target]
+          || [istarget "s390*-*-*" ]
+          || [istarget "powerpc*-*-*"]
+          || [istarget "rs6000*-*-aix*"] } {
+    set regname r0
+} elseif { [is_x86_like_target] } {
+    set regname eax
+} elseif { [is_amd64_regs_target] } {
+    set regname rax
+} else {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+standard_testfile symbol_needs_eval.c ${gdb_test_file_name}-dw.S
+
+# Make some DWARF for the test.
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global dwarf_regnum regname
+
+    set exec_mask_var [gdb_target_symbol exec_mask]
+
+    cu {} {
+       DW_TAG_compile_unit {
+           {DW_AT_name symbol_needs_eval.c}
+           {DW_AT_comp_dir /tmp}
+       } {
+           declare_labels int_type_label
+
+           # define int type
+           int_type_label: DW_TAG_base_type {
+               {DW_AT_name "int"}
+               {DW_AT_encoding @DW_ATE_signed}
+               {DW_AT_byte_size 4 DW_FORM_sdata}
+           }
+
+           # define artificial variable a
+           DW_TAG_variable {
+               {DW_AT_name a}
+               {DW_AT_type :$int_type_label}
+               {DW_AT_location {
+                   DW_OP_addr $exec_mask_var
+                   DW_OP_deref
+
+                   # conditional jump to DW_OP_bregx
+                   DW_OP_bra 4
+                   DW_OP_lit0
+
+                   # jump to DW_OP_stack_value
+                   DW_OP_skip 3
+                   DW_OP_bregx $dwarf_regnum 0
+                   DW_OP_stack_value
+               } SPECIAL_expr}
+               {external 1 flag}
+           }
+       }
+    }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+     [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+# The variable's location expression requires a frame,
+# so an error should be reported.
+gdb_test "print/d a" "No frame selected." "variable a can't be printed"
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test_no_output "set var \$$regname = 2" "init reg to 2"
+
+gdb_test "print/d a" " = 2" "a == 2"
 
--- /dev/null
+# Copyright 2017-2020 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 <http://www.gnu.org/licenses/>.
+
+# Test the symbol needs check mechanism if it assumes that faking
+# reads from a target is a safe thing to do.
+#
+# In particular, the test uses a relative branch DWARF operation to
+# potentially cause an infinite loop, if the target reads are indeed
+# faked.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+# Choose suitable integer registers for the test.
+
+set dwarf_regnum 0
+
+if { [is_aarch64_target] } {
+    set regname x0
+} elseif { [is_aarch32_target]
+          || [istarget "s390*-*-*" ]
+          || [istarget "powerpc*-*-*"]
+          || [istarget "rs6000*-*-aix*"] } {
+    set regname r0
+} elseif { [is_x86_like_target] } {
+    set regname eax
+} elseif { [is_amd64_regs_target] } {
+    set regname rax
+} else {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+standard_testfile symbol_needs_eval.c ${gdb_test_file_name}-dw.S
+
+# Make some DWARF for the test.
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global dwarf_regnum regname
+
+    set exec_mask_var [gdb_target_symbol exec_mask]
+
+    cu {} {
+       DW_TAG_compile_unit {
+           {DW_AT_name symbol_needs_eval.c}
+           {DW_AT_comp_dir /tmp}
+       } {
+           declare_labels int_type_label
+
+           # define int type
+           int_type_label: DW_TAG_base_type {
+               {DW_AT_name "int"}
+               {DW_AT_encoding @DW_ATE_signed}
+               {DW_AT_byte_size 4 DW_FORM_sdata}
+           }
+
+           # add info for variable exec_mask
+           DW_TAG_variable {
+               {DW_AT_name exec_mask}
+               {DW_AT_type :$int_type_label}
+               {DW_AT_location {
+                   DW_OP_addr $exec_mask_var
+               } SPECIAL_expr}
+               {external 1 flag}
+           }
+
+           # add info for subprogram main
+           DW_TAG_subprogram {
+               {MACRO_AT_func { main }}
+               {DW_AT_frame_base {
+                   DW_OP_regx $dwarf_regnum
+               } SPECIAL_expr}
+           } {
+               # define artificial variable a
+               DW_TAG_variable {
+                   {DW_AT_name a}
+                   {DW_AT_type :$int_type_label}
+                   {DW_AT_location {
+                       DW_OP_lit1
+                       DW_OP_addr $exec_mask_var
+                       DW_OP_deref
+
+                       # jump to DW_OP_fbreg
+                       DW_OP_skip 4
+                       DW_OP_drop
+                       DW_OP_fbreg 0
+                       DW_OP_dup
+                       DW_OP_lit0
+                       DW_OP_eq
+
+                       # conditional jump to DW_OP_drop
+                       DW_OP_bra -9
+                       DW_OP_stack_value
+                   } SPECIAL_expr}
+                   {external 1 flag}
+               }
+           }
+       }
+    }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+         [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test_no_output "set var \$$regname = 2" "init reg to 2"
+gdb_test_no_output "set var exec_mask = 0" "init exec_mask to 0"
+
+gdb_test "print/d a" " = 2" "a == 2"