Support ptype/o in Rust
This adds support for ptype/o to the Rust language code. By default, the Rust compiler reorders fields to reduce padding. So, the Rust language code sorts the fields by offset before printing. This may yield somewhat odd-looking results, but it is faithful to "what really happens", and might be useful when doing lower-level debugging. The reordering can be disabled using #[repr(c)]; ptype/o might be more useful in this case. gdb/ChangeLog 2018-06-26 Tom Tromey <tom@tromey.com> PR rust/22574: * typeprint.c (whatis_exp): Allow ptype/o for Rust. * rust-lang.c (rust_print_struct_def): Add podata parameter. Update. (rust_internal_print_type): Add podata parameter. (rust_print_type): Update. gdb/testsuite/ChangeLog 2018-06-26 Tom Tromey <tom@tromey.com> PR rust/22574: * gdb.rust/simple.exp (test_one_slice): Add ptype/o tests. * gdb.rust/simple.rs (struct SimpleLayout): New.
This commit is contained in:
parent
e0c547d14a
commit
a33ccfc7af
6 changed files with 106 additions and 20 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
2018-06-26 Tom Tromey <tom@tromey.com>
|
||||||
|
|
||||||
|
PR rust/22574:
|
||||||
|
* typeprint.c (whatis_exp): Allow ptype/o for Rust.
|
||||||
|
* rust-lang.c (rust_print_struct_def): Add podata parameter.
|
||||||
|
Update.
|
||||||
|
(rust_internal_print_type): Add podata parameter.
|
||||||
|
(rust_print_type): Update.
|
||||||
|
|
||||||
2018-06-26 Tom Tromey <tom@tromey.com>
|
2018-06-26 Tom Tromey <tom@tromey.com>
|
||||||
|
|
||||||
* typeprint.h (struct print_offset_data) <update, finish,
|
* typeprint.h (struct print_offset_data) <update, finish,
|
||||||
|
|
|
@ -31,8 +31,10 @@
|
||||||
#include "objfiles.h"
|
#include "objfiles.h"
|
||||||
#include "psymtab.h"
|
#include "psymtab.h"
|
||||||
#include "rust-lang.h"
|
#include "rust-lang.h"
|
||||||
|
#include "typeprint.h"
|
||||||
#include "valprint.h"
|
#include "valprint.h"
|
||||||
#include "varobj.h"
|
#include "varobj.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -616,14 +618,14 @@ static void
|
||||||
rust_internal_print_type (struct type *type, const char *varstring,
|
rust_internal_print_type (struct type *type, const char *varstring,
|
||||||
struct ui_file *stream, int show, int level,
|
struct ui_file *stream, int show, int level,
|
||||||
const struct type_print_options *flags,
|
const struct type_print_options *flags,
|
||||||
bool for_rust_enum);
|
bool for_rust_enum, print_offset_data *podata);
|
||||||
|
|
||||||
/* Print a struct or union typedef. */
|
/* Print a struct or union typedef. */
|
||||||
static void
|
static void
|
||||||
rust_print_struct_def (struct type *type, const char *varstring,
|
rust_print_struct_def (struct type *type, const char *varstring,
|
||||||
struct ui_file *stream, int show, int level,
|
struct ui_file *stream, int show, int level,
|
||||||
const struct type_print_options *flags,
|
const struct type_print_options *flags,
|
||||||
bool for_rust_enum)
|
bool for_rust_enum, print_offset_data *podata)
|
||||||
{
|
{
|
||||||
/* Print a tuple type simply. */
|
/* Print a tuple type simply. */
|
||||||
if (rust_tuple_type_p (type))
|
if (rust_tuple_type_p (type))
|
||||||
|
@ -636,6 +638,13 @@ rust_print_struct_def (struct type *type, const char *varstring,
|
||||||
if (TYPE_N_BASECLASSES (type) > 0)
|
if (TYPE_N_BASECLASSES (type) > 0)
|
||||||
c_print_type (type, varstring, stream, show, level, flags);
|
c_print_type (type, varstring, stream, show, level, flags);
|
||||||
|
|
||||||
|
if (flags->print_offsets)
|
||||||
|
{
|
||||||
|
/* Temporarily bump the level so that the output lines up
|
||||||
|
correctly. */
|
||||||
|
level += 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* Compute properties of TYPE here because, in the enum case, the
|
/* Compute properties of TYPE here because, in the enum case, the
|
||||||
rest of the code ends up looking only at the variant part. */
|
rest of the code ends up looking only at the variant part. */
|
||||||
const char *tagname = TYPE_NAME (type);
|
const char *tagname = TYPE_NAME (type);
|
||||||
|
@ -674,16 +683,41 @@ rust_print_struct_def (struct type *type, const char *varstring,
|
||||||
|
|
||||||
if (TYPE_NFIELDS (type) == 0 && !is_tuple)
|
if (TYPE_NFIELDS (type) == 0 && !is_tuple)
|
||||||
return;
|
return;
|
||||||
if (for_rust_enum)
|
if (for_rust_enum && !flags->print_offsets)
|
||||||
fputs_filtered (is_tuple_struct ? "(" : "{", stream);
|
fputs_filtered (is_tuple_struct ? "(" : "{", stream);
|
||||||
else
|
else
|
||||||
fputs_filtered (is_tuple_struct ? " (\n" : " {\n", stream);
|
fputs_filtered (is_tuple_struct ? " (\n" : " {\n", stream);
|
||||||
|
|
||||||
|
/* When printing offsets, we rearrange the fields into storage
|
||||||
|
order. This lets us show holes more clearly. We work using
|
||||||
|
field indices here because it simplifies calls to
|
||||||
|
print_offset_data::update below. */
|
||||||
|
std::vector<int> fields;
|
||||||
for (int i = 0; i < TYPE_NFIELDS (type); ++i)
|
for (int i = 0; i < TYPE_NFIELDS (type); ++i)
|
||||||
{
|
{
|
||||||
QUIT;
|
|
||||||
if (field_is_static (&TYPE_FIELD (type, i)))
|
if (field_is_static (&TYPE_FIELD (type, i)))
|
||||||
continue;
|
continue;
|
||||||
|
if (is_enum && i == enum_discriminant_index)
|
||||||
|
continue;
|
||||||
|
fields.push_back (i);
|
||||||
|
}
|
||||||
|
if (flags->print_offsets)
|
||||||
|
std::sort (fields.begin (), fields.end (),
|
||||||
|
[&] (int a, int b)
|
||||||
|
{
|
||||||
|
return (TYPE_FIELD_BITPOS (type, a)
|
||||||
|
< TYPE_FIELD_BITPOS (type, b));
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int i : fields)
|
||||||
|
{
|
||||||
|
QUIT;
|
||||||
|
|
||||||
|
gdb_assert (!field_is_static (&TYPE_FIELD (type, i)));
|
||||||
|
gdb_assert (! (is_enum && i == enum_discriminant_index));
|
||||||
|
|
||||||
|
if (flags->print_offsets)
|
||||||
|
podata->update (type, i, stream);
|
||||||
|
|
||||||
/* We'd like to print "pub" here as needed, but rustc
|
/* We'd like to print "pub" here as needed, but rustc
|
||||||
doesn't emit the debuginfo, and our types don't have
|
doesn't emit the debuginfo, and our types don't have
|
||||||
|
@ -691,27 +725,35 @@ rust_print_struct_def (struct type *type, const char *varstring,
|
||||||
|
|
||||||
/* For a tuple struct we print the type but nothing
|
/* For a tuple struct we print the type but nothing
|
||||||
else. */
|
else. */
|
||||||
if (!for_rust_enum)
|
if (!for_rust_enum || flags->print_offsets)
|
||||||
print_spaces_filtered (level + 2, stream);
|
print_spaces_filtered (level + 2, stream);
|
||||||
if (is_enum)
|
if (is_enum)
|
||||||
{
|
fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
|
||||||
if (i == enum_discriminant_index)
|
|
||||||
continue;
|
|
||||||
fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
|
|
||||||
}
|
|
||||||
else if (!is_tuple_struct)
|
else if (!is_tuple_struct)
|
||||||
fprintf_filtered (stream, "%s: ", TYPE_FIELD_NAME (type, i));
|
fprintf_filtered (stream, "%s: ", TYPE_FIELD_NAME (type, i));
|
||||||
|
|
||||||
rust_internal_print_type (TYPE_FIELD_TYPE (type, i), NULL,
|
rust_internal_print_type (TYPE_FIELD_TYPE (type, i), NULL,
|
||||||
stream, (is_enum ? show : show - 1),
|
stream, (is_enum ? show : show - 1),
|
||||||
level + 2, flags, is_enum);
|
level + 2, flags, is_enum, podata);
|
||||||
if (!for_rust_enum)
|
if (!for_rust_enum || flags->print_offsets)
|
||||||
fputs_filtered (",\n", stream);
|
fputs_filtered (",\n", stream);
|
||||||
|
/* Note that this check of "I" is ok because we only sorted the
|
||||||
|
fields by offset when print_offsets was set, so we won't take
|
||||||
|
this branch in that case. */
|
||||||
else if (i + 1 < TYPE_NFIELDS (type))
|
else if (i + 1 < TYPE_NFIELDS (type))
|
||||||
fputs_filtered (", ", stream);
|
fputs_filtered (", ", stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!for_rust_enum)
|
if (flags->print_offsets)
|
||||||
|
{
|
||||||
|
/* Undo the temporary level increase we did above. */
|
||||||
|
level -= 2;
|
||||||
|
podata->finish (type, level, stream);
|
||||||
|
print_spaces_filtered (print_offset_data::indentation, stream);
|
||||||
|
if (level == 0)
|
||||||
|
print_spaces_filtered (2, stream);
|
||||||
|
}
|
||||||
|
if (!for_rust_enum || flags->print_offsets)
|
||||||
print_spaces_filtered (level, stream);
|
print_spaces_filtered (level, stream);
|
||||||
fputs_filtered (is_tuple_struct ? ")" : "}", stream);
|
fputs_filtered (is_tuple_struct ? ")" : "}", stream);
|
||||||
}
|
}
|
||||||
|
@ -735,7 +777,7 @@ static void
|
||||||
rust_internal_print_type (struct type *type, const char *varstring,
|
rust_internal_print_type (struct type *type, const char *varstring,
|
||||||
struct ui_file *stream, int show, int level,
|
struct ui_file *stream, int show, int level,
|
||||||
const struct type_print_options *flags,
|
const struct type_print_options *flags,
|
||||||
bool for_rust_enum)
|
bool for_rust_enum, print_offset_data *podata)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -778,7 +820,7 @@ rust_internal_print_type (struct type *type, const char *varstring,
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
fputs_filtered (", ", stream);
|
fputs_filtered (", ", stream);
|
||||||
rust_internal_print_type (TYPE_FIELD_TYPE (type, i), "", stream,
|
rust_internal_print_type (TYPE_FIELD_TYPE (type, i), "", stream,
|
||||||
-1, 0, flags, false);
|
-1, 0, flags, false, podata);
|
||||||
}
|
}
|
||||||
fputs_filtered (")", stream);
|
fputs_filtered (")", stream);
|
||||||
/* If it returns unit, we can omit the return type. */
|
/* If it returns unit, we can omit the return type. */
|
||||||
|
@ -786,7 +828,7 @@ rust_internal_print_type (struct type *type, const char *varstring,
|
||||||
{
|
{
|
||||||
fputs_filtered (" -> ", stream);
|
fputs_filtered (" -> ", stream);
|
||||||
rust_internal_print_type (TYPE_TARGET_TYPE (type), "", stream,
|
rust_internal_print_type (TYPE_TARGET_TYPE (type), "", stream,
|
||||||
-1, 0, flags, false);
|
-1, 0, flags, false, podata);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -796,7 +838,8 @@ rust_internal_print_type (struct type *type, const char *varstring,
|
||||||
|
|
||||||
fputs_filtered ("[", stream);
|
fputs_filtered ("[", stream);
|
||||||
rust_internal_print_type (TYPE_TARGET_TYPE (type), NULL,
|
rust_internal_print_type (TYPE_TARGET_TYPE (type), NULL,
|
||||||
stream, show - 1, level, flags, false);
|
stream, show - 1, level, flags, false,
|
||||||
|
podata);
|
||||||
|
|
||||||
if (TYPE_HIGH_BOUND_KIND (TYPE_INDEX_TYPE (type)) == PROP_LOCEXPR
|
if (TYPE_HIGH_BOUND_KIND (TYPE_INDEX_TYPE (type)) == PROP_LOCEXPR
|
||||||
|| TYPE_HIGH_BOUND_KIND (TYPE_INDEX_TYPE (type)) == PROP_LOCLIST)
|
|| TYPE_HIGH_BOUND_KIND (TYPE_INDEX_TYPE (type)) == PROP_LOCLIST)
|
||||||
|
@ -811,7 +854,7 @@ rust_internal_print_type (struct type *type, const char *varstring,
|
||||||
case TYPE_CODE_UNION:
|
case TYPE_CODE_UNION:
|
||||||
case TYPE_CODE_STRUCT:
|
case TYPE_CODE_STRUCT:
|
||||||
rust_print_struct_def (type, varstring, stream, show, level, flags,
|
rust_print_struct_def (type, varstring, stream, show, level, flags,
|
||||||
for_rust_enum);
|
for_rust_enum, podata);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_CODE_ENUM:
|
case TYPE_CODE_ENUM:
|
||||||
|
@ -856,8 +899,9 @@ rust_print_type (struct type *type, const char *varstring,
|
||||||
struct ui_file *stream, int show, int level,
|
struct ui_file *stream, int show, int level,
|
||||||
const struct type_print_options *flags)
|
const struct type_print_options *flags)
|
||||||
{
|
{
|
||||||
|
print_offset_data podata;
|
||||||
rust_internal_print_type (type, varstring, stream, show, level,
|
rust_internal_print_type (type, varstring, stream, show, level,
|
||||||
flags, false);
|
flags, false, &podata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
2018-06-26 Tom Tromey <tom@tromey.com>
|
||||||
|
|
||||||
|
PR rust/22574:
|
||||||
|
* gdb.rust/simple.exp (test_one_slice): Add ptype/o tests.
|
||||||
|
* gdb.rust/simple.rs (struct SimpleLayout): New.
|
||||||
|
|
||||||
2018-06-22 Simon Marchi <simon.marchi@ericsson.com>
|
2018-06-22 Simon Marchi <simon.marchi@ericsson.com>
|
||||||
|
|
||||||
* gdb.base/jit-reader.exp (jit_reader_test): Expect spaces in
|
* gdb.base/jit-reader.exp (jit_reader_test): Expect spaces in
|
||||||
|
|
|
@ -285,6 +285,24 @@ gdb_test "print parametrized" \
|
||||||
|
|
||||||
gdb_test "print u" " = simple::Union {f1: -1, f2: 255}"
|
gdb_test "print u" " = simple::Union {f1: -1, f2: 255}"
|
||||||
|
|
||||||
|
gdb_test_sequence "ptype/o Union" "" {
|
||||||
|
"/\\* offset | size \\*/ type = union simple::Union {"
|
||||||
|
"/\\* 1 \\*/ f1: i8,"
|
||||||
|
"/\\* 1 \\*/ f2: u8,"
|
||||||
|
""
|
||||||
|
" /\\* total size \\(bytes\\): 1 \\*/"
|
||||||
|
" }"
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_test_sequence "ptype/o SimpleLayout" "" {
|
||||||
|
"/\\* offset | size \\*/ type = struct simple::SimpleLayout {"
|
||||||
|
"/\\* 0 | 2 \\*/ f1: u16,"
|
||||||
|
"/\\* 2 | 2 \\*/ f2: u16,"
|
||||||
|
""
|
||||||
|
" /\\* total size \\(bytes\\): 4 \\*/"
|
||||||
|
" }"
|
||||||
|
}
|
||||||
|
|
||||||
load_lib gdb-python.exp
|
load_lib gdb-python.exp
|
||||||
if {[skip_python_tests]} {
|
if {[skip_python_tests]} {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -85,6 +85,13 @@ union Union {
|
||||||
f2: u8,
|
f2: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A simple structure whose layout won't be changed by the compiler,
|
||||||
|
// so that ptype/o testing will work on any platform.
|
||||||
|
struct SimpleLayout {
|
||||||
|
f1: u16,
|
||||||
|
f2: u16
|
||||||
|
}
|
||||||
|
|
||||||
fn main () {
|
fn main () {
|
||||||
let a = ();
|
let a = ();
|
||||||
let b : [i32; 0] = [];
|
let b : [i32; 0] = [];
|
||||||
|
@ -159,6 +166,7 @@ fn main () {
|
||||||
};
|
};
|
||||||
|
|
||||||
let u = Union { f2: 255 };
|
let u = Union { f2: 255 };
|
||||||
|
let v = SimpleLayout { f1: 8, f2: 9 };
|
||||||
|
|
||||||
println!("{}, {}", x.0, x.1); // set breakpoint here
|
println!("{}, {}", x.0, x.1); // set breakpoint here
|
||||||
println!("{}", diff2(92, 45));
|
println!("{}", diff2(92, 45));
|
||||||
|
|
|
@ -490,7 +490,8 @@ whatis_exp (const char *exp, int show)
|
||||||
feature. */
|
feature. */
|
||||||
if (show > 0
|
if (show > 0
|
||||||
&& (current_language->la_language == language_c
|
&& (current_language->la_language == language_c
|
||||||
|| current_language->la_language == language_cplus))
|
|| current_language->la_language == language_cplus
|
||||||
|
|| current_language->la_language == language_rust))
|
||||||
{
|
{
|
||||||
flags.print_offsets = 1;
|
flags.print_offsets = 1;
|
||||||
flags.print_typedefs = 0;
|
flags.print_typedefs = 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue