2016-04-27 09:38:08 +08:00
|
|
|
|
/* Rust language support routines for GDB, the GNU debugger.
|
|
|
|
|
|
2018-01-01 12:43:02 +08:00
|
|
|
|
Copyright (C) 2016-2018 Free Software Foundation, Inc.
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
This file is part of GDB.
|
|
|
|
|
|
|
|
|
|
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/>. */
|
|
|
|
|
|
|
|
|
|
#include "defs.h"
|
|
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
|
|
#include "block.h"
|
|
|
|
|
#include "c-lang.h"
|
|
|
|
|
#include "charset.h"
|
|
|
|
|
#include "cp-support.h"
|
2016-05-27 05:04:07 +08:00
|
|
|
|
#include "demangle.h"
|
2016-04-27 09:38:08 +08:00
|
|
|
|
#include "gdbarch.h"
|
|
|
|
|
#include "infcall.h"
|
|
|
|
|
#include "objfiles.h"
|
Handle dereferencing Rust trait objects
In Rust, virtual tables work a bit differently than they do in C++. In
C++, as you know, they are connected to a particular class hierarchy.
Rust, instead, can generate a virtual table for potentially any type --
in fact, one such virtual table for each trait (a trait is similar to an
abstract class or to a Java interface) that a type implements.
Objects that are referenced via a trait can't currently be inspected by
gdb. This patch implements the Rust equivalent of "set print object".
gdb relies heavily on the C++ ABI to decode virtual tables; primarily to
make "set print object" work; but also "info vtbl". However, Rust does
not currently have a specified ABI, so this approach seems unwise to
emulate.
Instead, I've changed the Rust compiler to emit some DWARF that
describes trait objects (previously their internal structure was
opaque), vtables (currently just a size -- but I hope to expand this in
the future), and the concrete type for which a vtable was emitted.
The concrete type is expressed as a DW_AT_containing_type on the
vtable's type. This is a small extension to DWARF.
This patch adds a new entry to quick_symbol_functions to return the
symtab that holds a data address. Previously there was no way in gdb to
look up a full (only minimal) non-text symbol by address. The psymbol
implementation of this method works by lazily filling in a map that is
added to the objfile. This avoids slowing down psymbol reading for a
feature that is likely to not be used too frequently.
I did not update .gdb_index. My thinking here is that the DWARF 5
indices will obsolete .gdb_index soon-ish, meaning that adding a new
feature to them is probably wasted work. If necessary I can update the
DWARF 5 index code when it lands in gdb.
Regression tested on x86-64 Fedora 25.
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 Tom Tromey <tom@tromey.com>
* gdb.rust/traits.rs: New file.
* gdb.rust/traits.exp: New file.
2017-07-06 20:44:38 +08:00
|
|
|
|
#include "psymtab.h"
|
2016-04-27 09:38:08 +08:00
|
|
|
|
#include "rust-lang.h"
|
|
|
|
|
#include "valprint.h"
|
|
|
|
|
#include "varobj.h"
|
2016-09-22 23:51:20 +08:00
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
/* See rust-lang.h. */
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
const char *
|
|
|
|
|
rust_last_path_segment (const char *path)
|
2016-04-27 09:38:08 +08:00
|
|
|
|
{
|
|
|
|
|
const char *result = strrchr (path, ':');
|
|
|
|
|
|
|
|
|
|
if (result == NULL)
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
return path;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
return result + 1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-03 11:58:12 +08:00
|
|
|
|
/* See rust-lang.h. */
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
2017-02-03 11:58:12 +08:00
|
|
|
|
std::string
|
2016-04-27 09:38:08 +08:00
|
|
|
|
rust_crate_for_block (const struct block *block)
|
|
|
|
|
{
|
|
|
|
|
const char *scope = block_scope (block);
|
|
|
|
|
|
|
|
|
|
if (scope[0] == '\0')
|
2017-02-03 11:58:12 +08:00
|
|
|
|
return std::string ();
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
2017-02-03 11:58:12 +08:00
|
|
|
|
return std::string (scope, cp_find_first_component (scope));
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
/* Return true if TYPE, which must be a struct type, represents a Rust
|
|
|
|
|
enum. */
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
2016-10-29 09:00:43 +08:00
|
|
|
|
static bool
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
rust_enum_p (const struct type *type)
|
2016-10-29 09:00:43 +08:00
|
|
|
|
{
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
return (TYPE_CODE (type) == TYPE_CODE_STRUCT
|
|
|
|
|
&& TYPE_NFIELDS (type) == 1
|
|
|
|
|
&& TYPE_FLAG_DISCRIMINATED_UNION (TYPE_FIELD_TYPE (type, 0)));
|
2016-10-29 09:00:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
/* Given an enum type and contents, find which variant is active. */
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
struct field *
|
|
|
|
|
rust_enum_variant (struct type *type, const gdb_byte *contents)
|
2016-04-27 09:38:08 +08:00
|
|
|
|
{
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
/* In Rust the enum always fills the containing structure. */
|
|
|
|
|
gdb_assert (TYPE_FIELD_BITPOS (type, 0) == 0);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
struct type *union_type = TYPE_FIELD_TYPE (type, 0);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
int fieldno = value_union_variant (union_type, contents);
|
|
|
|
|
return &TYPE_FIELD (union_type, fieldno);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See rust-lang.h. */
|
|
|
|
|
|
2017-02-03 12:21:19 +08:00
|
|
|
|
bool
|
2016-04-27 09:38:08 +08:00
|
|
|
|
rust_tuple_type_p (struct type *type)
|
|
|
|
|
{
|
|
|
|
|
/* The current implementation is a bit of a hack, but there's
|
|
|
|
|
nothing else in the debuginfo to distinguish a tuple from a
|
|
|
|
|
struct. */
|
|
|
|
|
return (TYPE_CODE (type) == TYPE_CODE_STRUCT
|
|
|
|
|
&& TYPE_TAG_NAME (type) != NULL
|
|
|
|
|
&& TYPE_TAG_NAME (type)[0] == '(');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return true if all non-static fields of a structlike type are in a
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
sequence like __0, __1, __2. */
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
2017-02-03 12:21:19 +08:00
|
|
|
|
static bool
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
rust_underscore_fields (struct type *type)
|
2016-04-27 09:38:08 +08:00
|
|
|
|
{
|
|
|
|
|
int i, field_number;
|
|
|
|
|
|
|
|
|
|
field_number = 0;
|
|
|
|
|
|
|
|
|
|
if (TYPE_CODE (type) != TYPE_CODE_STRUCT)
|
2017-02-03 12:21:19 +08:00
|
|
|
|
return false;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
for (i = 0; i < TYPE_NFIELDS (type); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (!field_is_static (&TYPE_FIELD (type, i)))
|
|
|
|
|
{
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
char buf[20];
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
xsnprintf (buf, sizeof (buf), "__%d", field_number);
|
|
|
|
|
if (strcmp (buf, TYPE_FIELD_NAME (type, i)) != 0)
|
|
|
|
|
return false;
|
|
|
|
|
field_number++;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-02-03 12:21:19 +08:00
|
|
|
|
return true;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See rust-lang.h. */
|
|
|
|
|
|
2017-02-03 12:21:19 +08:00
|
|
|
|
bool
|
2016-04-27 09:38:08 +08:00
|
|
|
|
rust_tuple_struct_type_p (struct type *type)
|
|
|
|
|
{
|
2016-07-12 05:02:10 +08:00
|
|
|
|
/* This is just an approximation until DWARF can represent Rust more
|
|
|
|
|
precisely. We exclude zero-length structs because they may not
|
|
|
|
|
be tuple structs, and there's no way to tell. */
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
return TYPE_NFIELDS (type) > 0 && rust_underscore_fields (type);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return true if TYPE is a slice type, otherwise false. */
|
|
|
|
|
|
2017-02-03 12:21:19 +08:00
|
|
|
|
static bool
|
2016-04-27 09:38:08 +08:00
|
|
|
|
rust_slice_type_p (struct type *type)
|
|
|
|
|
{
|
|
|
|
|
return (TYPE_CODE (type) == TYPE_CODE_STRUCT
|
|
|
|
|
&& TYPE_TAG_NAME (type) != NULL
|
2017-10-03 02:15:52 +08:00
|
|
|
|
&& (strncmp (TYPE_TAG_NAME (type), "&[", 2) == 0
|
|
|
|
|
|| strcmp (TYPE_TAG_NAME (type), "&str") == 0));
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return true if TYPE is a range type, otherwise false. */
|
|
|
|
|
|
2017-02-03 12:21:19 +08:00
|
|
|
|
static bool
|
2016-04-27 09:38:08 +08:00
|
|
|
|
rust_range_type_p (struct type *type)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
|
|
|
|
|
|| TYPE_NFIELDS (type) > 2
|
|
|
|
|
|| TYPE_TAG_NAME (type) == NULL
|
|
|
|
|
|| strstr (TYPE_TAG_NAME (type), "::Range") == NULL)
|
2017-02-03 12:21:19 +08:00
|
|
|
|
return false;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
if (TYPE_NFIELDS (type) == 0)
|
2017-02-03 12:21:19 +08:00
|
|
|
|
return true;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
if (strcmp (TYPE_FIELD_NAME (type, 0), "start") == 0)
|
|
|
|
|
{
|
|
|
|
|
if (TYPE_NFIELDS (type) == 1)
|
2017-02-03 12:21:19 +08:00
|
|
|
|
return true;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
i = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (TYPE_NFIELDS (type) == 2)
|
|
|
|
|
{
|
|
|
|
|
/* First field had to be "start". */
|
2017-02-03 12:21:19 +08:00
|
|
|
|
return false;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return strcmp (TYPE_FIELD_NAME (type, i), "end") == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return true if TYPE seems to be the type "u8", otherwise false. */
|
|
|
|
|
|
2017-02-03 12:21:19 +08:00
|
|
|
|
static bool
|
2016-04-27 09:38:08 +08:00
|
|
|
|
rust_u8_type_p (struct type *type)
|
|
|
|
|
{
|
|
|
|
|
return (TYPE_CODE (type) == TYPE_CODE_INT
|
|
|
|
|
&& TYPE_UNSIGNED (type)
|
|
|
|
|
&& TYPE_LENGTH (type) == 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return true if TYPE is a Rust character type. */
|
|
|
|
|
|
2017-02-03 12:21:19 +08:00
|
|
|
|
static bool
|
2016-04-27 09:38:08 +08:00
|
|
|
|
rust_chartype_p (struct type *type)
|
|
|
|
|
{
|
|
|
|
|
return (TYPE_CODE (type) == TYPE_CODE_CHAR
|
|
|
|
|
&& TYPE_LENGTH (type) == 4
|
|
|
|
|
&& TYPE_UNSIGNED (type));
|
|
|
|
|
}
|
|
|
|
|
|
Handle dereferencing Rust trait objects
In Rust, virtual tables work a bit differently than they do in C++. In
C++, as you know, they are connected to a particular class hierarchy.
Rust, instead, can generate a virtual table for potentially any type --
in fact, one such virtual table for each trait (a trait is similar to an
abstract class or to a Java interface) that a type implements.
Objects that are referenced via a trait can't currently be inspected by
gdb. This patch implements the Rust equivalent of "set print object".
gdb relies heavily on the C++ ABI to decode virtual tables; primarily to
make "set print object" work; but also "info vtbl". However, Rust does
not currently have a specified ABI, so this approach seems unwise to
emulate.
Instead, I've changed the Rust compiler to emit some DWARF that
describes trait objects (previously their internal structure was
opaque), vtables (currently just a size -- but I hope to expand this in
the future), and the concrete type for which a vtable was emitted.
The concrete type is expressed as a DW_AT_containing_type on the
vtable's type. This is a small extension to DWARF.
This patch adds a new entry to quick_symbol_functions to return the
symtab that holds a data address. Previously there was no way in gdb to
look up a full (only minimal) non-text symbol by address. The psymbol
implementation of this method works by lazily filling in a map that is
added to the objfile. This avoids slowing down psymbol reading for a
feature that is likely to not be used too frequently.
I did not update .gdb_index. My thinking here is that the DWARF 5
indices will obsolete .gdb_index soon-ish, meaning that adding a new
feature to them is probably wasted work. If necessary I can update the
DWARF 5 index code when it lands in gdb.
Regression tested on x86-64 Fedora 25.
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 Tom Tromey <tom@tromey.com>
* gdb.rust/traits.rs: New file.
* gdb.rust/traits.exp: New file.
2017-07-06 20:44:38 +08:00
|
|
|
|
/* 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);
|
2017-11-18 03:05:58 +08:00
|
|
|
|
if (symbol == NULL || symbol->subclass != SYMBOL_RUST_VTABLE)
|
Handle dereferencing Rust trait objects
In Rust, virtual tables work a bit differently than they do in C++. In
C++, as you know, they are connected to a particular class hierarchy.
Rust, instead, can generate a virtual table for potentially any type --
in fact, one such virtual table for each trait (a trait is similar to an
abstract class or to a Java interface) that a type implements.
Objects that are referenced via a trait can't currently be inspected by
gdb. This patch implements the Rust equivalent of "set print object".
gdb relies heavily on the C++ ABI to decode virtual tables; primarily to
make "set print object" work; but also "info vtbl". However, Rust does
not currently have a specified ABI, so this approach seems unwise to
emulate.
Instead, I've changed the Rust compiler to emit some DWARF that
describes trait objects (previously their internal structure was
opaque), vtables (currently just a size -- but I hope to expand this in
the future), and the concrete type for which a vtable was emitted.
The concrete type is expressed as a DW_AT_containing_type on the
vtable's type. This is a small extension to DWARF.
This patch adds a new entry to quick_symbol_functions to return the
symtab that holds a data address. Previously there was no way in gdb to
look up a full (only minimal) non-text symbol by address. The psymbol
implementation of this method works by lazily filling in a map that is
added to the objfile. This avoids slowing down psymbol reading for a
feature that is likely to not be used too frequently.
I did not update .gdb_index. My thinking here is that the DWARF 5
indices will obsolete .gdb_index soon-ish, meaning that adding a new
feature to them is probably wasted work. If necessary I can update the
DWARF 5 index code when it lands in gdb.
Regression tested on x86-64 Fedora 25.
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 Tom Tromey <tom@tromey.com>
* gdb.rust/traits.rs: New file.
* gdb.rust/traits.exp: New file.
2017-07-06 20:44:38 +08:00
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* la_emitchar implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rust_emitchar (int c, struct type *type, struct ui_file *stream, int quoter)
|
|
|
|
|
{
|
|
|
|
|
if (!rust_chartype_p (type))
|
|
|
|
|
generic_emit_char (c, type, stream, quoter,
|
|
|
|
|
target_charset (get_type_arch (type)));
|
|
|
|
|
else if (c == '\\' || c == quoter)
|
|
|
|
|
fprintf_filtered (stream, "\\%c", c);
|
|
|
|
|
else if (c == '\n')
|
|
|
|
|
fputs_filtered ("\\n", stream);
|
|
|
|
|
else if (c == '\r')
|
|
|
|
|
fputs_filtered ("\\r", stream);
|
|
|
|
|
else if (c == '\t')
|
|
|
|
|
fputs_filtered ("\\t", stream);
|
|
|
|
|
else if (c == '\0')
|
|
|
|
|
fputs_filtered ("\\0", stream);
|
|
|
|
|
else if (c >= 32 && c <= 127 && isprint (c))
|
|
|
|
|
fputc_filtered (c, stream);
|
|
|
|
|
else if (c <= 255)
|
|
|
|
|
fprintf_filtered (stream, "\\x%02x", c);
|
|
|
|
|
else
|
|
|
|
|
fprintf_filtered (stream, "\\u{%06x}", c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* la_printchar implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rust_printchar (int c, struct type *type, struct ui_file *stream)
|
|
|
|
|
{
|
|
|
|
|
fputs_filtered ("'", stream);
|
|
|
|
|
LA_EMIT_CHAR (c, type, stream, '\'');
|
|
|
|
|
fputs_filtered ("'", stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* la_printstr implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rust_printstr (struct ui_file *stream, struct type *type,
|
|
|
|
|
const gdb_byte *string, unsigned int length,
|
|
|
|
|
const char *user_encoding, int force_ellipses,
|
|
|
|
|
const struct value_print_options *options)
|
|
|
|
|
{
|
|
|
|
|
/* Rust always uses UTF-8, but let the caller override this if need
|
|
|
|
|
be. */
|
|
|
|
|
const char *encoding = user_encoding;
|
|
|
|
|
if (user_encoding == NULL || !*user_encoding)
|
|
|
|
|
{
|
|
|
|
|
/* In Rust strings, characters are "u8". */
|
|
|
|
|
if (rust_u8_type_p (type))
|
|
|
|
|
encoding = "UTF-8";
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* This is probably some C string, so let's let C deal with
|
|
|
|
|
it. */
|
|
|
|
|
c_printstr (stream, type, string, length, user_encoding,
|
|
|
|
|
force_ellipses, options);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is not ideal as it doesn't use our character printer. */
|
|
|
|
|
generic_printstr (stream, type, string, length, encoding, force_ellipses,
|
|
|
|
|
'"', 0, options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-10-03 03:55:42 +08:00
|
|
|
|
/* Helper function to print a string slice. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rust_val_print_str (struct ui_file *stream, struct value *val,
|
|
|
|
|
const struct value_print_options *options)
|
|
|
|
|
{
|
|
|
|
|
struct value *base = value_struct_elt (&val, NULL, "data_ptr", NULL,
|
|
|
|
|
"slice");
|
|
|
|
|
struct value *len = value_struct_elt (&val, NULL, "length", NULL, "slice");
|
|
|
|
|
|
|
|
|
|
val_print_string (TYPE_TARGET_TYPE (value_type (base)), "UTF-8",
|
|
|
|
|
value_as_address (base), value_as_long (len), stream,
|
|
|
|
|
options);
|
|
|
|
|
}
|
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
/* rust_val_print helper for structs and untagged unions. */
|
2016-10-29 09:00:43 +08:00
|
|
|
|
|
|
|
|
|
static void
|
2016-11-09 00:02:42 +08:00
|
|
|
|
val_print_struct (struct type *type, int embedded_offset,
|
|
|
|
|
CORE_ADDR address, struct ui_file *stream,
|
|
|
|
|
int recurse, struct value *val,
|
2016-11-08 19:32:53 +08:00
|
|
|
|
const struct value_print_options *options)
|
2016-10-29 09:00:43 +08:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int first_field;
|
2017-10-03 03:55:42 +08:00
|
|
|
|
|
|
|
|
|
if (rust_slice_type_p (type) && strcmp (TYPE_NAME (type), "&str") == 0)
|
|
|
|
|
{
|
|
|
|
|
rust_val_print_str (stream, val, options);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-03 12:21:19 +08:00
|
|
|
|
bool is_tuple = rust_tuple_type_p (type);
|
|
|
|
|
bool is_tuple_struct = !is_tuple && rust_tuple_struct_type_p (type);
|
2016-10-29 09:00:43 +08:00
|
|
|
|
struct value_print_options opts;
|
|
|
|
|
|
|
|
|
|
if (!is_tuple)
|
|
|
|
|
{
|
|
|
|
|
if (TYPE_TAG_NAME (type) != NULL)
|
|
|
|
|
fprintf_filtered (stream, "%s", TYPE_TAG_NAME (type));
|
|
|
|
|
|
|
|
|
|
if (TYPE_NFIELDS (type) == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (TYPE_TAG_NAME (type) != NULL)
|
|
|
|
|
fputs_filtered (" ", stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_tuple || is_tuple_struct)
|
|
|
|
|
fputs_filtered ("(", stream);
|
|
|
|
|
else
|
|
|
|
|
fputs_filtered ("{", stream);
|
|
|
|
|
|
|
|
|
|
opts = *options;
|
|
|
|
|
opts.deref_ref = 0;
|
|
|
|
|
|
|
|
|
|
first_field = 1;
|
|
|
|
|
for (i = 0; i < TYPE_NFIELDS (type); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (field_is_static (&TYPE_FIELD (type, i)))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!first_field)
|
|
|
|
|
fputs_filtered (",", stream);
|
|
|
|
|
|
|
|
|
|
if (options->prettyformat)
|
|
|
|
|
{
|
2017-02-03 12:01:11 +08:00
|
|
|
|
fputs_filtered ("\n", stream);
|
|
|
|
|
print_spaces_filtered (2 + 2 * recurse, stream);
|
2016-10-29 09:00:43 +08:00
|
|
|
|
}
|
|
|
|
|
else if (!first_field)
|
|
|
|
|
fputs_filtered (" ", stream);
|
|
|
|
|
|
|
|
|
|
first_field = 0;
|
|
|
|
|
|
|
|
|
|
if (!is_tuple && !is_tuple_struct)
|
|
|
|
|
{
|
2017-02-03 12:01:11 +08:00
|
|
|
|
fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
|
|
|
|
|
fputs_filtered (": ", stream);
|
2016-10-29 09:00:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val_print (TYPE_FIELD_TYPE (type, i),
|
2017-02-03 12:01:11 +08:00
|
|
|
|
embedded_offset + TYPE_FIELD_BITPOS (type, i) / 8,
|
|
|
|
|
address,
|
|
|
|
|
stream, recurse + 1, val, &opts,
|
|
|
|
|
current_language);
|
2016-10-29 09:00:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (options->prettyformat)
|
|
|
|
|
{
|
|
|
|
|
fputs_filtered ("\n", stream);
|
|
|
|
|
print_spaces_filtered (2 * recurse, stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_tuple || is_tuple_struct)
|
|
|
|
|
fputs_filtered (")", stream);
|
|
|
|
|
else
|
|
|
|
|
fputs_filtered ("}", stream);
|
|
|
|
|
}
|
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
/* rust_val_print helper for discriminated unions (Rust enums). */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rust_print_enum (struct type *type, int embedded_offset,
|
|
|
|
|
CORE_ADDR address, struct ui_file *stream,
|
|
|
|
|
int recurse, struct value *val,
|
|
|
|
|
const struct value_print_options *options)
|
|
|
|
|
{
|
|
|
|
|
struct value_print_options opts = *options;
|
|
|
|
|
|
|
|
|
|
opts.deref_ref = 0;
|
|
|
|
|
|
|
|
|
|
const gdb_byte *valaddr = value_contents_for_printing (val);
|
|
|
|
|
struct field *variant_field = rust_enum_variant (type, valaddr);
|
|
|
|
|
embedded_offset += FIELD_BITPOS (*variant_field) / 8;
|
|
|
|
|
struct type *variant_type = FIELD_TYPE (*variant_field);
|
|
|
|
|
|
|
|
|
|
int nfields = TYPE_NFIELDS (variant_type);
|
|
|
|
|
|
|
|
|
|
bool is_tuple = rust_tuple_struct_type_p (variant_type);
|
|
|
|
|
|
|
|
|
|
fprintf_filtered (stream, "%s", TYPE_NAME (variant_type));
|
|
|
|
|
if (nfields == 0)
|
|
|
|
|
{
|
|
|
|
|
/* In case of a nullary variant like 'None', just output
|
|
|
|
|
the name. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* In case of a non-nullary variant, we output 'Foo(x,y,z)'. */
|
|
|
|
|
if (is_tuple)
|
|
|
|
|
fprintf_filtered (stream, "(");
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* struct variant. */
|
|
|
|
|
fprintf_filtered (stream, "{");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool first_field = true;
|
|
|
|
|
for (int j = 0; j < TYPE_NFIELDS (variant_type); j++)
|
|
|
|
|
{
|
|
|
|
|
if (!first_field)
|
|
|
|
|
fputs_filtered (", ", stream);
|
|
|
|
|
first_field = false;
|
|
|
|
|
|
|
|
|
|
if (!is_tuple)
|
|
|
|
|
fprintf_filtered (stream, "%s: ",
|
|
|
|
|
TYPE_FIELD_NAME (variant_type, j));
|
|
|
|
|
|
|
|
|
|
val_print (TYPE_FIELD_TYPE (variant_type, j),
|
|
|
|
|
(embedded_offset
|
|
|
|
|
+ TYPE_FIELD_BITPOS (variant_type, j) / 8),
|
|
|
|
|
address,
|
|
|
|
|
stream, recurse + 1, val, &opts,
|
|
|
|
|
current_language);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_tuple)
|
|
|
|
|
fputs_filtered (")", stream);
|
|
|
|
|
else
|
|
|
|
|
fputs_filtered ("}", stream);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-27 09:38:08 +08:00
|
|
|
|
static const struct generic_val_print_decorations rust_decorations =
|
|
|
|
|
{
|
|
|
|
|
/* Complex isn't used in Rust, but we provide C-ish values just in
|
|
|
|
|
case. */
|
|
|
|
|
"",
|
|
|
|
|
" + ",
|
|
|
|
|
" * I",
|
|
|
|
|
"true",
|
|
|
|
|
"false",
|
2016-06-27 23:46:59 +08:00
|
|
|
|
"()",
|
2016-04-27 09:38:08 +08:00
|
|
|
|
"[",
|
|
|
|
|
"]"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* la_val_print implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static void
|
2016-11-09 00:02:42 +08:00
|
|
|
|
rust_val_print (struct type *type, int embedded_offset,
|
2016-04-27 09:38:08 +08:00
|
|
|
|
CORE_ADDR address, struct ui_file *stream, int recurse,
|
2016-11-09 00:02:42 +08:00
|
|
|
|
struct value *val,
|
2016-04-27 09:38:08 +08:00
|
|
|
|
const struct value_print_options *options)
|
|
|
|
|
{
|
2016-11-09 00:02:42 +08:00
|
|
|
|
const gdb_byte *valaddr = value_contents_for_printing (val);
|
|
|
|
|
|
2016-04-27 09:38:08 +08:00
|
|
|
|
type = check_typedef (type);
|
|
|
|
|
switch (TYPE_CODE (type))
|
|
|
|
|
{
|
|
|
|
|
case TYPE_CODE_PTR:
|
|
|
|
|
{
|
|
|
|
|
LONGEST low_bound, high_bound;
|
|
|
|
|
|
|
|
|
|
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_ARRAY
|
|
|
|
|
&& rust_u8_type_p (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type)))
|
|
|
|
|
&& get_array_bounds (TYPE_TARGET_TYPE (type), &low_bound,
|
|
|
|
|
&high_bound)) {
|
|
|
|
|
/* We have a pointer to a byte string, so just print
|
|
|
|
|
that. */
|
|
|
|
|
struct type *elttype = check_typedef (TYPE_TARGET_TYPE (type));
|
|
|
|
|
CORE_ADDR addr;
|
|
|
|
|
struct gdbarch *arch = get_type_arch (type);
|
|
|
|
|
int unit_size = gdbarch_addressable_memory_unit_size (arch);
|
|
|
|
|
|
|
|
|
|
addr = unpack_pointer (type, valaddr + embedded_offset * unit_size);
|
|
|
|
|
if (options->addressprint)
|
|
|
|
|
{
|
|
|
|
|
fputs_filtered (paddress (arch, addr), stream);
|
|
|
|
|
fputs_filtered (" ", stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fputs_filtered ("b", stream);
|
|
|
|
|
val_print_string (TYPE_TARGET_TYPE (elttype), "ASCII", addr,
|
|
|
|
|
high_bound - low_bound + 1, stream,
|
|
|
|
|
options);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Fall through. */
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_METHODPTR:
|
|
|
|
|
case TYPE_CODE_MEMBERPTR:
|
2016-11-09 00:02:42 +08:00
|
|
|
|
c_val_print (type, embedded_offset, address, stream,
|
2016-04-27 09:38:08 +08:00
|
|
|
|
recurse, val, options);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_INT:
|
|
|
|
|
/* Recognize the unit type. */
|
|
|
|
|
if (TYPE_UNSIGNED (type) && TYPE_LENGTH (type) == 0
|
|
|
|
|
&& TYPE_NAME (type) != NULL && strcmp (TYPE_NAME (type), "()") == 0)
|
|
|
|
|
{
|
|
|
|
|
fputs_filtered ("()", stream);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
goto generic_print;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_STRING:
|
|
|
|
|
{
|
|
|
|
|
struct gdbarch *arch = get_type_arch (type);
|
|
|
|
|
int unit_size = gdbarch_addressable_memory_unit_size (arch);
|
|
|
|
|
LONGEST low_bound, high_bound;
|
|
|
|
|
|
|
|
|
|
if (!get_array_bounds (type, &low_bound, &high_bound))
|
|
|
|
|
error (_("Could not determine the array bounds"));
|
|
|
|
|
|
|
|
|
|
/* If we see a plain TYPE_CODE_STRING, then we're printing a
|
|
|
|
|
byte string, hence the choice of "ASCII" as the
|
|
|
|
|
encoding. */
|
|
|
|
|
fputs_filtered ("b", stream);
|
|
|
|
|
rust_printstr (stream, TYPE_TARGET_TYPE (type),
|
|
|
|
|
valaddr + embedded_offset * unit_size,
|
|
|
|
|
high_bound - low_bound + 1, "ASCII", 0, options);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
|
|
|
|
{
|
|
|
|
|
LONGEST low_bound, high_bound;
|
|
|
|
|
|
|
|
|
|
if (get_array_bounds (type, &low_bound, &high_bound)
|
|
|
|
|
&& high_bound - low_bound + 1 == 0)
|
|
|
|
|
fputs_filtered ("[]", stream);
|
|
|
|
|
else
|
|
|
|
|
goto generic_print;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_UNION:
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
/* Untagged unions are printed as if they are structs. Since
|
|
|
|
|
the field bit positions overlap in the debuginfo, the code
|
|
|
|
|
for printing a union is same as that for a struct, the only
|
|
|
|
|
difference is that the input type will have overlapping
|
|
|
|
|
fields. */
|
|
|
|
|
val_print_struct (type, embedded_offset, address, stream,
|
|
|
|
|
recurse, val, options);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_STRUCT:
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
if (rust_enum_p (type))
|
|
|
|
|
rust_print_enum (type, embedded_offset, address, stream,
|
|
|
|
|
recurse, val, options);
|
|
|
|
|
else
|
|
|
|
|
val_print_struct (type, embedded_offset, address, stream,
|
|
|
|
|
recurse, val, options);
|
2016-10-29 09:00:43 +08:00
|
|
|
|
break;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
2016-10-29 09:00:43 +08:00
|
|
|
|
default:
|
|
|
|
|
generic_print:
|
|
|
|
|
/* Nothing special yet. */
|
2016-11-09 00:02:42 +08:00
|
|
|
|
generic_val_print (type, embedded_offset, address, stream,
|
2016-10-29 09:00:43 +08:00
|
|
|
|
recurse, val, options, &rust_decorations);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
2016-10-29 09:00:43 +08:00
|
|
|
|
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
2016-10-29 09:00:43 +08:00
|
|
|
|
static void
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
rust_internal_print_type (struct type *type, const char *varstring,
|
|
|
|
|
struct ui_file *stream, int show, int level,
|
|
|
|
|
const struct type_print_options *flags,
|
|
|
|
|
bool for_rust_enum);
|
2016-10-29 09:00:43 +08:00
|
|
|
|
|
|
|
|
|
/* Print a struct or union typedef. */
|
|
|
|
|
static void
|
|
|
|
|
rust_print_struct_def (struct type *type, const char *varstring,
|
2017-02-03 12:01:11 +08:00
|
|
|
|
struct ui_file *stream, int show, int level,
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
const struct type_print_options *flags,
|
|
|
|
|
bool for_rust_enum)
|
2016-10-29 09:00:43 +08:00
|
|
|
|
{
|
2017-02-03 12:01:11 +08:00
|
|
|
|
/* Print a tuple type simply. */
|
|
|
|
|
if (rust_tuple_type_p (type))
|
|
|
|
|
{
|
|
|
|
|
fputs_filtered (TYPE_TAG_NAME (type), stream);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
2017-02-03 12:01:11 +08:00
|
|
|
|
/* If we see a base class, delegate to C. */
|
|
|
|
|
if (TYPE_N_BASECLASSES (type) > 0)
|
|
|
|
|
c_print_type (type, varstring, stream, show, level, flags);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
/* Compute properties of TYPE here because, in the enum case, the
|
|
|
|
|
rest of the code ends up looking only at the variant part. */
|
|
|
|
|
const char *tagname = TYPE_TAG_NAME (type);
|
|
|
|
|
bool is_tuple_struct = rust_tuple_struct_type_p (type);
|
|
|
|
|
bool is_tuple = rust_tuple_type_p (type);
|
|
|
|
|
bool is_enum = rust_enum_p (type);
|
|
|
|
|
bool is_univariant = false;
|
2016-10-29 09:00:43 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
int enum_discriminant_index = -1;
|
|
|
|
|
|
|
|
|
|
if (for_rust_enum)
|
|
|
|
|
{
|
|
|
|
|
/* Already printing an outer enum, so nothing to print here. */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* This code path is also used by unions and enums. */
|
|
|
|
|
if (is_enum)
|
|
|
|
|
{
|
|
|
|
|
fputs_filtered ("enum ", stream);
|
|
|
|
|
type = TYPE_FIELD_TYPE (type, 0);
|
|
|
|
|
|
|
|
|
|
struct dynamic_prop *discriminant_prop
|
|
|
|
|
= get_dyn_prop (DYN_PROP_DISCRIMINATED, type);
|
|
|
|
|
struct discriminant_info *info
|
|
|
|
|
= (struct discriminant_info *) discriminant_prop->data.baton;
|
|
|
|
|
enum_discriminant_index = info->discriminant_index;
|
|
|
|
|
}
|
|
|
|
|
else if (TYPE_CODE (type) == TYPE_CODE_UNION && TYPE_NFIELDS (type) == 1)
|
|
|
|
|
{
|
|
|
|
|
/* Probably a univariant enum. */
|
|
|
|
|
fputs_filtered ("enum ", stream);
|
|
|
|
|
is_univariant = true;
|
|
|
|
|
}
|
|
|
|
|
else if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
|
|
|
|
|
fputs_filtered ("struct ", stream);
|
|
|
|
|
else
|
|
|
|
|
fputs_filtered ("union ", stream);
|
2016-10-29 09:00:43 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
if (tagname != NULL)
|
|
|
|
|
fputs_filtered (tagname, stream);
|
|
|
|
|
}
|
2016-10-29 09:00:43 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
if (TYPE_NFIELDS (type) == 0 && !is_tuple)
|
2017-02-03 12:01:11 +08:00
|
|
|
|
return;
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
if (for_rust_enum)
|
|
|
|
|
fputs_filtered (is_tuple_struct ? "(" : "{", stream);
|
|
|
|
|
else
|
|
|
|
|
fputs_filtered (is_tuple_struct ? " (\n" : " {\n", stream);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
for (int i = 0; i < TYPE_NFIELDS (type); ++i)
|
2017-02-03 12:01:11 +08:00
|
|
|
|
{
|
|
|
|
|
QUIT;
|
|
|
|
|
if (field_is_static (&TYPE_FIELD (type, i)))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* We'd like to print "pub" here as needed, but rustc
|
|
|
|
|
doesn't emit the debuginfo, and our types don't have
|
|
|
|
|
cplus_struct_type attached. */
|
|
|
|
|
|
|
|
|
|
/* For a tuple struct we print the type but nothing
|
|
|
|
|
else. */
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
if (!for_rust_enum)
|
|
|
|
|
print_spaces_filtered (level + 2, stream);
|
|
|
|
|
if (is_enum)
|
|
|
|
|
{
|
|
|
|
|
if (i == enum_discriminant_index)
|
|
|
|
|
continue;
|
|
|
|
|
fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
|
|
|
|
|
}
|
|
|
|
|
else if (is_univariant)
|
|
|
|
|
{
|
|
|
|
|
const char *name
|
|
|
|
|
= rust_last_path_segment (TYPE_NAME (TYPE_FIELD_TYPE (type, i)));
|
|
|
|
|
fputs_filtered (name, stream);
|
|
|
|
|
}
|
|
|
|
|
else if (!is_tuple_struct)
|
2017-02-03 12:01:11 +08:00
|
|
|
|
fprintf_filtered (stream, "%s: ", TYPE_FIELD_NAME (type, i));
|
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
rust_internal_print_type (TYPE_FIELD_TYPE (type, i), NULL,
|
|
|
|
|
stream,
|
|
|
|
|
((is_enum || is_univariant) ? show : show - 1),
|
|
|
|
|
level + 2, flags, is_enum || is_univariant);
|
|
|
|
|
if (!for_rust_enum)
|
|
|
|
|
fputs_filtered (",\n", stream);
|
|
|
|
|
else if (i + 1 < TYPE_NFIELDS (type))
|
|
|
|
|
fputs_filtered (", ", stream);
|
2017-02-03 12:01:11 +08:00
|
|
|
|
}
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
if (!for_rust_enum)
|
|
|
|
|
print_spaces_filtered (level, stream);
|
|
|
|
|
fputs_filtered (is_tuple_struct ? ")" : "}", stream);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* la_print_typedef implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rust_print_typedef (struct type *type,
|
|
|
|
|
struct symbol *new_symbol,
|
|
|
|
|
struct ui_file *stream)
|
|
|
|
|
{
|
|
|
|
|
type = check_typedef (type);
|
|
|
|
|
fprintf_filtered (stream, "type %s = ", SYMBOL_PRINT_NAME (new_symbol));
|
|
|
|
|
type_print (type, "", stream, 0);
|
|
|
|
|
fprintf_filtered (stream, ";\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* la_print_type implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static void
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
rust_internal_print_type (struct type *type, const char *varstring,
|
|
|
|
|
struct ui_file *stream, int show, int level,
|
|
|
|
|
const struct type_print_options *flags,
|
|
|
|
|
bool for_rust_enum)
|
2016-04-27 09:38:08 +08:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
QUIT;
|
|
|
|
|
if (show <= 0
|
|
|
|
|
&& TYPE_NAME (type) != NULL)
|
|
|
|
|
{
|
2016-06-27 23:46:59 +08:00
|
|
|
|
/* Rust calls the unit type "void" in its debuginfo,
|
|
|
|
|
but we don't want to print it as that. */
|
|
|
|
|
if (TYPE_CODE (type) == TYPE_CODE_VOID)
|
|
|
|
|
fputs_filtered ("()", stream);
|
|
|
|
|
else
|
|
|
|
|
fputs_filtered (TYPE_NAME (type), stream);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type = check_typedef (type);
|
|
|
|
|
switch (TYPE_CODE (type))
|
|
|
|
|
{
|
2016-06-27 23:46:59 +08:00
|
|
|
|
case TYPE_CODE_VOID:
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
/* If we have an enum, we've already printed the type's
|
|
|
|
|
unqualified name, and there is nothing else to print
|
|
|
|
|
here. */
|
|
|
|
|
if (!for_rust_enum)
|
|
|
|
|
fputs_filtered ("()", stream);
|
2016-06-27 23:46:59 +08:00
|
|
|
|
break;
|
|
|
|
|
|
2016-04-27 09:38:08 +08:00
|
|
|
|
case TYPE_CODE_FUNC:
|
|
|
|
|
/* Delegate varargs to the C printer. */
|
|
|
|
|
if (TYPE_VARARGS (type))
|
|
|
|
|
goto c_printer;
|
|
|
|
|
|
|
|
|
|
fputs_filtered ("fn ", stream);
|
|
|
|
|
if (varstring != NULL)
|
|
|
|
|
fputs_filtered (varstring, stream);
|
|
|
|
|
fputs_filtered ("(", stream);
|
|
|
|
|
for (i = 0; i < TYPE_NFIELDS (type); ++i)
|
|
|
|
|
{
|
|
|
|
|
QUIT;
|
|
|
|
|
if (i > 0)
|
|
|
|
|
fputs_filtered (", ", stream);
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
rust_internal_print_type (TYPE_FIELD_TYPE (type, i), "", stream,
|
|
|
|
|
-1, 0, flags, false);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
2016-06-27 23:46:59 +08:00
|
|
|
|
fputs_filtered (")", stream);
|
|
|
|
|
/* If it returns unit, we can omit the return type. */
|
|
|
|
|
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
|
|
|
|
|
{
|
|
|
|
|
fputs_filtered (" -> ", stream);
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
rust_internal_print_type (TYPE_TARGET_TYPE (type), "", stream,
|
|
|
|
|
-1, 0, flags, false);
|
2016-06-27 23:46:59 +08:00
|
|
|
|
}
|
2016-04-27 09:38:08 +08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
|
|
|
|
{
|
|
|
|
|
LONGEST low_bound, high_bound;
|
|
|
|
|
|
|
|
|
|
fputs_filtered ("[", stream);
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
rust_internal_print_type (TYPE_TARGET_TYPE (type), NULL,
|
|
|
|
|
stream, show - 1, level, flags, false);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
if (TYPE_HIGH_BOUND_KIND (TYPE_INDEX_TYPE (type)) == PROP_LOCEXPR
|
|
|
|
|
|| TYPE_HIGH_BOUND_KIND (TYPE_INDEX_TYPE (type)) == PROP_LOCLIST)
|
2017-05-22 07:00:10 +08:00
|
|
|
|
fprintf_filtered (stream, "; variable length");
|
2016-04-27 09:38:08 +08:00
|
|
|
|
else if (get_array_bounds (type, &low_bound, &high_bound))
|
2017-05-22 07:00:10 +08:00
|
|
|
|
fprintf_filtered (stream, "; %s",
|
2016-04-27 09:38:08 +08:00
|
|
|
|
plongest (high_bound - low_bound + 1));
|
|
|
|
|
fputs_filtered ("]", stream);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
case TYPE_CODE_UNION:
|
2016-04-27 09:38:08 +08:00
|
|
|
|
case TYPE_CODE_STRUCT:
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
rust_print_struct_def (type, varstring, stream, show, level, flags,
|
|
|
|
|
for_rust_enum);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_ENUM:
|
|
|
|
|
{
|
|
|
|
|
int i, len = 0;
|
|
|
|
|
|
|
|
|
|
fputs_filtered ("enum ", stream);
|
|
|
|
|
if (TYPE_TAG_NAME (type) != NULL)
|
|
|
|
|
{
|
|
|
|
|
fputs_filtered (TYPE_TAG_NAME (type), stream);
|
|
|
|
|
fputs_filtered (" ", stream);
|
|
|
|
|
len = strlen (TYPE_TAG_NAME (type));
|
|
|
|
|
}
|
|
|
|
|
fputs_filtered ("{\n", stream);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < TYPE_NFIELDS (type); ++i)
|
|
|
|
|
{
|
|
|
|
|
const char *name = TYPE_FIELD_NAME (type, i);
|
|
|
|
|
|
|
|
|
|
QUIT;
|
|
|
|
|
|
|
|
|
|
if (len > 0
|
|
|
|
|
&& strncmp (name, TYPE_TAG_NAME (type), len) == 0
|
|
|
|
|
&& name[len] == ':'
|
|
|
|
|
&& name[len + 1] == ':')
|
|
|
|
|
name += len + 2;
|
|
|
|
|
fprintfi_filtered (level + 2, stream, "%s,\n", name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fputs_filtered ("}", stream);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
c_printer:
|
|
|
|
|
c_print_type (type, varstring, stream, show, level, flags);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
static void
|
|
|
|
|
rust_print_type (struct type *type, const char *varstring,
|
|
|
|
|
struct ui_file *stream, int show, int level,
|
|
|
|
|
const struct type_print_options *flags)
|
|
|
|
|
{
|
|
|
|
|
rust_internal_print_type (type, varstring, stream, show, level,
|
|
|
|
|
flags, false);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Compute the alignment of the type T. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
rust_type_alignment (struct type *t)
|
|
|
|
|
{
|
|
|
|
|
t = check_typedef (t);
|
|
|
|
|
switch (TYPE_CODE (t))
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
error (_("Could not compute alignment of type"));
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_PTR:
|
|
|
|
|
case TYPE_CODE_ENUM:
|
|
|
|
|
case TYPE_CODE_INT:
|
|
|
|
|
case TYPE_CODE_FLT:
|
|
|
|
|
case TYPE_CODE_REF:
|
|
|
|
|
case TYPE_CODE_CHAR:
|
|
|
|
|
case TYPE_CODE_BOOL:
|
|
|
|
|
return TYPE_LENGTH (t);
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
|
|
|
|
case TYPE_CODE_COMPLEX:
|
|
|
|
|
return rust_type_alignment (TYPE_TARGET_TYPE (t));
|
|
|
|
|
|
|
|
|
|
case TYPE_CODE_STRUCT:
|
|
|
|
|
case TYPE_CODE_UNION:
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int align = 1;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < TYPE_NFIELDS (t); ++i)
|
|
|
|
|
{
|
|
|
|
|
int a = rust_type_alignment (TYPE_FIELD_TYPE (t, i));
|
|
|
|
|
if (a > align)
|
|
|
|
|
align = a;
|
|
|
|
|
}
|
|
|
|
|
return align;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Like arch_composite_type, but uses TYPE to decide how to allocate
|
|
|
|
|
-- either on an obstack or on a gdbarch. */
|
|
|
|
|
|
|
|
|
|
static struct type *
|
|
|
|
|
rust_composite_type (struct type *original,
|
|
|
|
|
const char *name,
|
|
|
|
|
const char *field1, struct type *type1,
|
|
|
|
|
const char *field2, struct type *type2)
|
|
|
|
|
{
|
|
|
|
|
struct type *result = alloc_type_copy (original);
|
|
|
|
|
int i, nfields, bitpos;
|
|
|
|
|
|
|
|
|
|
nfields = 0;
|
|
|
|
|
if (field1 != NULL)
|
|
|
|
|
++nfields;
|
|
|
|
|
if (field2 != NULL)
|
|
|
|
|
++nfields;
|
|
|
|
|
|
|
|
|
|
TYPE_CODE (result) = TYPE_CODE_STRUCT;
|
|
|
|
|
TYPE_NAME (result) = name;
|
|
|
|
|
TYPE_TAG_NAME (result) = name;
|
|
|
|
|
|
|
|
|
|
TYPE_NFIELDS (result) = nfields;
|
|
|
|
|
TYPE_FIELDS (result)
|
|
|
|
|
= (struct field *) TYPE_ZALLOC (result, nfields * sizeof (struct field));
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
bitpos = 0;
|
|
|
|
|
if (field1 != NULL)
|
|
|
|
|
{
|
|
|
|
|
struct field *field = &TYPE_FIELD (result, i);
|
|
|
|
|
|
|
|
|
|
SET_FIELD_BITPOS (*field, bitpos);
|
|
|
|
|
bitpos += TYPE_LENGTH (type1) * TARGET_CHAR_BIT;
|
|
|
|
|
|
|
|
|
|
FIELD_NAME (*field) = field1;
|
|
|
|
|
FIELD_TYPE (*field) = type1;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
if (field2 != NULL)
|
|
|
|
|
{
|
|
|
|
|
struct field *field = &TYPE_FIELD (result, i);
|
|
|
|
|
int align = rust_type_alignment (type2);
|
|
|
|
|
|
|
|
|
|
if (align != 0)
|
|
|
|
|
{
|
|
|
|
|
int delta;
|
|
|
|
|
|
|
|
|
|
align *= TARGET_CHAR_BIT;
|
|
|
|
|
delta = bitpos % align;
|
|
|
|
|
if (delta != 0)
|
|
|
|
|
bitpos += align - delta;
|
|
|
|
|
}
|
|
|
|
|
SET_FIELD_BITPOS (*field, bitpos);
|
|
|
|
|
|
|
|
|
|
FIELD_NAME (*field) = field2;
|
|
|
|
|
FIELD_TYPE (*field) = type2;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i > 0)
|
|
|
|
|
TYPE_LENGTH (result)
|
|
|
|
|
= (TYPE_FIELD_BITPOS (result, i - 1) / TARGET_CHAR_BIT +
|
|
|
|
|
TYPE_LENGTH (TYPE_FIELD_TYPE (result, i - 1)));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* See rust-lang.h. */
|
|
|
|
|
|
|
|
|
|
struct type *
|
|
|
|
|
rust_slice_type (const char *name, struct type *elt_type,
|
|
|
|
|
struct type *usize_type)
|
|
|
|
|
{
|
|
|
|
|
struct type *type;
|
|
|
|
|
|
|
|
|
|
elt_type = lookup_pointer_type (elt_type);
|
|
|
|
|
type = rust_composite_type (elt_type, name,
|
|
|
|
|
"data_ptr", elt_type,
|
|
|
|
|
"length", usize_type);
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum rust_primitive_types
|
|
|
|
|
{
|
|
|
|
|
rust_primitive_bool,
|
|
|
|
|
rust_primitive_char,
|
|
|
|
|
rust_primitive_i8,
|
|
|
|
|
rust_primitive_u8,
|
|
|
|
|
rust_primitive_i16,
|
|
|
|
|
rust_primitive_u16,
|
|
|
|
|
rust_primitive_i32,
|
|
|
|
|
rust_primitive_u32,
|
|
|
|
|
rust_primitive_i64,
|
|
|
|
|
rust_primitive_u64,
|
|
|
|
|
rust_primitive_isize,
|
|
|
|
|
rust_primitive_usize,
|
|
|
|
|
rust_primitive_f32,
|
|
|
|
|
rust_primitive_f64,
|
|
|
|
|
rust_primitive_unit,
|
|
|
|
|
rust_primitive_str,
|
|
|
|
|
nr_rust_primitive_types
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* la_language_arch_info implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rust_language_arch_info (struct gdbarch *gdbarch,
|
|
|
|
|
struct language_arch_info *lai)
|
|
|
|
|
{
|
|
|
|
|
const struct builtin_type *builtin = builtin_type (gdbarch);
|
|
|
|
|
struct type *tem;
|
|
|
|
|
struct type **types;
|
|
|
|
|
unsigned int length;
|
|
|
|
|
|
|
|
|
|
types = GDBARCH_OBSTACK_CALLOC (gdbarch, nr_rust_primitive_types + 1,
|
|
|
|
|
struct type *);
|
|
|
|
|
|
|
|
|
|
types[rust_primitive_bool] = arch_boolean_type (gdbarch, 8, 1, "bool");
|
|
|
|
|
types[rust_primitive_char] = arch_character_type (gdbarch, 32, 1, "char");
|
|
|
|
|
types[rust_primitive_i8] = arch_integer_type (gdbarch, 8, 0, "i8");
|
|
|
|
|
types[rust_primitive_u8] = arch_integer_type (gdbarch, 8, 1, "u8");
|
|
|
|
|
types[rust_primitive_i16] = arch_integer_type (gdbarch, 16, 0, "i16");
|
|
|
|
|
types[rust_primitive_u16] = arch_integer_type (gdbarch, 16, 1, "u16");
|
|
|
|
|
types[rust_primitive_i32] = arch_integer_type (gdbarch, 32, 0, "i32");
|
|
|
|
|
types[rust_primitive_u32] = arch_integer_type (gdbarch, 32, 1, "u32");
|
|
|
|
|
types[rust_primitive_i64] = arch_integer_type (gdbarch, 64, 0, "i64");
|
|
|
|
|
types[rust_primitive_u64] = arch_integer_type (gdbarch, 64, 1, "u64");
|
|
|
|
|
|
|
|
|
|
length = 8 * TYPE_LENGTH (builtin->builtin_data_ptr);
|
|
|
|
|
types[rust_primitive_isize] = arch_integer_type (gdbarch, length, 0, "isize");
|
|
|
|
|
types[rust_primitive_usize] = arch_integer_type (gdbarch, length, 1, "usize");
|
|
|
|
|
|
2016-09-06 23:31:03 +08:00
|
|
|
|
types[rust_primitive_f32] = arch_float_type (gdbarch, 32, "f32",
|
|
|
|
|
floatformats_ieee_single);
|
|
|
|
|
types[rust_primitive_f64] = arch_float_type (gdbarch, 64, "f64",
|
|
|
|
|
floatformats_ieee_double);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
types[rust_primitive_unit] = arch_integer_type (gdbarch, 0, 1, "()");
|
|
|
|
|
|
|
|
|
|
tem = make_cv_type (1, 0, types[rust_primitive_u8], NULL);
|
|
|
|
|
types[rust_primitive_str] = rust_slice_type ("&str", tem,
|
|
|
|
|
types[rust_primitive_usize]);
|
|
|
|
|
|
|
|
|
|
lai->primitive_type_vector = types;
|
|
|
|
|
lai->bool_type_default = types[rust_primitive_bool];
|
|
|
|
|
lai->string_char_type = types[rust_primitive_u8];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* A helper for rust_evaluate_subexp that handles OP_FUNCALL. */
|
|
|
|
|
|
|
|
|
|
static struct value *
|
|
|
|
|
rust_evaluate_funcall (struct expression *exp, int *pos, enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int num_args = exp->elts[*pos + 1].longconst;
|
|
|
|
|
const char *method;
|
|
|
|
|
struct value *function, *result, *arg0;
|
|
|
|
|
struct type *type, *fn_type;
|
|
|
|
|
const struct block *block;
|
|
|
|
|
struct block_symbol sym;
|
|
|
|
|
|
|
|
|
|
/* For an ordinary function call we can simply defer to the
|
|
|
|
|
generic implementation. */
|
|
|
|
|
if (exp->elts[*pos + 3].opcode != STRUCTOP_STRUCT)
|
|
|
|
|
return evaluate_subexp_standard (NULL, exp, pos, noside);
|
|
|
|
|
|
|
|
|
|
/* Skip over the OP_FUNCALL and the STRUCTOP_STRUCT. */
|
|
|
|
|
*pos += 4;
|
|
|
|
|
method = &exp->elts[*pos + 1].string;
|
|
|
|
|
*pos += 3 + BYTES_TO_EXP_ELEM (exp->elts[*pos].longconst + 1);
|
|
|
|
|
|
|
|
|
|
/* Evaluate the argument to STRUCTOP_STRUCT, then find its
|
|
|
|
|
type in order to look up the method. */
|
|
|
|
|
arg0 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_SKIP)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < num_args; ++i)
|
|
|
|
|
evaluate_subexp (NULL_TYPE, exp, pos, noside);
|
|
|
|
|
return arg0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-22 23:51:20 +08:00
|
|
|
|
std::vector<struct value *> args (num_args + 1);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
args[0] = arg0;
|
|
|
|
|
|
|
|
|
|
/* We don't yet implement real Deref semantics. */
|
|
|
|
|
while (TYPE_CODE (value_type (args[0])) == TYPE_CODE_PTR)
|
|
|
|
|
args[0] = value_ind (args[0]);
|
|
|
|
|
|
|
|
|
|
type = value_type (args[0]);
|
|
|
|
|
if ((TYPE_CODE (type) != TYPE_CODE_STRUCT
|
|
|
|
|
&& TYPE_CODE (type) != TYPE_CODE_UNION
|
|
|
|
|
&& TYPE_CODE (type) != TYPE_CODE_ENUM)
|
|
|
|
|
|| rust_tuple_type_p (type))
|
|
|
|
|
error (_("Method calls only supported on struct or enum types"));
|
|
|
|
|
if (TYPE_TAG_NAME (type) == NULL)
|
|
|
|
|
error (_("Method call on nameless type"));
|
|
|
|
|
|
2016-09-22 23:51:20 +08:00
|
|
|
|
std::string name = std::string (TYPE_TAG_NAME (type)) + "::" + method;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
block = get_selected_block (0);
|
2016-09-22 23:51:20 +08:00
|
|
|
|
sym = lookup_symbol (name.c_str (), block, VAR_DOMAIN, NULL);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
if (sym.symbol == NULL)
|
2016-09-22 23:51:20 +08:00
|
|
|
|
error (_("Could not find function named '%s'"), name.c_str ());
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
fn_type = SYMBOL_TYPE (sym.symbol);
|
|
|
|
|
if (TYPE_NFIELDS (fn_type) == 0)
|
2016-09-22 23:51:20 +08:00
|
|
|
|
error (_("Function '%s' takes no arguments"), name.c_str ());
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
if (TYPE_CODE (TYPE_FIELD_TYPE (fn_type, 0)) == TYPE_CODE_PTR)
|
|
|
|
|
args[0] = value_addr (args[0]);
|
|
|
|
|
|
|
|
|
|
function = address_of_variable (sym.symbol, block);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_args; ++i)
|
|
|
|
|
args[i + 1] = evaluate_subexp (NULL_TYPE, exp, pos, noside);
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
result = value_zero (TYPE_TARGET_TYPE (fn_type), not_lval);
|
|
|
|
|
else
|
Stop assuming no-debug-info functions return int
The fact that GDB defaults to assuming that functions return int, when
it has no debug info for the function has been a recurring source of
user confusion. Recently this came up on the errno pretty printer
discussions. Shortly after, it came up again on IRC, with someone
wondering why does getenv() in GDB return a negative int:
(gdb) p getenv("PATH")
$1 = -6185
This question (with s/getenv/random-other-C-runtime-function) is a FAQ
on IRC.
The reason for the above is:
(gdb) p getenv
$2 = {<text variable, no debug info>} 0x7ffff7751d80 <getenv>
(gdb) ptype getenv
type = int ()
... which means that GDB truncated the 64-bit pointer that is actually
returned from getent to 32-bit, and then sign-extended it:
(gdb) p /x -6185
$6 = 0xffffe7d7
The workaround is to cast the function to the right type, like:
(gdb) p ((char *(*) (const char *)) getenv) ("PATH")
$3 = 0x7fffffffe7d7 "/usr/local/bin:/"...
IMO, we should do better than this.
I see the "assume-int" issue the same way I see printing bogus values
for optimized-out variables instead of "<optimized out>" -- I'd much
rather that the debugger tells me "I don't know" and tells me how to
fix it than showing me bogus misleading results, making me go around
tilting at windmills.
If GDB prints a signed integer when you're expecting a pointer or
aggregate, you at least have some sense that something is off, but
consider the case of the function actually returning a 64-bit integer.
For example, compile this without debug info:
unsigned long long
function ()
{
return 0x7fffffffffffffff;
}
Currently, with pristine GDB, you get:
(gdb) p function ()
$1 = -1 # incorrect
(gdb) p /x function ()
$2 = 0xffffffff # incorrect
maybe after spending a few hours debugging you suspect something is
wrong with that -1, and do:
(gdb) ptype function
type = int ()
and maybe, just maybe, you realize that the function actually returns
unsigned long long. And you try to fix it with:
(gdb) p /x (unsigned long long) function ()
$3 = 0xffffffffffffffff # incorrect
... which still produces the wrong result, because GDB simply applied
int to unsigned long long conversion. Meaning, it sign-extended the
integer that it extracted from the return of the function, to 64-bits.
and then maybe, after asking around on IRC, you realize you have to
cast the function to a pointer of the right type, and call that. It
won't be easy, but after a few missteps, you'll get to it:
..... (gdb) p /x ((unsigned long long(*) ()) function) ()
$666 = 0x7fffffffffffffff # finally! :-)
So to improve on the user experience, this patch does the following
(interrelated) things:
- makes no-debug-info functions no longer default to "int" as return
type. Instead, they're left with NULL/"<unknown return type>"
return type.
(gdb) ptype getenv
type = <unknown return type> ()
- makes calling a function with unknown return type an error.
(gdb) p getenv ("PATH")
'getenv' has unknown return type; cast the call to its declared return type
- and then to make it easier to call the function, makes it possible
to _only_ cast the return of the function to the right type,
instead of having to cast the function to a function pointer:
(gdb) p (char *) getenv ("PATH") # now Just Works
$3 = 0x7fffffffe7d7 "/usr/local/bin:/"...
(gdb) p ((char *(*) (const char *)) getenv) ("PATH") # continues working
$4 = 0x7fffffffe7d7 "/usr/local/bin:/"...
I.e., it makes GDB default the function's return type to the type
of the cast, and the function's parameters to the type of the
arguments passed down.
After this patch, here's what you'll get for the "unsigned long long"
example above:
(gdb) p function ()
'function' has unknown return type; cast the call to its declared return type
(gdb) p /x (unsigned long long) function ()
$4 = 0x7fffffffffffffff # correct!
Note that while with "print" GDB shows the name of the function that
has the problem:
(gdb) p getenv ("PATH")
'getenv' has unknown return type; cast the call to its declared return type
which can by handy in more complicated expressions, "ptype" does not:
(gdb) ptype getenv ("PATH")
function has unknown return type; cast the call to its declared return type
This will be fixed in the next patch.
gdb/ChangeLog:
2017-09-04 Pedro Alves <palves@redhat.com>
* ada-lang.c (ada_evaluate_subexp) <TYPE_CODE_FUNC>: Don't handle
TYPE_GNU_IFUNC specially here. Throw error if return type is
unknown.
* ada-typeprint.c (print_func_type): Handle functions with unknown
return type.
* c-typeprint.c (c_type_print_base): Handle functions and methods
with unknown return type.
* compile/compile-c-symbols.c (convert_symbol_bmsym)
<mst_text_gnu_ifunc>: Use nodebug_text_gnu_ifunc_symbol.
* compile/compile-c-types.c: Include "objfiles.h".
(convert_func): For functions with unknown return type, warn and
default to int.
* compile/compile-object-run.c (compile_object_run): Adjust call
to call_function_by_hand_dummy.
* elfread.c (elf_gnu_ifunc_resolve_addr): Adjust call to
call_function_by_hand.
* eval.c (evaluate_subexp_standard): Adjust calls to
call_function_by_hand. Handle functions and methods with unknown
return type. Pass expect_type to call_function_by_hand.
* f-typeprint.c (f_type_print_base): Handle functions with unknown
return type.
* gcore.c (call_target_sbrk): Adjust call to
call_function_by_hand.
* gdbtypes.c (objfile_type): Leave nodebug text symbol with NULL
return type instead of int. Make nodebug_text_gnu_ifunc_symbol be
an integer address type instead of nodebug.
* guile/scm-value.c (gdbscm_value_call): Adjust call to
call_function_by_hand.
* infcall.c (error_call_unknown_return_type): New function.
(call_function_by_hand): New "default_return_type" parameter.
Pass it down.
(call_function_by_hand_dummy): New "default_return_type"
parameter. Use it instead of defaulting to int. If there's no
default and the return type is unknown, throw an error. If
there's a default return type, and the called function has no
debug info, then assume the function is prototyped.
* infcall.h (call_function_by_hand, call_function_by_hand_dummy):
New "default_return_type" parameter.
(error_call_unknown_return_type): New declaration.
* linux-fork.c (call_lseek): Cast return type of lseek.
(inferior_call_waitpid, checkpoint_command): Adjust calls to
call_function_by_hand.
* linux-tdep.c (linux_infcall_mmap, linux_infcall_munmap): Adjust
calls to call_function_by_hand.
* m2-typeprint.c (m2_procedure): Handle functions with unknown
return type.
* objc-lang.c (lookup_objc_class, lookup_child_selector)
(value_nsstring, print_object_command): Adjust calls to
call_function_by_hand.
* p-typeprint.c (pascal_type_print_varspec_prefix): Handle
functions with unknown return type.
(pascal_type_print_func_varspec_suffix): New function.
(pascal_type_print_varspec_suffix) <TYPE_CODE_FUNC,
TYPE_CODE_METHOD>: Use it.
* python/py-value.c (valpy_call): Adjust call to
call_function_by_hand.
* rust-lang.c (rust_evaluate_funcall): Adjust call to
call_function_by_hand.
* valarith.c (value_x_binop, value_x_unop): Adjust calls to
call_function_by_hand.
* valops.c (value_allocate_space_in_inferior): Adjust call to
call_function_by_hand.
* typeprint.c (type_print_unknown_return_type): New function.
* typeprint.h (type_print_unknown_return_type): New declaration.
gdb/testsuite/ChangeLog:
2017-09-04 Pedro Alves <palves@redhat.com>
* gdb.base/break-main-file-remove-fail.exp (test_remove_bp): Cast
return type of munmap in infcall.
* gdb.base/break-probes.exp: Cast return type of foo in infcall.
* gdb.base/checkpoint.exp: Simplify using for loop. Cast return
type of ftell in infcall.
* gdb.base/dprintf-detach.exp (dprintf_detach_test): Cast return
type of getpid in infcall.
* gdb.base/infcall-exec.exp: Cast return type of execlp in
infcall.
* gdb.base/info-os.exp: Cast return type of getpid in infcall.
Bail on failure to extract the pid.
* gdb.base/nodebug.c: #include <stdint.h>.
(multf, multf_noproto, mult, mult_noproto, add8, add8_noproto):
New functions.
* gdb.base/nodebug.exp (test_call_promotion): New procedure.
Change expected output of print/whatis/ptype with functions with
no debug info. Test all supported languages. Call
test_call_promotion.
* gdb.compile/compile.exp: Adjust expected output to expect
warning.
* gdb.threads/siginfo-threads.exp: Likewise.
2017-09-05 03:21:13 +08:00
|
|
|
|
result = call_function_by_hand (function, NULL, num_args + 1, args.data ());
|
2016-04-27 09:38:08 +08:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-28 00:28:56 +08:00
|
|
|
|
/* A helper for rust_evaluate_subexp that handles OP_RANGE. */
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
static struct value *
|
|
|
|
|
rust_range (struct expression *exp, int *pos, enum noside noside)
|
|
|
|
|
{
|
2016-04-28 00:28:56 +08:00
|
|
|
|
enum range_type kind;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
struct value *low = NULL, *high = NULL;
|
|
|
|
|
struct value *addrval, *result;
|
|
|
|
|
CORE_ADDR addr;
|
|
|
|
|
struct type *range_type;
|
|
|
|
|
struct type *index_type;
|
|
|
|
|
struct type *temp_type;
|
|
|
|
|
const char *name;
|
|
|
|
|
|
2016-04-28 00:28:56 +08:00
|
|
|
|
kind = (enum range_type) longest_to_int (exp->elts[*pos + 1].longconst);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
*pos += 3;
|
|
|
|
|
|
|
|
|
|
if (kind == HIGH_BOUND_DEFAULT || kind == NONE_BOUND_DEFAULT)
|
|
|
|
|
low = evaluate_subexp (NULL_TYPE, exp, pos, noside);
|
|
|
|
|
if (kind == LOW_BOUND_DEFAULT || kind == NONE_BOUND_DEFAULT)
|
|
|
|
|
high = evaluate_subexp (NULL_TYPE, exp, pos, noside);
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_SKIP)
|
|
|
|
|
return value_from_longest (builtin_type (exp->gdbarch)->builtin_int, 1);
|
|
|
|
|
|
|
|
|
|
if (low == NULL)
|
|
|
|
|
{
|
|
|
|
|
if (high == NULL)
|
|
|
|
|
{
|
|
|
|
|
index_type = NULL;
|
|
|
|
|
name = "std::ops::RangeFull";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
index_type = value_type (high);
|
|
|
|
|
name = "std::ops::RangeTo";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (high == NULL)
|
|
|
|
|
{
|
|
|
|
|
index_type = value_type (low);
|
|
|
|
|
name = "std::ops::RangeFrom";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!types_equal (value_type (low), value_type (high)))
|
|
|
|
|
error (_("Range expression with different types"));
|
|
|
|
|
index_type = value_type (low);
|
|
|
|
|
name = "std::ops::Range";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we don't have an index type, just allocate this on the
|
|
|
|
|
arch. Here any type will do. */
|
|
|
|
|
temp_type = (index_type == NULL
|
|
|
|
|
? language_bool_type (exp->language_defn, exp->gdbarch)
|
|
|
|
|
: index_type);
|
|
|
|
|
/* It would be nicer to cache the range type. */
|
|
|
|
|
range_type = rust_composite_type (temp_type, name,
|
|
|
|
|
low == NULL ? NULL : "start", index_type,
|
|
|
|
|
high == NULL ? NULL : "end", index_type);
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
return value_zero (range_type, lval_memory);
|
|
|
|
|
|
|
|
|
|
addrval = value_allocate_space_in_inferior (TYPE_LENGTH (range_type));
|
|
|
|
|
addr = value_as_long (addrval);
|
|
|
|
|
result = value_at_lazy (range_type, addr);
|
|
|
|
|
|
|
|
|
|
if (low != NULL)
|
|
|
|
|
{
|
|
|
|
|
struct value *start = value_struct_elt (&result, NULL, "start", NULL,
|
|
|
|
|
"range");
|
|
|
|
|
|
|
|
|
|
value_assign (start, low);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (high != NULL)
|
|
|
|
|
{
|
|
|
|
|
struct value *end = value_struct_elt (&result, NULL, "end", NULL,
|
|
|
|
|
"range");
|
|
|
|
|
|
|
|
|
|
value_assign (end, high);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = value_at_lazy (range_type, addr);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* A helper function to compute the range and kind given a range
|
|
|
|
|
value. TYPE is the type of the range value. RANGE is the range
|
|
|
|
|
value. LOW, HIGH, and KIND are out parameters. The LOW and HIGH
|
|
|
|
|
parameters might be filled in, or might not be, depending on the
|
|
|
|
|
kind of range this is. KIND will always be set to the appropriate
|
|
|
|
|
value describing the kind of range, and this can be used to
|
|
|
|
|
determine whether LOW or HIGH are valid. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rust_compute_range (struct type *type, struct value *range,
|
|
|
|
|
LONGEST *low, LONGEST *high,
|
2016-04-28 00:28:56 +08:00
|
|
|
|
enum range_type *kind)
|
2016-04-27 09:38:08 +08:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
*low = 0;
|
|
|
|
|
*high = 0;
|
|
|
|
|
*kind = BOTH_BOUND_DEFAULT;
|
|
|
|
|
|
|
|
|
|
if (TYPE_NFIELDS (type) == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
if (strcmp (TYPE_FIELD_NAME (type, 0), "start") == 0)
|
|
|
|
|
{
|
|
|
|
|
*kind = HIGH_BOUND_DEFAULT;
|
|
|
|
|
*low = value_as_long (value_field (range, 0));
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
if (TYPE_NFIELDS (type) > i
|
|
|
|
|
&& strcmp (TYPE_FIELD_NAME (type, i), "end") == 0)
|
|
|
|
|
{
|
|
|
|
|
*kind = (*kind == BOTH_BOUND_DEFAULT
|
|
|
|
|
? LOW_BOUND_DEFAULT : NONE_BOUND_DEFAULT);
|
|
|
|
|
*high = value_as_long (value_field (range, i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* A helper for rust_evaluate_subexp that handles BINOP_SUBSCRIPT. */
|
|
|
|
|
|
|
|
|
|
static struct value *
|
|
|
|
|
rust_subscript (struct expression *exp, int *pos, enum noside noside,
|
|
|
|
|
int for_addr)
|
|
|
|
|
{
|
|
|
|
|
struct value *lhs, *rhs, *result;
|
|
|
|
|
struct type *rhstype;
|
2016-05-19 00:48:41 +08:00
|
|
|
|
LONGEST low, high_bound;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
/* Initialized to appease the compiler. */
|
2016-04-28 00:28:56 +08:00
|
|
|
|
enum range_type kind = BOTH_BOUND_DEFAULT;
|
2016-05-19 00:48:41 +08:00
|
|
|
|
LONGEST high = 0;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
int want_slice = 0;
|
|
|
|
|
|
|
|
|
|
++*pos;
|
|
|
|
|
lhs = evaluate_subexp (NULL_TYPE, exp, pos, noside);
|
|
|
|
|
rhs = evaluate_subexp (NULL_TYPE, exp, pos, noside);
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_SKIP)
|
|
|
|
|
return lhs;
|
|
|
|
|
|
|
|
|
|
rhstype = check_typedef (value_type (rhs));
|
|
|
|
|
if (rust_range_type_p (rhstype))
|
|
|
|
|
{
|
|
|
|
|
if (!for_addr)
|
|
|
|
|
error (_("Can't take slice of array without '&'"));
|
|
|
|
|
rust_compute_range (rhstype, rhs, &low, &high, &kind);
|
|
|
|
|
want_slice = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
low = value_as_long (rhs);
|
|
|
|
|
|
2017-10-03 03:47:15 +08:00
|
|
|
|
struct type *type = check_typedef (value_type (lhs));
|
2016-04-27 09:38:08 +08:00
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
{
|
2017-10-03 03:47:15 +08:00
|
|
|
|
struct type *base_type = nullptr;
|
|
|
|
|
if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
|
|
|
|
|
base_type = TYPE_TARGET_TYPE (type);
|
|
|
|
|
else if (rust_slice_type_p (type))
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < TYPE_NFIELDS (type); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp (TYPE_FIELD_NAME (type, i), "data_ptr") == 0)
|
|
|
|
|
{
|
|
|
|
|
base_type = TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, i));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (base_type == nullptr)
|
|
|
|
|
error (_("Could not find 'data_ptr' in slice type"));
|
|
|
|
|
}
|
|
|
|
|
else if (TYPE_CODE (type) == TYPE_CODE_PTR)
|
|
|
|
|
base_type = TYPE_TARGET_TYPE (type);
|
|
|
|
|
else
|
|
|
|
|
error (_("Cannot subscript non-array type"));
|
|
|
|
|
|
|
|
|
|
struct type *new_type;
|
|
|
|
|
if (want_slice)
|
|
|
|
|
{
|
|
|
|
|
if (rust_slice_type_p (type))
|
|
|
|
|
new_type = type;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct type *usize
|
|
|
|
|
= language_lookup_primitive_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch,
|
|
|
|
|
"usize");
|
|
|
|
|
new_type = rust_slice_type ("&[*gdb*]", base_type, usize);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
new_type = base_type;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
2017-10-03 03:47:15 +08:00
|
|
|
|
return value_zero (new_type, VALUE_LVAL (lhs));
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LONGEST low_bound;
|
|
|
|
|
struct value *base;
|
|
|
|
|
|
|
|
|
|
if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
|
|
|
|
|
{
|
|
|
|
|
base = lhs;
|
|
|
|
|
if (!get_array_bounds (type, &low_bound, &high_bound))
|
|
|
|
|
error (_("Can't compute array bounds"));
|
|
|
|
|
if (low_bound != 0)
|
|
|
|
|
error (_("Found array with non-zero lower bound"));
|
|
|
|
|
++high_bound;
|
|
|
|
|
}
|
|
|
|
|
else if (rust_slice_type_p (type))
|
|
|
|
|
{
|
|
|
|
|
struct value *len;
|
|
|
|
|
|
|
|
|
|
base = value_struct_elt (&lhs, NULL, "data_ptr", NULL, "slice");
|
|
|
|
|
len = value_struct_elt (&lhs, NULL, "length", NULL, "slice");
|
|
|
|
|
low_bound = 0;
|
|
|
|
|
high_bound = value_as_long (len);
|
|
|
|
|
}
|
2016-07-06 13:25:10 +08:00
|
|
|
|
else if (TYPE_CODE (type) == TYPE_CODE_PTR)
|
|
|
|
|
{
|
|
|
|
|
base = lhs;
|
|
|
|
|
low_bound = 0;
|
|
|
|
|
high_bound = LONGEST_MAX;
|
|
|
|
|
}
|
2016-04-27 09:38:08 +08:00
|
|
|
|
else
|
|
|
|
|
error (_("Cannot subscript non-array type"));
|
|
|
|
|
|
|
|
|
|
if (want_slice
|
|
|
|
|
&& (kind == BOTH_BOUND_DEFAULT || kind == LOW_BOUND_DEFAULT))
|
|
|
|
|
low = low_bound;
|
|
|
|
|
if (low < 0)
|
|
|
|
|
error (_("Index less than zero"));
|
|
|
|
|
if (low > high_bound)
|
|
|
|
|
error (_("Index greater than length"));
|
|
|
|
|
|
|
|
|
|
result = value_subscript (base, low);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (for_addr)
|
|
|
|
|
{
|
|
|
|
|
if (want_slice)
|
|
|
|
|
{
|
|
|
|
|
struct type *usize, *slice;
|
|
|
|
|
CORE_ADDR addr;
|
|
|
|
|
struct value *addrval, *tem;
|
|
|
|
|
|
|
|
|
|
if (kind == BOTH_BOUND_DEFAULT || kind == HIGH_BOUND_DEFAULT)
|
|
|
|
|
high = high_bound;
|
|
|
|
|
if (high < 0)
|
|
|
|
|
error (_("High index less than zero"));
|
|
|
|
|
if (low > high)
|
|
|
|
|
error (_("Low index greater than high index"));
|
|
|
|
|
if (high > high_bound)
|
|
|
|
|
error (_("High index greater than length"));
|
|
|
|
|
|
|
|
|
|
usize = language_lookup_primitive_type (exp->language_defn,
|
|
|
|
|
exp->gdbarch,
|
|
|
|
|
"usize");
|
2017-10-03 03:55:42 +08:00
|
|
|
|
const char *new_name = ((type != nullptr
|
|
|
|
|
&& rust_slice_type_p (type))
|
|
|
|
|
? TYPE_NAME (type) : "&[*gdb*]");
|
|
|
|
|
|
|
|
|
|
slice = rust_slice_type (new_name, value_type (result), usize);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
addrval = value_allocate_space_in_inferior (TYPE_LENGTH (slice));
|
|
|
|
|
addr = value_as_long (addrval);
|
|
|
|
|
tem = value_at_lazy (slice, addr);
|
|
|
|
|
|
|
|
|
|
value_assign (value_field (tem, 0), value_addr (result));
|
|
|
|
|
value_assign (value_field (tem, 1),
|
|
|
|
|
value_from_longest (usize, high - low));
|
|
|
|
|
|
|
|
|
|
result = value_at_lazy (slice, addr);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
result = value_addr (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* evaluate_exp implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static struct value *
|
|
|
|
|
rust_evaluate_subexp (struct type *expect_type, struct expression *exp,
|
|
|
|
|
int *pos, enum noside noside)
|
|
|
|
|
{
|
|
|
|
|
struct value *result;
|
|
|
|
|
|
|
|
|
|
switch (exp->elts[*pos].opcode)
|
|
|
|
|
{
|
Handle dereferencing Rust trait objects
In Rust, virtual tables work a bit differently than they do in C++. In
C++, as you know, they are connected to a particular class hierarchy.
Rust, instead, can generate a virtual table for potentially any type --
in fact, one such virtual table for each trait (a trait is similar to an
abstract class or to a Java interface) that a type implements.
Objects that are referenced via a trait can't currently be inspected by
gdb. This patch implements the Rust equivalent of "set print object".
gdb relies heavily on the C++ ABI to decode virtual tables; primarily to
make "set print object" work; but also "info vtbl". However, Rust does
not currently have a specified ABI, so this approach seems unwise to
emulate.
Instead, I've changed the Rust compiler to emit some DWARF that
describes trait objects (previously their internal structure was
opaque), vtables (currently just a size -- but I hope to expand this in
the future), and the concrete type for which a vtable was emitted.
The concrete type is expressed as a DW_AT_containing_type on the
vtable's type. This is a small extension to DWARF.
This patch adds a new entry to quick_symbol_functions to return the
symtab that holds a data address. Previously there was no way in gdb to
look up a full (only minimal) non-text symbol by address. The psymbol
implementation of this method works by lazily filling in a map that is
added to the objfile. This avoids slowing down psymbol reading for a
feature that is likely to not be used too frequently.
I did not update .gdb_index. My thinking here is that the DWARF 5
indices will obsolete .gdb_index soon-ish, meaning that adding a new
feature to them is probably wasted work. If necessary I can update the
DWARF 5 index code when it lands in gdb.
Regression tested on x86-64 Fedora 25.
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 Tom Tromey <tom@tromey.com>
* gdb.rust/traits.rs: New file.
* gdb.rust/traits.exp: New file.
2017-07-06 20:44:38 +08:00
|
|
|
|
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;
|
|
|
|
|
|
2016-04-27 09:38:08 +08:00
|
|
|
|
case UNOP_COMPLEMENT:
|
|
|
|
|
{
|
|
|
|
|
struct value *value;
|
|
|
|
|
|
|
|
|
|
++*pos;
|
|
|
|
|
value = evaluate_subexp (NULL_TYPE, exp, pos, noside);
|
|
|
|
|
if (noside == EVAL_SKIP)
|
|
|
|
|
{
|
|
|
|
|
/* Preserving the type is enough. */
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
if (TYPE_CODE (value_type (value)) == TYPE_CODE_BOOL)
|
|
|
|
|
result = value_from_longest (value_type (value),
|
|
|
|
|
value_logical_not (value));
|
|
|
|
|
else
|
|
|
|
|
result = value_complement (value);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BINOP_SUBSCRIPT:
|
|
|
|
|
result = rust_subscript (exp, pos, noside, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OP_FUNCALL:
|
|
|
|
|
result = rust_evaluate_funcall (exp, pos, noside);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OP_AGGREGATE:
|
|
|
|
|
{
|
|
|
|
|
int pc = (*pos)++;
|
|
|
|
|
struct type *type = exp->elts[pc + 1].type;
|
|
|
|
|
int arglen = longest_to_int (exp->elts[pc + 2].longconst);
|
|
|
|
|
int i;
|
|
|
|
|
CORE_ADDR addr = 0;
|
|
|
|
|
struct value *addrval = NULL;
|
|
|
|
|
|
|
|
|
|
*pos += 3;
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_NORMAL)
|
|
|
|
|
{
|
|
|
|
|
addrval = value_allocate_space_in_inferior (TYPE_LENGTH (type));
|
|
|
|
|
addr = value_as_long (addrval);
|
|
|
|
|
result = value_at_lazy (type, addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arglen > 0 && exp->elts[*pos].opcode == OP_OTHERS)
|
|
|
|
|
{
|
|
|
|
|
struct value *init;
|
|
|
|
|
|
|
|
|
|
++*pos;
|
|
|
|
|
init = rust_evaluate_subexp (NULL, exp, pos, noside);
|
|
|
|
|
if (noside == EVAL_NORMAL)
|
|
|
|
|
{
|
|
|
|
|
/* This isn't quite right but will do for the time
|
|
|
|
|
being, seeing that we can't implement the Copy
|
|
|
|
|
trait anyway. */
|
|
|
|
|
value_assign (result, init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
--arglen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gdb_assert (arglen % 2 == 0);
|
|
|
|
|
for (i = 0; i < arglen; i += 2)
|
|
|
|
|
{
|
|
|
|
|
int len;
|
|
|
|
|
const char *fieldname;
|
|
|
|
|
struct value *value, *field;
|
|
|
|
|
|
|
|
|
|
gdb_assert (exp->elts[*pos].opcode == OP_NAME);
|
|
|
|
|
++*pos;
|
|
|
|
|
len = longest_to_int (exp->elts[*pos].longconst);
|
|
|
|
|
++*pos;
|
|
|
|
|
fieldname = &exp->elts[*pos].string;
|
|
|
|
|
*pos += 2 + BYTES_TO_EXP_ELEM (len + 1);
|
|
|
|
|
|
|
|
|
|
value = rust_evaluate_subexp (NULL, exp, pos, noside);
|
|
|
|
|
if (noside == EVAL_NORMAL)
|
|
|
|
|
{
|
|
|
|
|
field = value_struct_elt (&result, NULL, fieldname, NULL,
|
|
|
|
|
"structure");
|
|
|
|
|
value_assign (field, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_SKIP)
|
|
|
|
|
return value_from_longest (builtin_type (exp->gdbarch)->builtin_int,
|
|
|
|
|
1);
|
|
|
|
|
else if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
result = allocate_value (type);
|
|
|
|
|
else
|
|
|
|
|
result = value_at_lazy (type, addr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OP_RUST_ARRAY:
|
|
|
|
|
{
|
|
|
|
|
int pc = (*pos)++;
|
|
|
|
|
int copies;
|
|
|
|
|
struct value *elt;
|
|
|
|
|
struct value *ncopies;
|
|
|
|
|
|
|
|
|
|
elt = rust_evaluate_subexp (NULL, exp, pos, noside);
|
|
|
|
|
ncopies = rust_evaluate_subexp (NULL, exp, pos, noside);
|
|
|
|
|
copies = value_as_long (ncopies);
|
|
|
|
|
if (copies < 0)
|
|
|
|
|
error (_("Array with negative number of elements"));
|
|
|
|
|
|
|
|
|
|
if (noside == EVAL_NORMAL)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2016-09-22 23:51:20 +08:00
|
|
|
|
std::vector<struct value *> eltvec (copies);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < copies; ++i)
|
|
|
|
|
eltvec[i] = elt;
|
2016-09-22 23:51:20 +08:00
|
|
|
|
result = value_array (0, copies - 1, eltvec.data ());
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct type *arraytype
|
|
|
|
|
= lookup_array_range_type (value_type (elt), 0, copies - 1);
|
|
|
|
|
result = allocate_value (arraytype);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case STRUCTOP_ANONYMOUS:
|
|
|
|
|
{
|
|
|
|
|
/* Anonymous field access, i.e. foo.1. */
|
|
|
|
|
struct value *lhs;
|
|
|
|
|
int pc, field_number, nfields;
|
|
|
|
|
struct type *type, *variant_type;
|
|
|
|
|
|
|
|
|
|
pc = (*pos)++;
|
|
|
|
|
field_number = longest_to_int (exp->elts[pc + 1].longconst);
|
|
|
|
|
(*pos) += 2;
|
|
|
|
|
lhs = evaluate_subexp (NULL_TYPE, exp, pos, noside);
|
|
|
|
|
|
|
|
|
|
type = value_type (lhs);
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
|
|
|
|
|
/* Treat a univariant union as if it were an enum. */
|
|
|
|
|
if (TYPE_CODE (type) == TYPE_CODE_UNION && TYPE_NFIELDS (type) == 1)
|
2016-04-27 09:38:08 +08:00
|
|
|
|
{
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
lhs = value_primitive_field (lhs, 0, 0, type);
|
|
|
|
|
type = value_type (lhs);
|
|
|
|
|
}
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
|
|
|
|
|
{
|
|
|
|
|
struct type *outer_type = NULL;
|
|
|
|
|
|
|
|
|
|
if (rust_enum_p (type))
|
2016-04-27 09:38:08 +08:00
|
|
|
|
{
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
const gdb_byte *valaddr = value_contents (lhs);
|
|
|
|
|
struct field *variant_field = rust_enum_variant (type, valaddr);
|
|
|
|
|
|
|
|
|
|
struct value *union_value = value_primitive_field (lhs, 0, 0,
|
|
|
|
|
type);
|
|
|
|
|
|
|
|
|
|
int fieldno = (variant_field
|
|
|
|
|
- &TYPE_FIELD (value_type (union_value), 0));
|
|
|
|
|
lhs = value_primitive_field (union_value, 0, fieldno,
|
|
|
|
|
value_type (union_value));
|
|
|
|
|
outer_type = type;
|
|
|
|
|
type = value_type (lhs);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Tuples and tuple structs */
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
nfields = TYPE_NFIELDS (type);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
if (field_number >= nfields || field_number < 0)
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
{
|
|
|
|
|
if (outer_type != NULL)
|
|
|
|
|
error(_("Cannot access field %d of variant %s::%s, "
|
|
|
|
|
"there are only %d fields"),
|
|
|
|
|
field_number, TYPE_TAG_NAME (outer_type),
|
|
|
|
|
rust_last_path_segment (TYPE_TAG_NAME (type)),
|
|
|
|
|
nfields);
|
|
|
|
|
else
|
|
|
|
|
error(_("Cannot access field %d of %s, "
|
|
|
|
|
"there are only %d fields"),
|
|
|
|
|
field_number, TYPE_TAG_NAME (type), nfields);
|
|
|
|
|
}
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
/* Tuples are tuple structs too. */
|
|
|
|
|
if (!rust_tuple_struct_type_p (type))
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
{
|
|
|
|
|
if (outer_type != NULL)
|
|
|
|
|
error(_("Variant %s::%s is not a tuple variant"),
|
|
|
|
|
TYPE_TAG_NAME (outer_type),
|
|
|
|
|
rust_last_path_segment (TYPE_TAG_NAME (type)));
|
|
|
|
|
else
|
|
|
|
|
error(_("Attempting to access anonymous field %d "
|
|
|
|
|
"of %s, which is not a tuple, tuple struct, or "
|
|
|
|
|
"tuple-like variant"),
|
|
|
|
|
field_number, TYPE_TAG_NAME (type));
|
|
|
|
|
}
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
result = value_primitive_field (lhs, 0, field_number, type);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
error(_("Anonymous field access is only allowed on tuples, \
|
|
|
|
|
tuple structs, and tuple-like enum variants"));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case STRUCTOP_STRUCT:
|
|
|
|
|
{
|
2017-05-12 12:22:36 +08:00
|
|
|
|
struct value *lhs;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
struct type *type;
|
|
|
|
|
int tem, pc;
|
|
|
|
|
|
|
|
|
|
pc = (*pos)++;
|
|
|
|
|
tem = longest_to_int (exp->elts[pc + 1].longconst);
|
|
|
|
|
(*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
|
|
|
|
|
lhs = evaluate_subexp (NULL_TYPE, exp, pos, noside);
|
|
|
|
|
|
2017-05-12 12:22:36 +08:00
|
|
|
|
const char *field_name = &exp->elts[pc + 2].string;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
type = value_type (lhs);
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
if (TYPE_CODE (type) == TYPE_CODE_STRUCT && rust_enum_p (type))
|
2016-04-27 09:38:08 +08:00
|
|
|
|
{
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
const gdb_byte *valaddr = value_contents (lhs);
|
|
|
|
|
struct field *variant_field = rust_enum_variant (type, valaddr);
|
|
|
|
|
|
|
|
|
|
struct value *union_value = value_primitive_field (lhs, 0, 0,
|
|
|
|
|
type);
|
|
|
|
|
|
|
|
|
|
int fieldno = (variant_field
|
|
|
|
|
- &TYPE_FIELD (value_type (union_value), 0));
|
|
|
|
|
lhs = value_primitive_field (union_value, 0, fieldno,
|
|
|
|
|
value_type (union_value));
|
|
|
|
|
|
|
|
|
|
struct type *outer_type = type;
|
|
|
|
|
type = value_type (lhs);
|
|
|
|
|
if (rust_tuple_type_p (type) || rust_tuple_struct_type_p (type))
|
|
|
|
|
error (_("Attempting to access named field foo of tuple "
|
|
|
|
|
"variant %s::%s, which has only anonymous fields"),
|
|
|
|
|
TYPE_TAG_NAME (outer_type),
|
|
|
|
|
rust_last_path_segment (TYPE_NAME (type)));
|
|
|
|
|
|
|
|
|
|
TRY
|
2016-04-27 09:38:08 +08:00
|
|
|
|
{
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
result = value_struct_elt (&lhs, NULL, field_name,
|
|
|
|
|
NULL, "structure");
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
CATCH (except, RETURN_MASK_ERROR)
|
|
|
|
|
{
|
|
|
|
|
error (_("Could not find field %s of struct variant %s::%s"),
|
|
|
|
|
field_name, TYPE_TAG_NAME (outer_type),
|
|
|
|
|
rust_last_path_segment (TYPE_NAME (type)));
|
|
|
|
|
}
|
|
|
|
|
END_CATCH
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
Convert Rust to use discriminated unions
A Rust enum is, essentially, a discriminated union. Currently the
Rust language support handles Rust enums locally, in rust-lang.c.
However, because I am changing the Rust compiler to use
DW_TAG_variant* to represent enums, it seemed better to have a single
internal representation for Rust enums in gdb.
This patch implements this idea by moving the current Rust enum
handling code to dwarf2read. This allows the simplification of some
parts of rust-lang.c as well.
2018-02-26 Tom Tromey <tom@tromey.com>
* rust-lang.h (rust_last_path_segment): Declare.
* rust-lang.c (rust_last_path_segment): Now public. Change
contract.
(struct disr_info): Remove.
(RUST_ENUM_PREFIX, RUST_ENCODED_ENUM_REAL)
(RUST_ENCODED_ENUM_HIDDEN, rust_union_is_untagged)
(rust_get_disr_info, rust_tuple_variant_type_p): Remove.
(rust_enum_p, rust_enum_variant): New function.
(rust_underscore_fields): Remove "offset" parameter.
(rust_print_enum): New function.
(rust_val_print) <TYPE_CODE_UNION>: Remove enum code.
<TYPE_CODE_STRUCT>: Call rust_print_enum when appropriate.
(rust_print_struct_def): Add "for_rust_enum" parameter. Handle
enums.
(rust_internal_print_type): New function, from rust_print_type.
Remove enum code.
(rust_print_type): Call rust_internal_print_type.
(rust_evaluate_subexp) <STRUCTOP_ANONYMOUS, STRUCTOP_STRUCT>:
Update enum handling.
* dwarf2read.c (struct dwarf2_cu) <rust_unions>: New field.
(rust_fully_qualify, alloc_discriminant_info, quirk_rust_enum)
(rust_union_quirks): New functions.
(process_full_comp_unit, process_full_type_unit): Call
rust_union_quirks.
(process_structure_scope): Update rust_unions if necessary.
2018-02-26 Tom Tromey <tom@tromey.com>
* gdb.rust/simple.exp: Accept more possible results in enum test.
2018-02-10 04:31:51 +08:00
|
|
|
|
result = value_struct_elt (&lhs, NULL, field_name, NULL, "structure");
|
|
|
|
|
if (noside == EVAL_AVOID_SIDE_EFFECTS)
|
|
|
|
|
result = value_zero (value_type (result), VALUE_LVAL (result));
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2016-04-28 00:28:56 +08:00
|
|
|
|
case OP_RANGE:
|
2016-04-27 09:38:08 +08:00
|
|
|
|
result = rust_range (exp, pos, noside);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case UNOP_ADDR:
|
|
|
|
|
/* We might have &array[range], in which case we need to make a
|
|
|
|
|
slice. */
|
|
|
|
|
if (exp->elts[*pos + 1].opcode == BINOP_SUBSCRIPT)
|
|
|
|
|
{
|
|
|
|
|
++*pos;
|
|
|
|
|
result = rust_subscript (exp, pos, noside, 1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
/* Fall through. */
|
|
|
|
|
default:
|
|
|
|
|
result = evaluate_subexp_standard (expect_type, exp, pos, noside);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* operator_length implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rust_operator_length (const struct expression *exp, int pc, int *oplenp,
|
|
|
|
|
int *argsp)
|
|
|
|
|
{
|
|
|
|
|
int oplen = 1;
|
|
|
|
|
int args = 0;
|
|
|
|
|
|
|
|
|
|
switch (exp->elts[pc - 1].opcode)
|
|
|
|
|
{
|
|
|
|
|
case OP_AGGREGATE:
|
|
|
|
|
/* We handle aggregate as a type and argument count. The first
|
|
|
|
|
argument might be OP_OTHERS. After that the arguments
|
|
|
|
|
alternate: first an OP_NAME, then an expression. */
|
|
|
|
|
oplen = 4;
|
|
|
|
|
args = longest_to_int (exp->elts[pc - 2].longconst);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OP_OTHERS:
|
|
|
|
|
oplen = 1;
|
|
|
|
|
args = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case STRUCTOP_ANONYMOUS:
|
|
|
|
|
oplen = 3;
|
|
|
|
|
args = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OP_RUST_ARRAY:
|
|
|
|
|
oplen = 1;
|
|
|
|
|
args = 2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
operator_length_standard (exp, pc, oplenp, argsp);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*oplenp = oplen;
|
|
|
|
|
*argsp = args;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* op_name implementation for Rust. */
|
|
|
|
|
|
-Wwrite-strings: The Rest
This is the remainder boring constification that all looks more of less
borderline obvious IMO.
gdb/ChangeLog:
2017-04-05 Pedro Alves <palves@redhat.com>
* ada-exp.y (yyerror): Constify.
* ada-lang.c (bound_name, get_selections)
(ada_variant_discrim_type)
(ada_variant_discrim_name, ada_value_struct_elt)
(ada_lookup_struct_elt_type, is_unchecked_variant)
(ada_which_variant_applies, standard_exc, ada_get_next_arg)
(catch_ada_exception_command_split)
(catch_ada_assert_command_split, catch_assert_command)
(ada_op_name): Constify.
* ada-lang.h (ada_yyerror, get_selections)
(ada_variant_discrim_name, ada_value_struct_elt): Constify.
* arc-tdep.c (arc_print_frame_cache): Constify.
* arm-tdep.c (arm_skip_stub): Constify.
* ax-gdb.c (gen_binop, gen_struct_ref_recursive, gen_struct_ref)
(gen_aggregate_elt_ref): Constify.
* bcache.c (print_bcache_statistics): Constify.
* bcache.h (print_bcache_statistics): Constify.
* break-catch-throw.c (catch_exception_command_1):
* breakpoint.c (struct ep_type_description::description):
Constify.
(add_solib_catchpoint): Constify.
(catch_fork_command_1): Add cast.
(add_catch_command): Constify.
* breakpoint.h (add_catch_command, add_solib_catchpoint):
Constify.
* bsd-uthread.c (bsd_uthread_state): Constify.
* buildsym.c (patch_subfile_names): Constify.
* buildsym.h (next_symbol_text_func, patch_subfile_names):
Constify.
* c-exp.y (yyerror): Constify.
(token::oper): Constify.
* c-lang.h (c_yyerror, cp_print_class_member): Constify.
* c-varobj.c (cplus_describe_child): Constify.
* charset.c (find_charset_names): Add cast.
(find_charset_names): Constify array and add const_cast.
* cli/cli-cmds.c (complete_command, cd_command): Constify.
(edit_command): Constify.
* cli/cli-decode.c (lookup_cmd): Constify.
* cli/cli-dump.c (dump_memory_command, dump_value_command):
Constify.
(struct dump_context): Constify.
(add_dump_command, restore_command): Constify.
* cli/cli-script.c (get_command_line): Constify.
* cli/cli-script.h (get_command_line): Constify.
* cli/cli-utils.c (check_for_argument): Constify.
* cli/cli-utils.h (check_for_argument): Constify.
* coff-pe-read.c (struct read_pe_section_data): Constify.
* command.h (lookup_cmd): Constify.
* common/print-utils.c (decimal2str): Constify.
* completer.c (gdb_print_filename): Constify.
* corefile.c (set_gnutarget): Constify.
* cp-name-parser.y (yyerror): Constify.
* cp-valprint.c (cp_print_class_member): Constify.
* cris-tdep.c (cris_register_name, crisv32_register_name):
Constify.
* d-exp.y (yyerror): Constify.
(struct token::oper): Constify.
* d-lang.h (d_yyerror): Constify.
* dbxread.c (struct header_file_location::name): Constify.
(add_old_header_file, add_new_header_file, last_function_name)
(dbx_next_symbol_text, add_bincl_to_list)
(find_corresponding_bincl_psymtab, set_namestring)
(find_stab_function_addr, read_dbx_symtab, start_psymtab)
(dbx_end_psymtab, read_ofile_symtab, process_one_symbol):
* defs.h (command_line_input, print_address_symbolic)
(deprecated_readline_begin_hook): Constify.
* dwarf2read.c (anonymous_struct_prefix, dwarf_bool_name):
Constify.
* event-top.c (handle_line_of_input): Constify and add cast.
* exceptions.c (catch_errors): Constify.
* exceptions.h (catch_errors): Constify.
* expprint.c (print_subexp_standard, op_string, op_name)
(op_name_standard, dump_raw_expression, dump_raw_expression):
* expression.h (op_name, op_string, dump_raw_expression):
Constify.
* f-exp.y (yyerror): Constify.
(struct token::oper): Constify.
(struct f77_boolean_val::name): Constify.
* f-lang.c (f_word_break_characters): Constify.
* f-lang.h (f_yyerror): Constify.
* fork-child.c (fork_inferior): Add cast.
* frv-tdep.c (struct gdbarch_tdep::register_names): Constify.
(new_variant): Constify.
* gdbarch.sh (pstring_ptr, pstring_list): Constify.
* gdbarch.c: Regenerate.
* gdbcore.h (set_gnutarget): Constify.
* go-exp.y (yyerror): Constify.
(token::oper): Constify.
* go-lang.h (go_yyerror): Constify.
* go32-nat.c (go32_sysinfo): Constify.
* guile/scm-breakpoint.c (gdbscm_breakpoint_expression): Constify.
* guile/scm-cmd.c (cmdscm_function): Constify.
* guile/scm-param.c (pascm_param_value): Constify.
* h8300-tdep.c (h8300_register_name, h8300s_register_name)
(h8300sx_register_name): Constify.
* hppa-tdep.c (hppa32_register_name, hppa64_register_name):
Constify.
* ia64-tdep.c (ia64_register_names): Constify.
* infcmd.c (construct_inferior_arguments): Constify.
(path_command, attach_post_wait): Constify.
* language.c (show_range_command, show_case_command)
(unk_lang_error): Constify.
* language.h (language_defn::la_error)
(language_defn::la_name_of_this): Constify.
* linespec.c (decode_line_2): Constify.
* linux-thread-db.c (thread_db_err_str): Constify.
* lm32-tdep.c (lm32_register_name): Constify.
* m2-exp.y (yyerror): Constify.
* m2-lang.h (m2_yyerror): Constify.
* m32r-tdep.c (m32r_register_names): Constify and make static.
* m68hc11-tdep.c (m68hc11_register_names): Constify.
* m88k-tdep.c (m88k_register_name): Constify.
* macroexp.c (appendmem): Constify.
* mdebugread.c (fdr_name, add_data_symbol, parse_type)
(upgrade_type, parse_external, parse_partial_symbols)
(mdebug_next_symbol_text, cross_ref, mylookup_symbol, new_psymtab)
(new_symbol): Constify.
* memattr.c (mem_info_command): Constify.
* mep-tdep.c (register_name_from_keyword): Constify.
* mi/mi-cmd-env.c (mi_cmd_env_path, _initialize_mi_cmd_env):
Constify.
* mi/mi-cmd-stack.c (list_args_or_locals): Constify.
* mi/mi-cmd-var.c (mi_cmd_var_show_attributes): Constify.
* mi/mi-main.c (captured_mi_execute_command): Constify and add
cast.
(mi_execute_async_cli_command): Constify.
* mips-tdep.c (mips_register_name): Constify.
* mn10300-tdep.c (register_name, mn10300_generic_register_name)
(am33_register_name, am33_2_register_name)
* moxie-tdep.c (moxie_register_names): Constify.
* nat/linux-osdata.c (osdata_type): Constify fields.
* nto-tdep.c (nto_parse_redirection): Constify.
* objc-lang.c (lookup_struct_typedef, lookup_objc_class)
(lookup_child_selector): Constify.
(objc_methcall::name): Constify.
* objc-lang.h (lookup_objc_class, lookup_child_selector)
(lookup_struct_typedef): Constify.
* objfiles.c (pc_in_section): Constify.
* objfiles.h (pc_in_section): Constify.
* p-exp.y (struct token::oper): Constify.
(yyerror): Constify.
* p-lang.h (pascal_yyerror): Constify.
* parser-defs.h (op_name_standard): Constify.
(op_print::string): Constify.
(exp_descriptor::op_name): Constify.
* printcmd.c (print_address_symbolic): Constify.
* psymtab.c (print_partial_symbols): Constify.
* python/py-breakpoint.c (stop_func): Constify.
(bppy_get_expression): Constify.
* python/py-cmd.c (cmdpy_completer::name): Constify.
(cmdpy_function): Constify.
* python/py-event.c (evpy_add_attribute)
(gdbpy_initialize_event_generic): Constify.
* python/py-event.h (evpy_add_attribute)
(gdbpy_initialize_event_generic): Constify.
* python/py-evts.c (add_new_registry): Constify.
* python/py-finishbreakpoint.c (outofscope_func): Constify.
* python/py-framefilter.c (get_py_iter_from_func): Constify.
* python/py-inferior.c (get_buffer): Add cast.
* python/py-param.c (parm_constant::name): Constify.
* python/py-unwind.c (fprint_frame_id): Constify.
* python/python.c (gdbpy_parameter_value): Constify.
* remote-fileio.c (remote_fio_func_map): Make 'name' const.
* remote.c (memory_packet_config::name): Constify.
(show_packet_config_cmd, remote_write_bytes)
(remote_buffer_add_string):
* reverse.c (exec_reverse_once): Constify.
* rs6000-tdep.c (variant::name, variant::description): Constify.
* rust-exp.y (rustyyerror): Constify.
* rust-lang.c (rust_op_name): Constify.
* rust-lang.h (rustyyerror): Constify.
* serial.h (serial_ops::name): Constify.
* sh-tdep.c (sh_sh_register_name, sh_sh3_register_name)
(sh_sh3e_register_name, sh_sh2e_register_name)
(sh_sh2a_register_name, sh_sh2a_nofpu_register_name)
(sh_sh_dsp_register_name, sh_sh3_dsp_register_name)
(sh_sh4_register_name, sh_sh4_nofpu_register_name)
(sh_sh4al_dsp_register_name): Constify.
* sh64-tdep.c (sh64_register_name): Constify.
* solib-darwin.c (lookup_symbol_from_bfd): Constify.
* spu-tdep.c (spu_register_name, info_spu_dma_cmdlist): Constify.
* stabsread.c (patch_block_stabs, read_type_number)
(ref_map::stabs, ref_add, process_reference)
(symbol_reference_defined, define_symbol, define_symbol)
(error_type, read_type, read_member_functions, read_cpp_abbrev)
(read_one_struct_field, read_struct_fields, read_baseclasses)
(read_tilde_fields, read_struct_type, read_array_type)
(read_enum_type, read_sun_builtin_type, read_sun_floating_type)
(read_huge_number, read_range_type, read_args, common_block_start)
(find_name_end): Constify.
* stabsread.h (common_block_start, define_symbol)
(process_one_symbol, symbol_reference_defined, ref_add):
* symfile.c (get_section_index, add_symbol_file_command):
* symfile.h (get_section_index): Constify.
* target-descriptions.c (tdesc_type::name): Constify.
(tdesc_free_type): Add cast.
* target.c (find_default_run_target):
(add_deprecated_target_alias, find_default_run_target)
(target_announce_detach): Constify.
(do_option): Constify.
* target.h (add_deprecated_target_alias): Constify.
* thread.c (print_thread_info_1): Constify.
* top.c (deprecated_readline_begin_hook, command_line_input):
Constify.
(init_main): Add casts.
* top.h (handle_line_of_input): Constify.
* tracefile-tfile.c (tfile_write_uploaded_tsv): Constify.
* tracepoint.c (tvariables_info_1, trace_status_mi): Constify.
(tfind_command): Rename to ...
(tfind_command_1): ... this and constify.
(tfind_command): New function.
(tfind_end_command, tfind_start_command): Adjust.
(encode_source_string): Constify.
* tracepoint.h (encode_source_string): Constify.
* tui/tui-data.c (tui_partial_win_by_name): Constify.
* tui/tui-data.h (tui_partial_win_by_name): Constify.
* tui/tui-source.c (tui_set_source_content_nil): Constify.
* tui/tui-source.h (tui_set_source_content_nil): Constify.
* tui/tui-win.c (parse_scrolling_args): Constify.
* tui/tui-windata.c (tui_erase_data_content): Constify.
* tui/tui-windata.h (tui_erase_data_content): Constify.
* tui/tui-winsource.c (tui_erase_source_content): Constify.
* tui/tui.c (tui_enable): Add cast.
* utils.c (defaulted_query): Constify.
(init_page_info): Add cast.
(puts_debug, subset_compare): Constify.
* utils.h (subset_compare): Constify.
* varobj.c (varobj_format_string): Constify.
* varobj.h (varobj_format_string): Constify.
* vax-tdep.c (vax_register_name): Constify.
* windows-nat.c (windows_detach): Constify.
* xcoffread.c (process_linenos, xcoff_next_symbol_text): Constify.
* xml-support.c (gdb_xml_end_element): Constify.
* xml-tdesc.c (tdesc_start_reg): Constify.
* xstormy16-tdep.c (xstormy16_register_name): Constify.
* xtensa-tdep.c (xtensa_find_register_by_name): Constify.
* xtensa-tdep.h (xtensa_register_t::name): Constify.
gdb/gdbserver/ChangeLog:
2017-04-05 Pedro Alves <palves@redhat.com>
* gdbreplay.c (sync_error): Constify.
* linux-x86-low.c (push_opcode): Constify.
2017-04-06 02:21:37 +08:00
|
|
|
|
static const char *
|
2016-04-27 09:38:08 +08:00
|
|
|
|
rust_op_name (enum exp_opcode opcode)
|
|
|
|
|
{
|
|
|
|
|
switch (opcode)
|
|
|
|
|
{
|
|
|
|
|
case OP_AGGREGATE:
|
|
|
|
|
return "OP_AGGREGATE";
|
|
|
|
|
case OP_OTHERS:
|
|
|
|
|
return "OP_OTHERS";
|
|
|
|
|
default:
|
|
|
|
|
return op_name_standard (opcode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* dump_subexp_body implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
rust_dump_subexp_body (struct expression *exp, struct ui_file *stream,
|
|
|
|
|
int elt)
|
|
|
|
|
{
|
|
|
|
|
switch (exp->elts[elt].opcode)
|
|
|
|
|
{
|
|
|
|
|
case OP_AGGREGATE:
|
|
|
|
|
{
|
|
|
|
|
int length = longest_to_int (exp->elts[elt + 2].longconst);
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
fprintf_filtered (stream, "Type @");
|
|
|
|
|
gdb_print_host_address (exp->elts[elt + 1].type, stream);
|
|
|
|
|
fprintf_filtered (stream, " (");
|
|
|
|
|
type_print (exp->elts[elt + 1].type, NULL, stream, 0);
|
|
|
|
|
fprintf_filtered (stream, "), length %d", length);
|
|
|
|
|
|
|
|
|
|
elt += 4;
|
|
|
|
|
for (i = 0; i < length; ++i)
|
|
|
|
|
elt = dump_subexp (exp, stream, elt);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OP_STRING:
|
|
|
|
|
case OP_NAME:
|
|
|
|
|
{
|
|
|
|
|
LONGEST len = exp->elts[elt + 1].longconst;
|
|
|
|
|
|
|
|
|
|
fprintf_filtered (stream, "%s: %s",
|
|
|
|
|
(exp->elts[elt].opcode == OP_STRING
|
|
|
|
|
? "string" : "name"),
|
|
|
|
|
&exp->elts[elt + 2].string);
|
|
|
|
|
elt += 4 + BYTES_TO_EXP_ELEM (len + 1);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OP_OTHERS:
|
|
|
|
|
elt = dump_subexp (exp, stream, elt + 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case STRUCTOP_ANONYMOUS:
|
|
|
|
|
{
|
|
|
|
|
int field_number;
|
|
|
|
|
|
2017-05-12 09:50:47 +08:00
|
|
|
|
field_number = longest_to_int (exp->elts[elt + 1].longconst);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
fprintf_filtered (stream, "Field number: %d", field_number);
|
2017-05-12 09:50:47 +08:00
|
|
|
|
elt = dump_subexp (exp, stream, elt + 3);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OP_RUST_ARRAY:
|
2017-05-12 09:50:47 +08:00
|
|
|
|
++elt;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
elt = dump_subexp_body_standard (exp, stream, elt);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return elt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* print_subexp implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rust_print_subexp (struct expression *exp, int *pos, struct ui_file *stream,
|
|
|
|
|
enum precedence prec)
|
|
|
|
|
{
|
|
|
|
|
switch (exp->elts[*pos].opcode)
|
|
|
|
|
{
|
|
|
|
|
case OP_AGGREGATE:
|
|
|
|
|
{
|
|
|
|
|
int length = longest_to_int (exp->elts[*pos + 2].longconst);
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
type_print (exp->elts[*pos + 1].type, "", stream, 0);
|
|
|
|
|
fputs_filtered (" { ", stream);
|
|
|
|
|
|
|
|
|
|
*pos += 4;
|
|
|
|
|
for (i = 0; i < length; ++i)
|
|
|
|
|
{
|
|
|
|
|
rust_print_subexp (exp, pos, stream, prec);
|
|
|
|
|
fputs_filtered (", ", stream);
|
|
|
|
|
}
|
|
|
|
|
fputs_filtered (" }", stream);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OP_NAME:
|
|
|
|
|
{
|
|
|
|
|
LONGEST len = exp->elts[*pos + 1].longconst;
|
|
|
|
|
|
|
|
|
|
fputs_filtered (&exp->elts[*pos + 2].string, stream);
|
|
|
|
|
*pos += 4 + BYTES_TO_EXP_ELEM (len + 1);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OP_OTHERS:
|
|
|
|
|
{
|
|
|
|
|
fputs_filtered ("<<others>> (", stream);
|
|
|
|
|
++*pos;
|
|
|
|
|
rust_print_subexp (exp, pos, stream, prec);
|
|
|
|
|
fputs_filtered (")", stream);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case STRUCTOP_ANONYMOUS:
|
|
|
|
|
{
|
|
|
|
|
int tem = longest_to_int (exp->elts[*pos + 1].longconst);
|
|
|
|
|
|
|
|
|
|
(*pos) += 3;
|
|
|
|
|
print_subexp (exp, pos, stream, PREC_SUFFIX);
|
|
|
|
|
fprintf_filtered (stream, ".%d", tem);
|
|
|
|
|
}
|
2017-05-12 09:44:43 +08:00
|
|
|
|
break;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
|
|
|
|
|
case OP_RUST_ARRAY:
|
|
|
|
|
++*pos;
|
|
|
|
|
fprintf_filtered (stream, "[");
|
|
|
|
|
rust_print_subexp (exp, pos, stream, prec);
|
|
|
|
|
fprintf_filtered (stream, "; ");
|
|
|
|
|
rust_print_subexp (exp, pos, stream, prec);
|
|
|
|
|
fprintf_filtered (stream, "]");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
print_subexp_standard (exp, pos, stream, prec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* operator_check implementation for Rust. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
rust_operator_check (struct expression *exp, int pos,
|
|
|
|
|
int (*objfile_func) (struct objfile *objfile,
|
|
|
|
|
void *data),
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
switch (exp->elts[pos].opcode)
|
|
|
|
|
{
|
|
|
|
|
case OP_AGGREGATE:
|
|
|
|
|
{
|
|
|
|
|
struct type *type = exp->elts[pos + 1].type;
|
|
|
|
|
struct objfile *objfile = TYPE_OBJFILE (type);
|
|
|
|
|
|
|
|
|
|
if (objfile != NULL && (*objfile_func) (objfile, data))
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OP_OTHERS:
|
|
|
|
|
case OP_NAME:
|
|
|
|
|
case OP_RUST_ARRAY:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return operator_check_standard (exp, pos, objfile_func, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Implementation of la_lookup_symbol_nonlocal for Rust. */
|
|
|
|
|
|
|
|
|
|
static struct block_symbol
|
|
|
|
|
rust_lookup_symbol_nonlocal (const struct language_defn *langdef,
|
|
|
|
|
const char *name,
|
|
|
|
|
const struct block *block,
|
|
|
|
|
const domain_enum domain)
|
|
|
|
|
{
|
|
|
|
|
struct block_symbol result = {NULL, NULL};
|
|
|
|
|
|
|
|
|
|
if (symbol_lookup_debug)
|
|
|
|
|
{
|
|
|
|
|
fprintf_unfiltered (gdb_stdlog,
|
|
|
|
|
"rust_lookup_symbol_non_local"
|
|
|
|
|
" (%s, %s (scope %s), %s)\n",
|
|
|
|
|
name, host_address_to_string (block),
|
|
|
|
|
block_scope (block), domain_name (domain));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Look up bare names in the block's scope. */
|
2018-01-20 06:25:19 +08:00
|
|
|
|
std::string scopedname;
|
2016-04-27 09:38:08 +08:00
|
|
|
|
if (name[cp_find_first_component (name)] == '\0')
|
|
|
|
|
{
|
|
|
|
|
const char *scope = block_scope (block);
|
|
|
|
|
|
|
|
|
|
if (scope[0] != '\0')
|
|
|
|
|
{
|
2018-01-20 06:25:19 +08:00
|
|
|
|
scopedname = std::string (scope) + "::" + name;
|
|
|
|
|
name = scopedname.c_str ();
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
2018-01-20 06:25:19 +08:00
|
|
|
|
else
|
|
|
|
|
name = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (name != NULL)
|
|
|
|
|
{
|
|
|
|
|
result = lookup_symbol_in_static_block (name, block, domain);
|
|
|
|
|
if (result.symbol == NULL)
|
|
|
|
|
result = lookup_global_symbol (name, block, domain);
|
2016-04-27 09:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-05-27 05:04:07 +08:00
|
|
|
|
/* la_sniff_from_mangled_name for Rust. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
rust_sniff_from_mangled_name (const char *mangled, char **demangled)
|
|
|
|
|
{
|
|
|
|
|
*demangled = gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
|
|
|
|
|
return *demangled != NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Use watchpoint's language when re-parsing expression
PR rust/21484 notes that watch -location does not work with Rust:
(gdb) watch -location a
syntax error in expression, near `) 0x00007fffffffe0f4'.
update_watchpoint tries to tell gdb that the new expression it creates
has C syntax:
/* The above expression is in C. */
b->language = language_c;
However, update_watchpoint doesn't actually use this language when
re-parsing the expression.
Originally I was going to fix this by saving and restoring the
language in update_watchpoint, but this regressed
gdb.dlang/watch-loc.exp, because the constructed expression actually
has D syntax (specifically the name is not parseable by C).
Next I looked at directly constructing an expression, and not relying
on the parser at all; but it seemed to me that upon a re-set, we'd
want to reparse the type, and there is no existing API to do this
correctly.
So, in the end I made a hook to let each language choose what
expression to use. I made all the languages other than Rust use the C
expression, because that is the status quo ante. However, this is
probably not truly correct. After this patch, at least, it is easy to
correct by someone who knows the language(s) in question.
Regtested by the buildbot.
ChangeLog
2017-05-19 Tom Tromey <tom@tromey.com>
PR rust/21484:
* rust-lang.c (exp_descriptor_rust): New function.
(rust_language_defn): Use it.
* p-lang.c (pascal_language_defn): Update.
* opencl-lang.c (opencl_language_defn): Update.
* objc-lang.c (objc_language_defn): Update.
* m2-lang.c (m2_language_defn): Update.
* language.h (struct language_defn)
<la_watch_location_expression>: New member.
* language.c (unknown_language_defn, auto_language_defn)
(local_language_defn): Update.
* go-lang.c (go_language_defn): Update.
* f-lang.c (f_language_defn): Update.
* d-lang.c (d_language_defn): Update.
* c-lang.h (c_watch_location_expression): Declare.
* c-lang.c (c_watch_location_expression): New function.
(c_language_defn, cplus_language_defn, asm_language_defn)
(minimal_language_defn): Use it.
* breakpoint.c (watch_command_1): Call
la_watch_location_expression.
* ada-lang.c (ada_language_defn): Update.
testsuite/ChangeLog
2017-05-19 Tom Tromey <tom@tromey.com>
PR rust/21484:
* gdb.rust/watch.exp: New file.
* gdb.rust/watch.rs: New file.
2017-05-15 01:12:14 +08:00
|
|
|
|
/* la_watch_location_expression for Rust. */
|
|
|
|
|
|
|
|
|
|
static gdb::unique_xmalloc_ptr<char>
|
|
|
|
|
rust_watch_location_expression (struct type *type, CORE_ADDR addr)
|
|
|
|
|
{
|
|
|
|
|
type = check_typedef (TYPE_TARGET_TYPE (check_typedef (type)));
|
|
|
|
|
std::string name = type_to_string (type);
|
|
|
|
|
return gdb::unique_xmalloc_ptr<char>
|
|
|
|
|
(xstrprintf ("*(%s as *mut %s)", core_addr_to_string (addr),
|
|
|
|
|
name.c_str ()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-27 09:38:08 +08:00
|
|
|
|
static const struct exp_descriptor exp_descriptor_rust =
|
|
|
|
|
{
|
|
|
|
|
rust_print_subexp,
|
|
|
|
|
rust_operator_length,
|
|
|
|
|
rust_operator_check,
|
|
|
|
|
rust_op_name,
|
|
|
|
|
rust_dump_subexp_body,
|
|
|
|
|
rust_evaluate_subexp
|
|
|
|
|
};
|
|
|
|
|
|
2016-05-27 00:33:28 +08:00
|
|
|
|
static const char *rust_extensions[] =
|
|
|
|
|
{
|
|
|
|
|
".rs", NULL
|
|
|
|
|
};
|
|
|
|
|
|
Make language_def O(1)
Profiling GDB with the rest of series applied, I saw calls to
language_def showing up high in some runs. The problem is that
language_def is O(N) currently, since walk the languages vector each
time to find the matching language_defn.
IMO, the add_language mechanism is pointless, because "enum language"
implies the core of GDB needs to know about all languages anyway. So
simply make the languages vector array be an array where each
element's index is the corresponding enum language enumerator. Note
that "local_language_defn" is gone along the way. It's just a copy of
"auto", so the new code simply maps one to the other. One fewer place
to update when we need to change the language vector...
Also, a while ago the output of "set language" was made out of order
as side effect of some other change. While I was at it, I made them
sorted again.
gdb/ChangeLog:
2017-07-20 Pedro Alves <palves@redhat.com>
* ada-lang.c (ada_language_defn): Make extern.
(_initialize_ada_language): Remove add_language call.
* c-lang.c (c_language_defn, cplus_language_defn)
(asm_language_defn, minimal_language_defn): Make extern.
(_initialize_c_language): Delete.
* completer.c (compare_cstrings): Delete, moved to utils.h.
* d-lang.c (d_language_defn): Make extern.
(_initialize_d_language): Remove add_language calls.
* defs.h (enum language): Add comment.
* f-lang.c (f_language_defn): Make extern.
(_initialize_f_language): Remove add_language call.
* go-lang.c (go_language_defn): Make extern.
(_initialize_go_language): Remove add_language call.
* language.c: Include <algorithm>.
(languages): Redefine as const array.
(languages_size, languages_allocsize, DEFAULT_ALLOCSIZE): Delete.
(set_language_command): Handle "local". Use for-range loop.
(set_language): Remove loop.
(language_enum): Rewrite.
(language_def, language_str): Remove loops.
(add_language): Delete.
(add_set_language_command): New, based on add_languages.
(skip_language_trampoline): Adjust.
(local_language_defn): Delete.
(language_gdbarch_post_init): Adjust.
(_initialize_language): Remove add_language calls. Call
add_set_language_command.
* language.h (add_language): Delete.
(auto_language_defn)
(unknown_language_defn, minimal_language_defn, ada_language_defn)
(asm_language_defn, c_language_defn, cplus_language_defn)
(d_language_defn, f_language_defn, go_language_defn)
(m2_language_defn, objc_language_defn, opencl_language_defn)
(pascal_language_defn, rust_language_defn): Declare.
* m2-lang.c (m2_language_defn): Make extern.
(_initialize_m2_language): Remove add_language call.
* objc-lang.c (objc_language_defn): Make extern.
(_initialize_objc_language): Remove add_language call.
* opencl-lang.c (opencl_language_defn): Make extern.
(_initialize_opencl_language): Remove add_language call.
* p-lang.c (pascal_language_defn): Make extern.
(_initialize_pascal_language): Delete.
* rust-lang.c (rust_language_defn): Make extern.
(_initialize_rust_language): Delete.
* utils.h (compare_cstrings): New static inline function.
gdb/testsuite/ChangeLog:
2017-07-20 Pedro Alves <palves@redhat.com>
* gdb.base/default.exp (set language): Adjust expected output.
2017-07-21 01:28:01 +08:00
|
|
|
|
extern const struct language_defn rust_language_defn =
|
2016-04-27 09:38:08 +08:00
|
|
|
|
{
|
|
|
|
|
"rust",
|
|
|
|
|
"Rust",
|
|
|
|
|
language_rust,
|
|
|
|
|
range_check_on,
|
|
|
|
|
case_sensitive_on,
|
|
|
|
|
array_row_major,
|
|
|
|
|
macro_expansion_no,
|
2016-05-27 00:33:28 +08:00
|
|
|
|
rust_extensions,
|
2016-04-27 09:38:08 +08:00
|
|
|
|
&exp_descriptor_rust,
|
|
|
|
|
rust_parse,
|
|
|
|
|
rustyyerror,
|
|
|
|
|
null_post_parser,
|
|
|
|
|
rust_printchar, /* Print a character constant */
|
|
|
|
|
rust_printstr, /* Function to print string constant */
|
|
|
|
|
rust_emitchar, /* Print a single char */
|
|
|
|
|
rust_print_type, /* Print a type using appropriate syntax */
|
|
|
|
|
rust_print_typedef, /* Print a typedef using appropriate syntax */
|
|
|
|
|
rust_val_print, /* Print a value using appropriate syntax */
|
|
|
|
|
c_value_print, /* Print a top-level value */
|
|
|
|
|
default_read_var_value, /* la_read_var_value */
|
|
|
|
|
NULL, /* Language specific skip_trampoline */
|
|
|
|
|
NULL, /* name_of_this */
|
problem looking up some symbols when they have a linkage name
This patch fixes a known failure in gdb.ada/maint_with_ada.exp
(maintenance check-psymtabs). Another way to witness the same
issue is by considering the following Ada declarations...
type Wrapper is record
A : Integer;
end record;
u00045 : constant Wrapper := (A => 16#060287af#);
pragma Export (C, u00045, "symada__cS");
... which declares a variable name "u00045" but with a linkage
name which is "symada__cS". This variable is a record with one
component, the Ada equivalent of a struct with one field in C.
Trying to print that variable's value currently yields:
(gdb) p /x <symada__cS>
'symada(char, signed)' has unknown type; cast it to its declared type
This indicates that GDB was only able to find the minimal symbol,
but not the full symbol. The expected output is:
(gdb) print /x <symada__cS>
$1 = (a => 0x60287af)
The error message gives a hint about what's happening: We processed
the symbol through gdb_demangle, which in the case of this particular
symbol name, ends up matching the C++ naming scheme. As a result,
the demangler transforms our symbol name into 'symada(char, signed)',
thus breaking Ada lookups.
This patch fixes the issue by first introducing a new language_defn
attribute called la_store_sym_names_in_linkage_form_p, which is a boolean
to be set to true for the few languages that do not want their symbols
to have their names stored in demangled form, and false otherwise.
We then use this language attribute to skip the call to gdb_demangle
for all languages whose la_store_sym_names_in_linkage_form_p is true.
In terms of the selection of languages for which the new attribute
is set to true, the selection errs on the side of preserving the
existing behavior, and only changes the behavior for the languages
where we are certain storing symbol names in demangling form is not
needed. It is conceivable that other languages might be in the same
situation, but I not knowing in detail the symbol name enconding
strategy, I decided to play it safe and let other language maintainers
potentially adjust their language if it makes sense to do so.
gdb/ChangeLog:
PR gdb/22670
* dwarf2read.c (dwarf2_physname): Do not return the demangled
symbol name if the CU's language stores symbol names in linkage
format.
* language.h (struct language_defn)
<la_store_sym_names_in_linkage_form_p>: New field. Adjust
all instances of this struct.
gdb/testsuite/ChangeLog:
* gdb.ada/maint_with_ada.exp: Remove PR gdb/22670 setup_kfail.
* gdb.ada/notcplusplus: New testcase.
* gdb.base/c-linkage-name.c: New file.
* gdb.base/c-linkage-name.exp: New testcase.
Tested on x86_64-linux.
This also passes AdaCore's internal GDB testsuite.
2018-03-27 21:57:16 +08:00
|
|
|
|
false, /* la_store_sym_names_in_linkage_form_p */
|
2016-04-27 09:38:08 +08:00
|
|
|
|
rust_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
|
|
|
|
|
basic_lookup_transparent_type,/* lookup_transparent_type */
|
|
|
|
|
gdb_demangle, /* Language specific symbol demangler */
|
2016-05-27 05:04:07 +08:00
|
|
|
|
rust_sniff_from_mangled_name,
|
2016-04-27 09:38:08 +08:00
|
|
|
|
NULL, /* Language specific
|
|
|
|
|
class_name_from_physname */
|
|
|
|
|
c_op_print_tab, /* expression operators for printing */
|
|
|
|
|
1, /* c-style arrays */
|
|
|
|
|
0, /* String lower bound */
|
|
|
|
|
default_word_break_characters,
|
Introduce class completion_tracker & rewrite completion<->readline interaction
This patch reworks the whole completion machinery, and prepares it
for later enhancements.
Adds a new "completion_tracker" class that is meant to hold everything
about the state of the current completion operation.
This class now has the responsibility of tracking the list of
completion matches, and checking whether the max completions limit has
been reached. You can look at this as this patch starting out by
C++fying the existing "completion_tracker" in symtab.c (it's just an
htab_t typedef currently), moving it to completer.h/c, and then making
it a class/generalizing/enhancing it.
Unlike with the current tracking, completion_tracker now checks
whether the limit has been reached on each completion match list
insertion. This both simplifies the max-completions handling code
(maybe_add_completion_enum is gone, for example), and is a
prerequisite for follow up patches.
The current completion_tracker is only used for symbol completions,
and the symbol code gets at the current instance via globals. This
patch cleans that up by adding a completion_tracker reference to the
signature of the completion functions, and passing the tracker around
everywhere necessary.
Then, the patch changes how the completion match list is handed over
to readline. Currently, we're using the rl_completion_entry_function
readline entry point, and the patch switches to
rl_attempted_completion_function. A following patch will want to let
GDB itself decide the common completion prefix between all matches
(what readline calls the "lowest common denominator"), instead of
having readline compute it, and that's not possible with the
rl_completion_entry_function entry point. Also,
rl_attempted_completion_function lets GDB hand over the match list to
readline as an array in one go instead of passing down matches one by
one, so from that angle it's a nicer entry point anyway.
Lastly, the patch catches exceptions around the readline entry points,
because we can't let C++ exceptions cross readline. We handle that in
the readline input entry point, but the completion entry point isn't
guarded, so GDB can abort if completion throws. E.g., in current
master:
(gdb) b -function "fun<tab>
terminate called after throwing an instance of 'gdb_exception_RETURN_MASK_ERROR'
Aborted (core dumped)
This patch fixes that. This will be exercised in the new tests added
later on in the series.
gdb/ChangeLog:
2017-07-17 Pedro Alves <palves@redhat.com>
* ada-lang.c (symbol_completion_match): Adjust comments.
(symbol_completion_add): Replace vector parameter with
completion_tracker parameter. Use it.
(ada_make_symbol_completion_list): Rename to...
(ada_collect_symbol_completion_matches): ... this. Add
completion_tracker parameter and use it.
(ada_language_defn): Adjust.
* break-catch-syscall.c (catch_syscall_completer): Adjust
prototype and work with completion_tracker instead of VEC.
* breakpoint.c (condition_completer): Adjust prototype and work
with completion_tracker instead of VEC.
* c-lang.c (c_language_defn, cplus_language_defn)
(asm_language_defn, minimal_language_defn): Adjust to renames.
* cli/cli-cmds.c (complete_command): Rework using
completion_tracker. Catch exceptions when completing.
* cli/cli-decode.c (integer_unlimited_completer)
(complete_on_cmdlist, complete_on_enum): Adjust prototype and work
with completion_tracker instead of VEC.
* command.h (struct completion_tracker): Forward declare.
(completer_ftype, completer_handle_brkchars_ftype): Change
types.
(complete_on_cmdlist, complete_on_enum): Adjust.
* completer.c: Include <algorithm>.
(struct gdb_completer_state): New.
(current_completion): New global.
(readline_line_completion_function): Delete.
(noop_completer, filename_completer)
(filename_completer_handle_brkchars, complete_files_symbols)
(linespec_location_completer): Adjust to work with a
completion_tracker instead of a VEC.
(string_or_empty): New.
(collect_explicit_location_matches): Adjust to work with a
completion_tracker instead of a VEC.
(explicit_location_completer): Rename to ...
(complete_explicit_location): ... this and adjust to work with a
completion_tracker instead of a VEC.
(location_completer): Adjust to work with a completion_tracker
instead of a VEC.
(add_struct_fields): Adjust to work with a completion_list instead
of VEC.
(expression_completer): Rename to ...
(complete_expression): ... this and adjust to work with a
completion_tracker instead of a VEC. Use complete_files_symbols.
(expression_completer): Reimplement on top of complete_expression.
(symbol_completer): Adjust to work with a completion_tracker
instead of a VEC.
(enum complete_line_internal_reason): Add describing comments.
(complete_line_internal_normal_command): Adjust to work with a
completion_tracker instead of a VEC.
(complete_line_internal): Rename to ...
(complete_line_internal_1): ... this and adjust to work with a
completion_tracker instead of a VEC. Assert TEXT is NULL in the
handle_brkchars phase.
(new_completion_tracker): Delete.
(complete_line_internal): Reimplement as TRY/CATCH wrapper around
complete_line_internal_1.
(free_completion_tracker): Delete.
(INITIAL_COMPLETION_HTAB_SIZE): New.
(completion_tracker::completion_tracker)
(completion_tracker::~completion_tracker): New.
(maybe_add_completion): Delete.
(completion_tracker::maybe_add_completion)
(completion_tracker::add_completion)
(completion_tracker::add_completions): New.
(throw_max_completions_reached_error): Delete.
(complete_line): Adjust to work with a completion_tracker instead
of a VEC. Don't create a completion_tracker_t or check for max
completions here.
(command_completer, command_completer_handle_brkchars)
(signal_completer, reg_or_group_completer_1)
(reg_or_group_completer, default_completer_handle_brkchars):
Adjust to work with a completion_tracker.
(gdb_completion_word_break_characters_throw): New.
(gdb_completion_word_break_characters): Reimplement.
(line_completion_function): Delete.
(completion_tracker::recompute_lowest_common_denominator)
(expand_preserving_ws)
(completion_tracker::build_completion_result)
(completion_result::completion_result)
(completion_result::completion_result)
(completion_result::~completion_result)
(completion_result::completion_result)
(completion_result::release_match_list, compare_cstrings)
(completion_result::sort_match_list)
(completion_result::reset_match_list)
(gdb_rl_attempted_completion_function_throw)
(gdb_rl_attempted_completion_function): New.
* completer.h (completion_list, struct completion_result)
(class completion_tracker): New.
(complete_line): Add completion_tracker parameter.
(readline_line_completion_function): Delete.
(gdb_rl_attempted_completion_function): New.
(noop_completer, filename_completer, expression_completer)
(location_completer, symbol_completer, command_completer)
(signal_completer, reg_or_group_completer): Update prototypes.
(completion_tracker_t, new_completion_tracker)
(make_cleanup_free_completion_tracker): Delete.
(enum maybe_add_completion_enum): Delete.
(maybe_add_completion): Delete.
(throw_max_completions_reached_error): Delete.
* corefile.c (complete_set_gnutarget): Adjust to work with a
completion_tracker instead of a VEC.
* cp-abi.c (cp_abi_completer): Adjust to work with a
completion_tracker instead of a VEC.
* d-lang.c (d_language_defn): Adjust.
* disasm.c (disassembler_options_completer): Adjust to work with a
completion_tracker instead of a VEC.
* f-lang.c (f_make_symbol_completion_list): Rename to ...
(f_collect_symbol_completion_matches): ... this. Adjust to work
with a completion_tracker instead of a VEC.
(f_language_defn): Adjust.
* go-lang.c (go_language_defn): Adjust.
* guile/scm-cmd.c (cmdscm_add_completion, cmdscm_completer):
Adjust to work with a completion_tracker instead of a VEC.
* infrun.c (handle_completer): Likewise.
* interps.c (interpreter_completer): Likewise.
* interps.h (interpreter_completer): Likewise.
* language.c (unknown_language_defn, auto_language_defn)
(local_language_defn): Adjust.
* language.h (language_defn::la_make_symbol_completion_list):
Rename to ...
(language_defn::la_collect_symbol_completion_matches): ... this
and adjust to work with a completion_tracker instead of a VEC.
* m2-lang.c (m2_language_defn): Adjust.
* objc-lang.c (objc_language_defn): Adjust.
* opencl-lang.c (opencl_language_defn): Adjust.
* p-lang.c (pascal_language_defn): Adjust.
* python/py-cmd.c (cmdpy_completer_helper): Handle NULL word.
(cmdpy_completer_handle_brkchars, cmdpy_completer): Adjust to work
with a completion_tracker.
* rust-lang.c (rust_language_defn): Adjust.
* symtab.c (free_completion_list, do_free_completion_list)
(return_val, completion_tracker): Delete.
(completion_list_add_name, completion_list_add_symbol)
(completion_list_add_msymbol, completion_list_objc_symbol)
(completion_list_add_fields, add_symtab_completions): Add
completion_tracker parameter and use it.
(default_make_symbol_completion_list_break_on_1): Rename to...
(default_collect_symbol_completion_matches_break_on): ... this.
Add completion_tracker parameter and use it instead of allocating
a completion tracker here.
(default_make_symbol_completion_list_break_on): Delete old
implementation.
(default_make_symbol_completion_list): Delete.
(default_collect_symbol_completion_matches): New.
(make_symbol_completion_list): Delete.
(collect_symbol_completion_matches): New.
(make_symbol_completion_type): Rename to ...
(collect_symbol_completion_matches_type): ... this. Add
completion_tracker parameter and use it instead of VEC.
(make_file_symbol_completion_list_1): Rename to...
(collect_file_symbol_completion_matches): ... this. Add
completion_tracker parameter and use it instead of VEC.
(make_file_symbol_completion_list): Delete.
(add_filename_to_list): Use completion_list instead of a VEC.
(add_partial_filename_data::list): Now a completion_list.
(make_source_files_completion_list): Work with a completion_list
instead of a VEC.
* symtab.h: Include "completer.h".
(default_make_symbol_completion_list_break_on)
(default_make_symbol_completion_list, make_symbol_completion_list)
(make_symbol_completion_type, make_file_symbol_completion_list)
(make_source_files_completion_list): Delete.
(default_collect_symbol_completion_matches_break_on)
(default_collect_symbol_completion_matches)
(collect_symbol_completion_matches)
(collect_symbol_completion_matches_type)
(collect_file_symbol_completion_matches)
(make_source_files_completion_list): New.
* top.c (init_main): Don't install a rl_completion_entry_function
hook. Install a rl_attempted_completion_function hook instead.
* tui/tui-layout.c (layout_completer): Adjust to work with a
completion_tracker.
* tui/tui-regs.c (tui_reggroup_completer):
* tui/tui-win.c (window_name_completer, focus_completer)
(winheight_completer): Adjust to work with a completion_tracker.
* value.c: Include "completer.h".
(complete_internalvar): Adjust to work with a completion_tracker.
* value.h (complete_internalvar): Likewise.
2017-07-17 21:45:59 +08:00
|
|
|
|
default_collect_symbol_completion_matches,
|
2016-04-27 09:38:08 +08:00
|
|
|
|
rust_language_arch_info,
|
|
|
|
|
default_print_array_index,
|
|
|
|
|
default_pass_by_reference,
|
|
|
|
|
c_get_string,
|
Use watchpoint's language when re-parsing expression
PR rust/21484 notes that watch -location does not work with Rust:
(gdb) watch -location a
syntax error in expression, near `) 0x00007fffffffe0f4'.
update_watchpoint tries to tell gdb that the new expression it creates
has C syntax:
/* The above expression is in C. */
b->language = language_c;
However, update_watchpoint doesn't actually use this language when
re-parsing the expression.
Originally I was going to fix this by saving and restoring the
language in update_watchpoint, but this regressed
gdb.dlang/watch-loc.exp, because the constructed expression actually
has D syntax (specifically the name is not parseable by C).
Next I looked at directly constructing an expression, and not relying
on the parser at all; but it seemed to me that upon a re-set, we'd
want to reparse the type, and there is no existing API to do this
correctly.
So, in the end I made a hook to let each language choose what
expression to use. I made all the languages other than Rust use the C
expression, because that is the status quo ante. However, this is
probably not truly correct. After this patch, at least, it is easy to
correct by someone who knows the language(s) in question.
Regtested by the buildbot.
ChangeLog
2017-05-19 Tom Tromey <tom@tromey.com>
PR rust/21484:
* rust-lang.c (exp_descriptor_rust): New function.
(rust_language_defn): Use it.
* p-lang.c (pascal_language_defn): Update.
* opencl-lang.c (opencl_language_defn): Update.
* objc-lang.c (objc_language_defn): Update.
* m2-lang.c (m2_language_defn): Update.
* language.h (struct language_defn)
<la_watch_location_expression>: New member.
* language.c (unknown_language_defn, auto_language_defn)
(local_language_defn): Update.
* go-lang.c (go_language_defn): Update.
* f-lang.c (f_language_defn): Update.
* d-lang.c (d_language_defn): Update.
* c-lang.h (c_watch_location_expression): Declare.
* c-lang.c (c_watch_location_expression): New function.
(c_language_defn, cplus_language_defn, asm_language_defn)
(minimal_language_defn): Use it.
* breakpoint.c (watch_command_1): Call
la_watch_location_expression.
* ada-lang.c (ada_language_defn): Update.
testsuite/ChangeLog
2017-05-19 Tom Tromey <tom@tromey.com>
PR rust/21484:
* gdb.rust/watch.exp: New file.
* gdb.rust/watch.rs: New file.
2017-05-15 01:12:14 +08:00
|
|
|
|
rust_watch_location_expression,
|
Introduce lookup_name_info and generalize Ada's FULL/WILD name matching
Summary:
- This is preparation for supporting wild name matching on C++ too.
- This is also preparation for TAB-completion fixes.
- Makes symbol name matching (think strcmp_iw) be based on a per-language method.
- Merges completion and non-completion name comparison (think
language_ops::la_get_symbol_name_cmp generalized).
- Avoid re-hashing lookup name multiple times
- Centralizes preparing a name for lookup (Ada name encoding / C++ Demangling),
both completion and non-completion.
- Fixes Ada latent bug with verbatim name matches in expressions
- Makes ada-lang.c use common|symtab.c completion code a bit more.
Ada's wild matching basically means that
"(gdb) break foo"
will find all methods named "foo" in all packages. Translating to
C++, it's roughly the same as saying that "break klass::method" sets
breakpoints on all "klass::method" methods of all classes, no matter
the namespace. A following patch will teach GDB about fullname vs
wild matching for C++ too. This patch is preparatory work to get
there.
Another idea here is to do symbol name matching based on the symbol
language's algorithm. I.e., avoid dependency on current language set.
This allows for example doing
(gdb) b foo::bar< int > (<tab>
and having gdb name match the C++ symbols correctly even if the
current language is C or Assembly (or Rust, or Ada, or ...), which can
easily happen if you step into an Assembly/C runtime library frame.
By encapsulating all the information related to a lookup name in a
class, we can also cache hash computation for a given language in the
lookup name object, to avoid recomputing it over and over.
Similarly, because we don't really know upfront which languages the
lookup name will be matched against, for each language we store the
lookup name transformed into a search name. E.g., for C++, that means
demangling the name. But for Ada, it means encoding the name. This
actually forces us to centralize all the different lookup name
encoding in a central place, resulting in clearer code, IMO. See
e.g., the new ada_lookup_name_info class.
The lookup name -> symbol search name computation is also done only
once per language.
The old language->la_get_symbol_name_cmp / symbol_name_cmp_ftype are
generalized to work with both completion, and normal symbol look up.
At some point early on, I had separate completion vs non-completion
language vector entry points, but a single method ends up being better
IMO for simplifying things -- the more we merge the completion /
non-completion name lookup code paths, the less changes for bugs
causing completion vs normal lookup finding different symbols.
The ada-lex.l change is necessary because when doing
(gdb) p <UpperCase>
then the name that is passed to write_ write_var_or_type ->
ada_lookup_symbol_list misses the "<>", i.e., it's just "UpperCase",
and we end up doing a wild match against "UpperCase" lowercased by
ada_lookup_name_info's constructor. I.e., "uppercase" wouldn't ever
match "UpperCase", and the symbol lookup fails.
This wouldn't cause any regression in the testsuite, but I added a new
test that would pass before the patch and fail after, if it weren't
for that fix.
This is latent bug that happens to go unnoticed because that
particular path was inconsistent with the rest of Ada symbol lookup by
not lowercasing the lookup name.
Ada's symbol_completion_add is deleted, replaced by using common
code's completion_list_add_name. To make the latter work for Ada, we
needed to add a new output parameter, because Ada wants to return back
a custom completion candidates that are not the symbol name.
With this patch, minimal symbol demangled name hashing is made
consistent with regular symbol hashing. I.e., it now goes via the
language vector's search_name_hash method too, as I had suggested in a
previous patch.
dw2_expand_symtabs_matching / .gdb_index symbol names were a
challenge. The problem is that we have no way to telling what is the
language of each symbol name found in the index, until we expand the
corresponding full symbol, which is off course what we're trying to
avoid. Language information is simply not considered in the index
format... Since the symbol name hashing and comparison routines are
per-language, we now have a problem. The patch sorts this out by
matching each name against all languages. This is inneficient, and
indeed slows down completion several times. E.g., with:
$ cat script.cmd
set pagination off
set $count = 0
while $count < 400
complete b string_prin
printf "count = %d\n", $count
set $count = $count + 1
end
$ time gdb --batch -q ./gdb-with-index -ex "source script-string_printf.cmd"
I get, before patch (-O2, x86-64):
real 0m1.773s
user 0m1.737s
sys 0m0.040s
While after patch (-O2, x86-64):
real 0m9.843s
user 0m9.482s
sys 0m0.034s
However, the following patch will optimize this, and will actually
make this use case faster compared to the "before patch" above:
real 0m1.321s
user 0m1.285s
sys 0m0.039s
gdb/ChangeLog:
2017-11-08 Pedro Alves <palves@redhat.com>
* ada-lang.c (ada_encode): Rename to ..
(ada_encode_1): ... this. Add throw_errors parameter and handle
it.
(ada_encode): Reimplement.
(match_name): Delete, folded into full_name.
(resolve_subexp): No longer pass the encoded name to
ada_lookup_symbol_list.
(should_use_wild_match): Delete.
(name_match_type_from_name): New.
(ada_lookup_simple_minsym): Use lookup_name_info and the
language's symbol_name_matcher_ftype.
(add_symbols_from_enclosing_procs, ada_add_local_symbols)
(ada_add_block_renamings): Adjust to use lookup_name_info.
(ada_lookup_name): New.
(add_nonlocal_symbols, ada_add_all_symbols)
(ada_lookup_symbol_list_worker, ada_lookup_symbol_list)
(ada_iterate_over_symbols): Adjust to use lookup_name_info.
(ada_name_for_lookup): Delete.
(ada_lookup_encoded_symbol): Construct a verbatim name.
(wild_match): Reverse sense of return type. Use bool.
(full_match): Reverse sense of return type. Inline bits of old
match_name here.
(ada_add_block_symbols): Adjust to use lookup_name_info.
(symbol_completion_match): Delete, folded into...
(ada_lookup_name_info::matches): ... .this new method.
(symbol_completion_add): Delete.
(ada_collect_symbol_completion_matches): Add name_match_type
parameter. Adjust to use lookup_name_info and
completion_list_add_name.
(get_var_value, ada_add_global_exceptions): Adjust to use
lookup_name_info.
(ada_get_symbol_name_cmp): Delete.
(do_wild_match, do_full_match): New functions.
(ada_lookup_name_info::ada_lookup_name_info): New method.
(ada_symbol_name_matches, ada_get_symbol_name_matcher): New
functions.
(ada_language_defn): Install ada_get_symbol_name_matcher.
* ada-lex.l (processId): If name starts with '<', copy it
verbatim.
* block.c (block_iter_match_step, block_iter_match_first)
(block_iter_match_next, block_lookup_symbol)
(block_lookup_symbol_primary, block_find_symbol): Adjust to use
lookup_name_info.
* block.h (block_iter_match_first, block_iter_match_next)
(ALL_BLOCK_SYMBOLS_WITH_NAME): Adjust to use lookup_name_info.
* c-lang.c (c_language_defn, cplus_language_defn)
(asm_language_defn, minimal_language_defn): Adjust comments to
refer to la_get_symbol_name_matcher.
* completer.c (complete_files_symbols)
(collect_explicit_location_matches, symbol_completer): Pass a
symbol_name_match_type down.
* completer.h (class completion_match, completion_match_result):
New classes.
(completion_tracker::reset_completion_match_result): New method.
(completion_tracker::m_completion_match_result): New field.
* cp-support.c (make_symbol_overload_list_block): Adjust to use
lookup_name_info.
(cp_fq_symbol_name_matches, cp_get_symbol_name_matcher): New
functions.
* cp-support.h (cp_get_symbol_name_matcher): New declaration.
* d-lang.c: Adjust comments to refer to
la_get_symbol_name_matcher.
* dictionary.c (dict_vector) <iter_match_first, iter_match_next>:
Adjust to use lookup_name_info.
(dict_iter_match_first, dict_iter_match_next)
(iter_match_first_hashed, iter_match_next_hashed)
(iter_match_first_linear, iter_match_next_linear): Adjust to work
with a lookup_name_info.
* dictionary.h (dict_iter_match_first, dict_iter_match_next):
Likewise.
* dwarf2read.c (dw2_lookup_symbol): Adjust to use lookup_name_info.
(dw2_map_matching_symbols): Adjust to use symbol_name_match_type.
(gdb_index_symbol_name_matcher): New class.
(dw2_expand_symtabs_matching) Adjust to use lookup_name_info and
gdb_index_symbol_name_matcher. Accept a NULL symbol_matcher.
* f-lang.c (f_collect_symbol_completion_matches): Adjust to work
with a symbol_name_match_type.
(f_language_defn): Adjust comments to refer to
la_get_symbol_name_matcher.
* go-lang.c (go_language_defn): Adjust comments to refer to
la_get_symbol_name_matcher.
* language.c (default_symbol_name_matcher)
(language_get_symbol_name_matcher): New functions.
(unknown_language_defn, auto_language_defn): Adjust comments to
refer to la_get_symbol_name_matcher.
* language.h (symbol_name_cmp_ftype): Delete.
(language_defn) <la_collect_symbol_completion_matches>: Add match
type parameter.
<la_get_symbol_name_cmp>: Delete field.
<la_get_symbol_name_matcher>: New field.
<la_iterate_over_symbols>: Adjust to use lookup_name_info.
(default_symbol_name_matcher, language_get_symbol_name_matcher):
Declare.
* linespec.c (iterate_over_all_matching_symtabs)
(iterate_over_file_blocks): Adjust to use lookup_name_info.
(find_methods): Add language parameter, and use lookup_name_info
and the language's symbol_name_matcher_ftype.
(linespec_complete_function): Adjust.
(lookup_prefix_sym): Use lookup_name_info.
(add_all_symbol_names_from_pspace): Adjust.
(find_superclass_methods): Add language parameter and pass it
down.
(find_method): Pass symbol language down.
(find_linespec_symbols): Don't demangle or Ada encode here.
(search_minsyms_for_name): Add lookup_name_info parameter.
(add_matching_symbols_to_info): Add name_match_type parameter.
Use lookup_name_info.
* m2-lang.c (m2_language_defn): Adjust comments to refer to
la_get_symbol_name_matcher.
* minsyms.c: Include <algorithm>.
(add_minsym_to_demangled_hash_table): Remove table parameter and
add objfile parameter. Use search_name_hash, and add language to
demangled languages vector.
(struct found_minimal_symbols): New struct.
(lookup_minimal_symbol_mangled, lookup_minimal_symbol_demangled):
New functions.
(lookup_minimal_symbol): Adjust to use them. Don't canonicalize
input names here. Use lookup_name_info instead. Lookup up
demangled names once for each language in the demangled names
vector.
(iterate_over_minimal_symbols): Use lookup_name_info. Lookup up
demangled names once for each language in the demangled names
vector.
(build_minimal_symbol_hash_tables): Adjust.
* minsyms.h (iterate_over_minimal_symbols): Adjust to pass down a
lookup_name_info.
* objc-lang.c (objc_language_defn): Adjust comment to refer to
la_get_symbol_name_matcher.
* objfiles.h: Include <vector>.
(objfile_per_bfd_storage) <demangled_hash_languages>: New field.
* opencl-lang.c (opencl_language_defn): Adjust comment to refer to
la_get_symbol_name_matcher.
* p-lang.c (pascal_language_defn): Adjust comment to refer to
la_get_symbol_name_matcher.
* psymtab.c (psym_lookup_symbol): Use lookup_name_info.
(match_partial_symbol): Use symbol_name_match_type,
lookup_name_info and psymbol_name_matches.
(lookup_partial_symbol): Use lookup_name_info.
(map_block): Use symbol_name_match_type and lookup_name_info.
(psym_map_matching_symbols): Use symbol_name_match_type.
(psymbol_name_matches): New.
(recursively_search_psymtabs): Use lookup_name_info and
psymbol_name_matches. Rename 'kind' parameter to 'domain'.
(psym_expand_symtabs_matching): Use lookup_name_info. Rename
'kind' parameter to 'domain'.
* rust-lang.c (rust_language_defn): Adjust comment to refer to
la_get_symbol_name_matcher.
* symfile-debug.c (debug_qf_map_matching_symbols)
(debug_qf_map_matching_symbols): Use symbol_name_match_type.
(debug_qf_expand_symtabs_matching): Use lookup_name_info.
* symfile.c (expand_symtabs_matching): Use lookup_name_info.
* symfile.h (quick_symbol_functions) <map_matching_symbols>:
Adjust to use symbol_name_match_type.
<expand_symtabs_matching>: Adjust to use lookup_name_info.
(expand_symtabs_matching): Adjust to use lookup_name_info.
* symmisc.c (maintenance_expand_symtabs): Use
lookup_name_info::match_any ().
* symtab.c (symbol_matches_search_name): New.
(eq_symbol_entry): Adjust to use lookup_name_info and the
language's matcher.
(demangle_for_lookup_info::demangle_for_lookup_info): New.
(lookup_name_info::match_any): New.
(iterate_over_symbols, search_symbols): Use lookup_name_info.
(compare_symbol_name): Add language, lookup_name_info and
completion_match_result parameters, and use them.
(completion_list_add_name): Make extern. Add language and
lookup_name_info parameters. Use them.
(completion_list_add_symbol, completion_list_add_msymbol)
(completion_list_objc_symbol): Add lookup_name_info parameters and
adjust. Pass down language.
(completion_list_add_fields): Add lookup_name_info parameters and
adjust. Pass down language.
(add_symtab_completions): Add lookup_name_info parameters and
adjust.
(default_collect_symbol_completion_matches_break_on): Add
name_match_type parameter, and use it. Use lookup_name_info.
(default_collect_symbol_completion_matches)
(collect_symbol_completion_matches): Add name_match_type
parameter, and pass it down.
(collect_symbol_completion_matches_type): Adjust.
(collect_file_symbol_completion_matches): Add name_match_type
parameter, and use lookup_name_info.
* symtab.h: Include <string> and "common/gdb_optional.h".
(enum class symbol_name_match_type): New.
(class ada_lookup_name_info): New.
(struct demangle_for_lookup_info): New.
(class lookup_name_info): New.
(symbol_name_matcher_ftype): New.
(SYMBOL_MATCHES_SEARCH_NAME): Use symbol_matches_search_name.
(symbol_matches_search_name): Declare.
(MSYMBOL_MATCHES_SEARCH_NAME): Delete.
(default_collect_symbol_completion_matches)
(collect_symbol_completion_matches)
(collect_file_symbol_completion_matches): Add name_match_type
parameter.
(iterate_over_symbols): Use lookup_name_info.
(completion_list_add_name): Declare.
* utils.c (enum class strncmp_iw_mode): Moved to utils.h.
(strncmp_iw_with_mode): Now extern.
* utils.h (enum class strncmp_iw_mode): Moved from utils.c.
(strncmp_iw_with_mode): Declare.
gdb/testsuite/ChangeLog:
2017-11-08 Pedro Alves <palves@redhat.com>
* gdb.ada/complete.exp (p <Exported_Capitalized>): New test.
(p Exported_Capitalized): New test.
(p exported_capitalized): New test.
2017-11-08 22:22:32 +08:00
|
|
|
|
NULL, /* la_get_symbol_name_matcher */
|
2016-04-27 09:38:08 +08:00
|
|
|
|
iterate_over_symbols,
|
Per-language symbol name hashing algorithm
Currently, we have a mess of symbol name hashing/comparison routines.
There's msymbol_hash for mangled names, and dict_hash and
msymbol_hash_iw for demangled names. Then there's strcmp_iw,
strcmp_iw_ordered and Ada's full_match/wild_match, which all have to
agree with the hashing routines. That's why dict_hash is really about
Ada names. From the inconsistency department, minimal symbol hashing
doesn't go via dict_hash, so Ada's wild matching can't ever work with
minimal symbols.
This patch starts fixing this, by doing two things:
#1 - adds a language vector method to let each language decide how to
compute a symbol name hash.
#2 - makes dictionaries know the language of the symbols they hold,
and then use the dictionaries language to decide which hashing
method to use.
For now, this is just scaffolding, since all languages install the
default method. The series will make C++ install its own hashing
method later on, and will add per-language symbol name comparison
routines too.
This patch was originally based on a patch that Keith wrote for the
libcc1/C++ WIP support.
gdb/ChangeLog:
2017-11-08 Keith Seitz <keiths@redhat.com>
Pedro Alves <palves@redhat.com>
* ada-lang.c (ada_language_defn): Install
default_search_name_hash.
* buildsym.c (struct buildsym_compunit): <language>: New field.
(finish_block_internal): Pass language when creating dictionaries.
(start_buildsym_compunit, start_symtab): New language parameters.
Use them.
(restart_symtab): Pass down compilation unit's language.
* buildsym.h (enum language): Forward declare.
(start_symtab): New 'language' parameter.
* c-lang.c (c_language_defn, cplus_language_defn)
(asm_language_defn, minimal_language_defn): Install
default_search_name_hash.
* coffread.c (coff_start_symtab): Adjust.
* d-lang.c (d_language_defn): Install default_search_name_hash.
* dbxread.c (struct symloc): Add 'pst_language' field.
(PST_LANGUAGE): Define.
(start_psymtab, read_ofile_symtab): Use it.
(process_one_symbol): New 'language' parameter. Pass it down.
* dictionary.c (struct dictionary) <language>: New field.
(DICT_LANGUAGE): Define.
(dict_create_hashed, dict_create_hashed_expandable)
(dict_create_linear, dict_create_linear_expandable): New parameter
'language'. Set the dictionary's language.
(iter_match_first_hashed): Adjust to rename.
(insert_symbol_hashed): Assert we don't see mismatching
languages. Adjust to rename.
(dict_hash): Rename to ...
(default_search_name_hash): ... this and make extern.
* dictionary.h (struct language_defn): Forward declare.
(dict_create_hashed): New parameter 'language'.
* dwarf2read.c (dwarf2_start_symtab): Pass down language.
* f-lang.c (f_language_defn): Install default_search_name_hash.
* go-lang.c (go_language_defn): Install default_search_name_hash.
* jit.c (finalize_symtab): Pass compunit's language to dictionary
creation.
* language.c (unknown_language_defn, auto_language_defn):
* language.h (language_defn::la_search_name_hash): New field.
(default_search_name_hash): Declare.
* m2-lang.c (m2_language_defn): Install default_search_name_hash.
* mdebugread.c (new_block): New parameter 'language'.
* mdebugread.c (parse_symbol): Pass symbol language to block
allocation.
(psymtab_to_symtab_1): Pass down language.
(new_symtab): Pass compunit's language to block allocation.
* objc-lang.c (objc_language_defn): Install
default_search_name_hash.
* opencl-lang.c (opencl_language_defn):
* p-lang.c (pascal_language_defn): Install
default_search_name_hash.
* rust-lang.c (rust_language_defn): Install
default_search_name_hash.
* stabsread.h (enum language): Forward declare.
(process_one_symbol): Add 'language' parameter.
* symtab.c (search_name_hash): New function.
* symtab.h (search_name_hash): Declare.
* xcoffread.c (read_xcoff_symtab): Pass language to start_symtab.
2017-11-08 23:07:56 +08:00
|
|
|
|
default_search_name_hash,
|
2016-04-27 09:38:08 +08:00
|
|
|
|
&default_varobj_ops,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
LANG_MAGIC
|
|
|
|
|
};
|