+2018-09-05  Tom de Vries  <tdevries@suse.de>
+
+       * dwarf2loc.c (sect_variable_value): Call indirect_synthetic_pointer
+       with resolve_abstract_p == true.
+       (indirect_synthetic_pointer): Add resolve_abstract_p parameter,
+       defaulting to false. Propagate resolve_abstract_p to
+       dwarf2_fetch_die_loc_sect_off.
+       * dwarf2loc.h (dwarf2_fetch_die_loc_sect_off): Add resolve_abstract_p
+       parameter, defaulting to false.
+       * dwarf2read.c (read_variable): Add variable to abstract_to_concrete.
+       (dwarf2_fetch_die_loc_sect_off): Add and handle resolve_abstract_p
+       parameter.
+       * dwarf2read.h (struct die_info): Forward-declare.
+       (die_info_ptr): New typedef.
+       (struct dwarf2_per_objfile): Add abstract_to_concrete field.
+
 2018-09-05  Joel Brobecker  <brobecker@adacore.com>
 
        GDB 8.2 released.
 
   (sect_offset die, LONGEST byte_offset,
    struct dwarf2_per_cu_data *per_cu,
    struct frame_info *frame,
-   struct type *type);
+   struct type *type, bool resolve_abstract_p = false);
 
 /* Until these have formal names, we define these here.
    ref: http://gcc.gnu.org/wiki/DebugFission
 
   struct type *type = lookup_pointer_type (die_type);
   struct frame_info *frame = get_selected_frame (_("No frame selected."));
-  return indirect_synthetic_pointer (sect_off, 0, per_cu, frame, type);
+  return indirect_synthetic_pointer (sect_off, 0, per_cu, frame, type, true);
 }
 
 class dwarf_evaluate_loc_desc : public dwarf_expr_context
 static struct value *
 indirect_synthetic_pointer (sect_offset die, LONGEST byte_offset,
                            struct dwarf2_per_cu_data *per_cu,
-                           struct frame_info *frame, struct type *type)
+                           struct frame_info *frame, struct type *type,
+                           bool resolve_abstract_p)
 {
   /* Fetch the location expression of the DIE we're pointing to.  */
   struct dwarf2_locexpr_baton baton
     = dwarf2_fetch_die_loc_sect_off (die, per_cu,
-                                    get_frame_address_in_block_wrapper, frame);
+                                    get_frame_address_in_block_wrapper, frame,
+                                    resolve_abstract_p);
 
   /* Get type of pointed-to DIE.  */
   struct type *orig_type = dwarf2_fetch_die_type_sect_off (die, per_cu);
 
 struct dwarf2_locexpr_baton dwarf2_fetch_die_loc_sect_off
   (sect_offset offset_in_cu, struct dwarf2_per_cu_data *per_cu,
    CORE_ADDR (*get_frame_pc) (void *baton),
-   void *baton);
+   void *baton, bool resolve_abstract_p = false);
 
 struct dwarf2_locexpr_baton dwarf2_fetch_die_loc_cu_off
   (cu_offset offset_in_cu, struct dwarf2_per_cu_data *per_cu,
 
        }
     }
 
-  new_symbol (die, NULL, cu, storage);
+  struct symbol *res = new_symbol (die, NULL, cu, storage);
+  struct attribute *abstract_origin
+    = dwarf2_attr (die, DW_AT_abstract_origin, cu);
+  struct attribute *loc = dwarf2_attr (die, DW_AT_location, cu);
+  if (res == NULL && loc && abstract_origin)
+    {
+      /* We have a variable without a name, but with a location and an abstract
+        origin.  This may be a concrete instance of an abstract variable
+        referenced from an DW_OP_GNU_variable_value, so save it to find it back
+        later.  */
+      struct dwarf2_cu *origin_cu = cu;
+      struct die_info *origin_die
+       = follow_die_ref (die, abstract_origin, &origin_cu);
+      dwarf2_per_objfile *dpo = cu->per_cu->dwarf2_per_objfile;
+      dpo->abstract_to_concrete[origin_die].push_back (die);
+    }
 }
 
 /* Call CALLBACK from DW_AT_ranges attribute value OFFSET
 dwarf2_fetch_die_loc_sect_off (sect_offset sect_off,
                               struct dwarf2_per_cu_data *per_cu,
                               CORE_ADDR (*get_frame_pc) (void *baton),
-                              void *baton)
+                              void *baton, bool resolve_abstract_p)
 {
   struct dwarf2_cu *cu;
   struct die_info *die;
           sect_offset_str (sect_off), objfile_name (objfile));
 
   attr = dwarf2_attr (die, DW_AT_location, cu);
+  if (!attr && resolve_abstract_p
+      && (dwarf2_per_objfile->abstract_to_concrete.find (die)
+         != dwarf2_per_objfile->abstract_to_concrete.end ()))
+    {
+      CORE_ADDR pc = (*get_frame_pc) (baton);
+
+      for (const auto &cand : dwarf2_per_objfile->abstract_to_concrete[die])
+       {
+         if (!cand->parent
+             || cand->parent->tag != DW_TAG_subprogram)
+           continue;
+
+         CORE_ADDR pc_low, pc_high;
+         get_scope_pc_bounds (cand->parent, &pc_low, &pc_high, cu);
+         if (pc_low == ((CORE_ADDR) -1)
+             || !(pc_low <= pc && pc < pc_high))
+           continue;
+
+         die = cand;
+         attr = dwarf2_attr (die, DW_AT_location, cu);
+         break;
+       }
+    }
+
   if (!attr)
     {
       /* DWARF: "If there is no such attribute, then there is no effect.".
 
 #ifndef DWARF2READ_H
 #define DWARF2READ_H
 
+#include <unordered_map>
 #include "dwarf-index-cache.h"
 #include "filename-seen-cache.h"
 #include "gdb_obstack.h"
 struct mapped_index;
 struct mapped_debug_names;
 struct signatured_type;
+struct die_info;
+typedef struct die_info *die_info_ptr;
 
 /* Collection of data recorded per objfile.
    This hangs off of dwarf2_objfile_data_key.  */
   /* If we loaded the index from an external file, this contains the
      resources associated to the open file, memory mapping, etc.  */
   std::unique_ptr<index_cache_resource> index_cache_res;
+
+  /* Mapping from abstract origin DIE to concrete DIEs that reference it as
+     DW_AT_abstract_origin.  */
+  std::unordered_map<die_info_ptr, std::vector<die_info_ptr>>
+    abstract_to_concrete;
 };
 
 /* Get the dwarf2_per_objfile associated to OBJFILE.  */
 
+2018-09-05  Tom de Vries  <tdevries@suse.de>
+
+       * gdb.dwarf2/varval.exp: Add test.
+
 2018-09-04  Gary Benson <gbenson@redhat.com>
 
        * gdb.base/batch-exit-status.exp: Use gdb_test_multiple and expect
 
        } {
            declare_labels int_label ptr_label struct_label var_a_label \
                           var_b_label var_c_label var_p_label var_bad_label \
-                          varval_label var_s_label var_untyped_label
+                          varval_label var_s_label var_untyped_label \
+                          var_a_abstract_label var_a_concrete_label \
+                          varval2_label
 
            set int_size [get_sizeof "int" -1]
 
                {DW_AT_location {DW_OP_addr [gdb_target_symbol "var_a"]} SPECIAL_expr}
            }
 
+           var_a_abstract_label: DW_TAG_variable {
+               {DW_AT_type :${int_label}}
+               {DW_AT_external 1 DW_FORM_flag}
+           }
+
            var_b_label: DW_TAG_variable {
                {DW_AT_name "var_b"}
                {DW_AT_type :${int_label}}
                        DW_OP_stack_value
                    } SPECIAL_expr}
                }
+               varval2_label: DW_TAG_variable {
+                   {DW_AT_name "varval2"}
+                   {DW_AT_type :${int_label}}
+                   {DW_AT_location {
+                       DW_OP_GNU_variable_value ${var_a_abstract_label}
+                       DW_OP_stack_value
+                   } SPECIAL_expr}
+               }
+               var_a_concrete_label: DW_TAG_variable {
+                   {DW_AT_abstract_origin :${var_a_abstract_label}}
+                   {DW_AT_location {DW_OP_addr [gdb_target_symbol "var_a"]} SPECIAL_expr}
+               }
                DW_TAG_variable {
                    {DW_AT_name "constval"}
                    {DW_AT_type :${int_label}}
 }
 
 gdb_test "print varval" "= 8"
+gdb_test "print varval2" "= 8"
 gdb_test "print constval" "= 53"
 gdb_test "print mixedval" "= 42"
 gdb_test "print pointerval" "= \\(int \\*\\) $hex <var_b>"