+2017-11-17 Tom Tromey <tom@tromey.com>
+
+ * symtab.h (struct symbol) <is_rust_vtable>: New member.
+ (struct rust_vtable_symbol): New.
+ (find_symbol_at_address): Declare.
+ * symtab.c (find_symbol_at_address): New function.
+ * symfile.h (struct quick_symbol_functions)
+ <find_compunit_symtab_by_address>: New member.
+ * symfile-debug.c (debug_qf_find_compunit_symtab_by_address): New
+ function.
+ (debug_sym_quick_functions): Link to
+ debug_qf_find_compunit_symtab_by_address.
+ * rust-lang.c (rust_get_trait_object_pointer): New function.
+ (rust_evaluate_subexp) <case UNOP_IND>: New case. Call
+ rust_get_trait_object_pointer.
+ * psymtab.c (psym_relocate): Clear psymbol_map.
+ (psym_fill_psymbol_map, psym_find_compunit_symtab_by_address): New
+ functions.
+ (psym_functions): Link to psym_find_compunit_symtab_by_address.
+ * objfiles.h (struct objfile) <psymbol_map>: New member.
+ * dwarf2read.c (dwarf2_gdb_index_functions): Update.
+ (process_die) <DW_TAG_variable>: New case. Call read_variable.
+ (rust_containing_type, read_variable): New functions.
+
2017-11-17 Simon Marchi <simon.marchi@polymtl.ca>
* common/gdb_vecs.h (DEF_VEC_I (int)): Remove.
static void read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu);
+static void read_variable (struct die_info *die, struct dwarf2_cu *cu);
+
static int dwarf2_ranges_read (unsigned, CORE_ADDR *, CORE_ADDR *,
struct dwarf2_cu *, struct partial_symtab *);
dw2_map_matching_symbols,
dw2_expand_symtabs_matching,
dw2_find_pc_sect_compunit_symtab,
+ NULL,
dw2_map_symbol_filenames
};
process_imported_unit_die (die, cu);
break;
+ case DW_TAG_variable:
+ read_variable (die, cu);
+ break;
+
default:
new_symbol (die, NULL, cu);
break;
}
}
+/* Helper function for read_variable. If DIE represents a virtual
+ table, then return the type of the concrete object that is
+ associated with the virtual table. Otherwise, return NULL. */
+
+static struct type *
+rust_containing_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct attribute *attr = dwarf2_attr (die, DW_AT_type, cu);
+ if (attr == NULL)
+ return NULL;
+
+ /* Find the type DIE. */
+ struct die_info *type_die = NULL;
+ struct dwarf2_cu *type_cu = cu;
+
+ if (attr_form_is_ref (attr))
+ type_die = follow_die_ref (die, attr, &type_cu);
+ if (type_die == NULL)
+ return NULL;
+
+ if (dwarf2_attr (type_die, DW_AT_containing_type, type_cu) == NULL)
+ return NULL;
+ return die_containing_type (type_die, type_cu);
+}
+
+/* Read a variable (DW_TAG_variable) DIE and create a new symbol. */
+
+static void
+read_variable (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct rust_vtable_symbol *storage = NULL;
+
+ if (cu->language == language_rust)
+ {
+ struct type *containing_type = rust_containing_type (die, cu);
+
+ if (containing_type != NULL)
+ {
+ struct objfile *objfile = cu->objfile;
+
+ storage = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+ struct rust_vtable_symbol);
+ initialize_objfile_symbol (storage);
+ storage->concrete_type = containing_type;
+ storage->is_rust_vtable = 1;
+ }
+ }
+
+ new_symbol_full (die, NULL, cu, storage);
+}
+
/* Call CALLBACK from DW_AT_ranges attribute value OFFSET
reading .debug_rnglists.
Callback's type should be:
struct psymbol_bcache *psymbol_cache;
+ /* Map symbol addresses to the partial symtab that defines the
+ object at that address. */
+
+ std::vector<std::pair<CORE_ADDR, partial_symtab *>> psymbol_map;
+
/* Vectors of all partial symbols read in from file. The actual data
is stored in the objfile_obstack. */
#include "cp-support.h"
#include "gdbcmd.h"
#include <algorithm>
+#include <set>
struct psymbol_bcache
{
if (SYMBOL_SECTION (psym) >= 0)
SYMBOL_VALUE_ADDRESS (psym) += ANOFFSET (delta, SYMBOL_SECTION (psym));
}
+
+ objfile->psymbol_map.clear ();
}
/* Psymtab version of find_last_source_symtab. See its definition in
return objfile->psymtabs != NULL;
}
+/* Helper function for psym_find_compunit_symtab_by_address that fills
+ in psymbol_map for a given range of psymbols. */
+
+static void
+psym_fill_psymbol_map (struct objfile *objfile,
+ struct partial_symtab *psymtab,
+ std::set<CORE_ADDR> *seen_addrs,
+ const std::vector<partial_symbol *> &symbols,
+ int start,
+ int length)
+{
+ for (int i = 0; i < length; ++i)
+ {
+ struct partial_symbol *psym = symbols[start + i];
+
+ if (PSYMBOL_CLASS (psym) == LOC_STATIC)
+ {
+ CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (psym);
+ if (seen_addrs->find (addr) == seen_addrs->end ())
+ {
+ seen_addrs->insert (addr);
+ objfile->psymbol_map.emplace_back (addr, psymtab);
+ }
+ }
+ }
+}
+
+/* See find_compunit_symtab_by_address in quick_symbol_functions, in
+ symfile.h. */
+
+static compunit_symtab *
+psym_find_compunit_symtab_by_address (struct objfile *objfile,
+ CORE_ADDR address)
+{
+ if (objfile->psymbol_map.empty ())
+ {
+ struct partial_symtab *pst;
+
+ std::set<CORE_ADDR> seen_addrs;
+
+ ALL_OBJFILE_PSYMTABS_REQUIRED (objfile, pst)
+ {
+ psym_fill_psymbol_map (objfile, pst,
+ &seen_addrs,
+ objfile->global_psymbols,
+ pst->globals_offset,
+ pst->n_global_syms);
+ psym_fill_psymbol_map (objfile, pst,
+ &seen_addrs,
+ objfile->static_psymbols,
+ pst->statics_offset,
+ pst->n_static_syms);
+ }
+
+ objfile->psymbol_map.shrink_to_fit ();
+
+ std::sort (objfile->psymbol_map.begin (), objfile->psymbol_map.end (),
+ [] (const std::pair<CORE_ADDR, partial_symtab *> &a,
+ const std::pair<CORE_ADDR, partial_symtab *> &b)
+ {
+ return a.first < b.first;
+ });
+ }
+
+ auto iter = std::lower_bound
+ (objfile->psymbol_map.begin (), objfile->psymbol_map.end (), address,
+ [] (const std::pair<CORE_ADDR, partial_symtab *> &a,
+ CORE_ADDR b)
+ {
+ return a.first < b;
+ });
+
+ if (iter == objfile->psymbol_map.end () || iter->first != address)
+ return NULL;
+
+ return psymtab_to_symtab (objfile, iter->second);
+}
+
const struct quick_symbol_functions psym_functions =
{
psym_has_symbols,
psym_map_matching_symbols,
psym_expand_symtabs_matching,
psym_find_pc_sect_compunit_symtab,
+ psym_find_compunit_symtab_by_address,
psym_map_symbol_filenames
};
#include "gdbarch.h"
#include "infcall.h"
#include "objfiles.h"
+#include "psymtab.h"
#include "rust-lang.h"
#include "valprint.h"
#include "varobj.h"
&& TYPE_UNSIGNED (type));
}
+/* If VALUE represents a trait object pointer, return the underlying
+ pointer with the correct (i.e., runtime) type. Otherwise, return
+ NULL. */
+
+static struct value *
+rust_get_trait_object_pointer (struct value *value)
+{
+ struct type *type = check_typedef (value_type (value));
+
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT || TYPE_NFIELDS (type) != 2)
+ return NULL;
+
+ /* Try to be a bit resilient if the ABI changes. */
+ int vtable_field = 0;
+ for (int i = 0; i < 2; ++i)
+ {
+ if (strcmp (TYPE_FIELD_NAME (type, i), "vtable") == 0)
+ vtable_field = i;
+ else if (strcmp (TYPE_FIELD_NAME (type, i), "pointer") != 0)
+ return NULL;
+ }
+
+ CORE_ADDR vtable = value_as_address (value_field (value, vtable_field));
+ struct symbol *symbol = find_symbol_at_address (vtable);
+ if (symbol == NULL || !symbol->is_rust_vtable)
+ return NULL;
+
+ struct rust_vtable_symbol *vtable_sym
+ = static_cast<struct rust_vtable_symbol *> (symbol);
+ struct type *pointer_type = lookup_pointer_type (vtable_sym->concrete_type);
+ return value_cast (pointer_type, value_field (value, 1 - vtable_field));
+}
+
\f
/* la_emitchar implementation for Rust. */
switch (exp->elts[*pos].opcode)
{
+ case UNOP_IND:
+ {
+ if (noside != EVAL_NORMAL)
+ result = evaluate_subexp_standard (expect_type, exp, pos, noside);
+ else
+ {
+ ++*pos;
+ struct value *value = evaluate_subexp (expect_type, exp, pos,
+ noside);
+
+ struct value *trait_ptr = rust_get_trait_object_pointer (value);
+ if (trait_ptr != NULL)
+ value = trait_ptr;
+
+ result = value_ind (value);
+ }
+ }
+ break;
+
case UNOP_COMPLEMENT:
{
struct value *value;
need_fullname);
}
+static struct compunit_symtab *
+debug_qf_find_compunit_symtab_by_address (struct objfile *objfile,
+ CORE_ADDR address)
+{
+ const struct debug_sym_fns_data *debug_data
+ = ((const struct debug_sym_fns_data *)
+ objfile_data (objfile, symfile_debug_objfile_data_key));
+ fprintf_filtered (gdb_stdlog,
+ "qf->find_compunit_symtab_by_address (%s, %s)\n",
+ objfile_debug_name (objfile),
+ hex_string (address));
+
+ struct compunit_symtab *result = NULL;
+ if (debug_data->real_sf->qf->map_symbol_filenames != NULL)
+ result
+ = debug_data->real_sf->qf->find_compunit_symtab_by_address (objfile,
+ address);
+
+ fprintf_filtered (gdb_stdlog,
+ "qf->find_compunit_symtab_by_address (...) = %s\n",
+ result
+ ? debug_symtab_name (compunit_primary_filetab (result))
+ : "NULL");
+
+ return result;
+}
+
static const struct quick_symbol_functions debug_sym_quick_functions =
{
debug_qf_has_symbols,
debug_qf_map_matching_symbols,
debug_qf_expand_symtabs_matching,
debug_qf_find_pc_sect_compunit_symtab,
+ debug_qf_find_compunit_symtab_by_address,
debug_qf_map_symbol_filenames
};
\f
(struct objfile *objfile, struct bound_minimal_symbol msymbol,
CORE_ADDR pc, struct obj_section *section, int warn_if_readin);
+ /* Return the comp unit from OBJFILE that contains a symbol at
+ ADDRESS. Return NULL if there is no such comp unit. Unlike
+ find_pc_sect_compunit_symtab, any sort of symbol (not just text
+ symbols) can be considered, and only exact address matches are
+ considered. This pointer may be NULL. */
+ struct compunit_symtab *(*find_compunit_symtab_by_address)
+ (struct objfile *objfile, CORE_ADDR address);
+
/* Call a callback for every file defined in OBJFILE whose symtab is
not already read in. FUN is the callback. It is passed the file's
FILENAME, the file's FULLNAME (if need_fullname is non-zero), and
{
return find_pc_sect_compunit_symtab (pc, find_pc_mapped_section (pc));
}
+
+/* See symtab.h. */
+
+struct symbol *
+find_symbol_at_address (CORE_ADDR address)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ if (objfile->sf == NULL
+ || objfile->sf->qf->find_compunit_symtab_by_address == NULL)
+ continue;
+
+ struct compunit_symtab *symtab
+ = objfile->sf->qf->find_compunit_symtab_by_address (objfile, address);
+ if (symtab != NULL)
+ {
+ const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (symtab);
+
+ for (int i = GLOBAL_BLOCK; i <= STATIC_BLOCK; ++i)
+ {
+ struct block *b = BLOCKVECTOR_BLOCK (bv, i);
+ struct block_iterator iter;
+ struct symbol *sym;
+
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ if (SYMBOL_CLASS (sym) == LOC_STATIC
+ && SYMBOL_VALUE_ADDRESS (sym) == address)
+ return sym;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
\f
/* Find the source file and line number for a given PC value and SECTION.
In this case the symbol is really a "struct template_symbol". */
unsigned is_cplus_template_function : 1;
+ /* True if this is a Rust virtual table. In this case, the symbol
+ can be downcast to "struct rust_vtable_symbol". */
+
+ unsigned is_rust_vtable : 1;
+
/* Line number of this symbol's definition, except for inlined
functions. For an inlined function (class LOC_BLOCK and
SYMBOL_INLINED set) this is the line number of the function's call
struct symbol **template_arguments;
};
+/* A symbol that represents a Rust virtual table object. */
+
+struct rust_vtable_symbol : public symbol
+{
+ /* The concrete type for which this vtable was created; that is, in
+ "impl Trait for Type", this is "Type". */
+ struct type *concrete_type;
+};
+
\f
/* Each item represents a line-->pc (or the reverse) mapping. This is
somewhat more wasteful of space than one might wish, but since only
extern struct symbol *find_pc_sect_function (CORE_ADDR, struct obj_section *);
+/* Find the symbol at the given address. Returns NULL if no symbol
+ found. Only exact matches for ADDRESS are considered. */
+
+extern struct symbol *find_symbol_at_address (CORE_ADDR);
+
extern int find_pc_partial_function_gnu_ifunc (CORE_ADDR pc, const char **name,
CORE_ADDR *address,
CORE_ADDR *endaddr,
+2017-11-17 Tom Tromey <tom@tromey.com>
+
+ * gdb.rust/traits.rs: New file.
+ * gdb.rust/traits.exp: New file.
+
2017-11-17 Joel Brobecker <brobecker@adacore.com>
* gdb.ada/minsyms: New testcase.
--- /dev/null
+# Copyright (C) 2017 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 trait object printing.
+
+load_lib rust-support.exp
+if {[skip_rust_tests]} {
+ continue
+}
+
+standard_testfile .rs
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug rust}]} {
+ return -1
+}
+
+set readelf_program [gdb_find_readelf]
+set result [catch "exec $readelf_program --debug-dump=info $binfile" output]
+if {$result != 0} {
+ untested "could not read ${binfile} with readelf"
+ return
+}
+
+if {![regexp DW_AT_containing_type $output]} {
+ untested "Rust compiler did not emit DW_AT_containing_type"
+ return
+}
+
+set line [gdb_get_line_number "set breakpoint here"]
+if {![runto ${srcfile}:$line]} {
+ untested "could not run to breakpoint"
+ return -1
+}
+
+gdb_test "print *td" " = 23.5"
+gdb_test "print *tu" " = 23"
--- /dev/null
+// Copyright (C) 2017 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/>.
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+pub trait T {
+}
+
+impl T for f64 {
+}
+
+impl T for u8 {
+}
+
+pub fn main() {
+ let d = 23.5f64;
+ let u = 23u8;
+
+ let td = &d as &T;
+ let tu = &u as &T;
+
+ println!(""); // set breakpoint here
+}