diff options
-rw-r--r-- | gdb/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/eval.c | 13 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 19 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/dfp-test.c | 17 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/dfp-test.exp | 59 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/gnu_vector.exp | 27 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/whatis-ptype-typedefs.c | 143 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp | 272 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-prettyprint.c | 9 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-prettyprint.exp | 13 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-prettyprint.py | 34 | ||||
-rw-r--r-- | gdb/typeprint.c | 36 | ||||
-rw-r--r-- | gdb/valops.c | 33 |
13 files changed, 654 insertions, 31 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7ad3f4c..fae7150 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2017-08-21 Pedro Alves <palves@redhat.com> + + * eval.c (evaluate_subexp_standard) <OP_TYPE>: Don't dig past + typedefs. + * typeprint.c (whatis_exp): If handling "whatis", and expression + is OP_TYPE, strip one typedef level. Otherwise don't strip + typedefs here. + * valops.c (value_cast): Save "to" type before resolving + stubs/typedefs. Use that type as resulting value's type. + 2017-08-18 Tom Tromey <tom@tromey.com> Pedro Alves <palves@redhat.com> @@ -2727,18 +2727,7 @@ evaluate_subexp_standard (struct type *expect_type, if (noside == EVAL_SKIP) goto nosideret; else if (noside == EVAL_AVOID_SIDE_EFFECTS) - { - struct type *type = exp->elts[pc + 1].type; - - /* If this is a typedef, then find its immediate target. We - use check_typedef to resolve stubs, but we ignore its - result because we do not want to dig past all - typedefs. */ - check_typedef (type); - if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) - type = TYPE_TARGET_TYPE (type); - return allocate_value (type); - } + return allocate_value (exp->elts[pc + 1].type); else error (_("Attempt to use a type name as an expression")); diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index d188f83..03e825e 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,22 @@ +2017-08-21 Pedro Alves <palves@redhat.com> + + * gdb.base/dfp-test.c + (d32_t, d64_t, d128_t, d32_t2, d64_t2, d128_t2, v_d32_t, v_d64_t) + (v_d128_t, v_d32_t2, v_d64_t2, v_d128_t2): New. + * gdb.base/dfp-test.exp: Add whatis/ptype/cast tests. + * gdb.base/gnu_vector.exp: Add whatis/ptype/cast tests. + * gdb.base/whatis-ptype-typedefs.c: New. + * gdb.base/whatis-ptype-typedefs.exp: New. + * gdb.python/py-prettyprint.c (int_type, int_type2): New typedefs. + (an_int, an_int_type, an_int_type2): New globals. + * gdb.python/py-prettyprint.exp (run_lang_tests): Add tests + involving typedefs and cast expressions. + * gdb.python/py-prettyprint.py (class pp_int_typedef): New. + (lookup_typedefs_function): New. + (typedefs_pretty_printers_dict): New. + (top level): Register lookup_typedefs_function in + gdb.pretty_printers. + 2017-08-18 Yao Qi <yao.qi@linaro.org> * gdb.server/unittest.exp: New. diff --git a/gdb/testsuite/gdb.base/dfp-test.c b/gdb/testsuite/gdb.base/dfp-test.c index 3af2b4d..a184acb 100644 --- a/gdb/testsuite/gdb.base/dfp-test.c +++ b/gdb/testsuite/gdb.base/dfp-test.c @@ -91,6 +91,23 @@ volatile _Decimal32 d32; volatile _Decimal64 d64; volatile _Decimal128 d128; +/* Typedefs and typedefs of typedefs, for ptype/whatis testing. */ +typedef _Decimal32 d32_t; +typedef _Decimal64 d64_t; +typedef _Decimal128 d128_t; + +typedef d32_t d32_t2; +typedef d64_t d64_t2; +typedef d128_t d128_t2; + +d32_t v_d32_t; +d64_t v_d64_t; +d128_t v_d128_t; + +d32_t2 v_d32_t2; +d64_t2 v_d64_t2; +d128_t2 v_d128_t2; + struct decstruct { int int4; diff --git a/gdb/testsuite/gdb.base/dfp-test.exp b/gdb/testsuite/gdb.base/dfp-test.exp index 5f7b13d..c3a51a4 100644 --- a/gdb/testsuite/gdb.base/dfp-test.exp +++ b/gdb/testsuite/gdb.base/dfp-test.exp @@ -274,6 +274,10 @@ gdb_test "ptype d64 + ds.dec32" " = volatile _Decimal64" gdb_test "ptype d128 + ds.dec32" " = volatile _Decimal128" gdb_test "ptype d128 + ds.dec64" " = volatile _Decimal128" +gdb_test "whatis d64 + ds.dec32" " = volatile _Decimal64" +gdb_test "whatis d128 + ds.dec32" " = volatile _Decimal128" +gdb_test "whatis d128 + ds.dec64" " = volatile _Decimal128" + # Mixture of Decimal and integral operands gdb_test "p d32 + 1" " = 1.1" gdb_test "p 2 + d64" " = 2.1" @@ -331,3 +335,58 @@ gdb_test "print ds.dec128 = -ds.double8" " = 0.(0999.*|1000.*)" gdb_test "print ds.dec128 = ds.dec32" " = -0.1" gdb_test "print ds.dec32 = ds.int4" " = 1" gdb_test "print ds.int4 = 7.3dl" " = 7" + +# Test "whatis"/"ptype" of expressions involving casts to/from dfp +# typedefs. + +# This list is composed by sub-lists, and their elements are (in +# order): +# +# - Type to cast to. This is also what "whatis" should print. +# - What "ptype" should print. + +# Columns in the sublists represent: + # to/whatis # ptype +foreach elem { + {"_Decimal32" "_Decimal32"} + {"_Decimal64" "_Decimal64"} + {"_Decimal128" "_Decimal128"} + {"d32_t" "_Decimal32"} + {"d64_t" "_Decimal64"} + {"d128_t" "_Decimal128"} + {"d32_t2" "_Decimal32"} + {"d64_t2" "_Decimal64"} + {"d128_t2" "_Decimal128"} +} { + set type [lindex $elem 0] + set ptype [lindex $elem 1] + gdb_test "whatis ($type) 0" " = $type" + gdb_test "ptype ($type) 0" " = $ptype" +} + +# Test: +# - whatis/ptype of variables of typedef type. +# - whatis/ptype of typedef type names. +# - whatis/ptype of typedef-of-typedef type names. + +# Columns in the sublists represent: + # Type name # whatis # ptype +foreach elem { + {"v_d32_t" "d32_t" "_Decimal32"} + {"v_d64_t" "d64_t" "_Decimal64"} + {"v_d128_t" "d128_t" "_Decimal128"} + + {"d32_t" "_Decimal32" "_Decimal32"} + {"d64_t" "_Decimal64" "_Decimal64"} + {"d128_t" "_Decimal128" "_Decimal128"} + + {"d32_t2" "d32_t" "_Decimal32"} + {"d64_t2" "d64_t" "_Decimal64"} + {"d128_t2" "d128_t" "_Decimal128"} +} { + set type [lindex $elem 0] + set whatis [lindex $elem 1] + set ptype [lindex $elem 2] + gdb_test "whatis $type" " = $whatis" + gdb_test "ptype $type" " = $ptype" +} diff --git a/gdb/testsuite/gdb.base/gnu_vector.exp b/gdb/testsuite/gdb.base/gnu_vector.exp index 44b1405..dac1714 100644 --- a/gdb/testsuite/gdb.base/gnu_vector.exp +++ b/gdb/testsuite/gdb.base/gnu_vector.exp @@ -95,6 +95,17 @@ gdb_test "print -f4a" "\\\$$decimal = \\{-2, -4, -8, -16\\}" gdb_test "print (char4) 0x01010101" "\\\$$decimal = \\{1, 1, 1, 1\\}" gdb_test "print (int2) lla" "\\\$$decimal = \\{1, 1\\}" +# Check that "whatis" doesn't peel off the destination type's typedef +# by mistake, in expressions that involve a cast to typedef type. +gdb_test "whatis (char4) 0x01010101" "type = char4" +gdb_test "whatis (int2) lla" "type = int2" +# Check that OTOH "ptype" does peel off the destination type's +# typedef. +gdb_test "ptype (char4) 0x01010101" \ + "type = char __attribute__ \\(\\(vector_size\\(4\\)\\)\\)" +gdb_test "ptype (int2) lla" \ + "type = int __attribute__ \\(\\(vector_size\\(2\\)\\)\\)" + if { ![string compare $endian big] } then { gdb_test "print (char4) ia" "\\\$$decimal = \\{0, 0, 0, 2\\}" } else { @@ -167,16 +178,30 @@ gdb_test "print (double2) f2" "Cannot convert between vector values of different gdb_test "print (int4) c4" "Cannot convert between vector values of different sizes" gdb_test "print (char4) i4a" "Cannot convert between vector values of different sizes" -# Test ptype on vector types. +# Test ptype/whatis on vector types/vars. gdb_test "ptype c4" "type = char __attribute__ \\(\\(vector_size\\(4\\)\\)\\)" +gdb_test "whatis c4" "type = char4" + gdb_test "ptype char4" "type = char __attribute__ \\(\\(vector_size\\(4\\)\\)\\)" +gdb_test "whatis char4" "type = char __attribute__ \\(\\(vector_size\\(4\\)\\)\\)" + gdb_test "ptype i4a" "type = int __attribute__ \\(\\(vector_size\\(4\\)\\)\\)" +gdb_test "whatis i4a" "type = int4" + gdb_test "ptype int4" "type = int __attribute__ \\(\\(vector_size\\(4\\)\\)\\)" +gdb_test "whatis int4" "type = int __attribute__ \\(\\(vector_size\\(4\\)\\)\\)" + gdb_test "ptype f4b" "type = float __attribute__ \\(\\(vector_size\\(4\\)\\)\\)" +gdb_test "whatis f4b" "type = float4" + gdb_test "ptype float4" "type = float __attribute__ \\(\\(vector_size\\(4\\)\\)\\)" +gdb_test "whatis float4" "type = float __attribute__ \\(\\(vector_size\\(4\\)\\)\\)" gdb_test "ptype union_with_vector_1" "type = union {\r\n\[\t \]+int i;\r\n\[\t \]+char cv __attribute__ \\(\\(vector_size\\(4\\)\\)\\);\r\n}" +gdb_test "whatis union_with_vector_1" {type = union {...}} + gdb_test "ptype struct_with_vector_1" "type = struct {\r\n\[\t \]+int i;\r\n\[\t \]+char cv __attribute__ \\(\\(vector_size\\(4\\)\\)\\);\r\n\[\t \]+float4 f4;\r\n}" +gdb_test "whatis struct_with_vector_1" {type = struct {...}} # Test inferior function calls with vector arguments and/or vector # return values. diff --git a/gdb/testsuite/gdb.base/whatis-ptype-typedefs.c b/gdb/testsuite/gdb.base/whatis-ptype-typedefs.c new file mode 100644 index 0000000..5711a96 --- /dev/null +++ b/gdb/testsuite/gdb.base/whatis-ptype-typedefs.c @@ -0,0 +1,143 @@ +/* This test program is part of GDB, the GNU debugger. + + Copyright 2017 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Define typedefs of different types, for testing the "whatis" and + "ptype" commands. */ + +/* Helper macro used to consistently define variables/typedefs using + the same name scheme. BASE is the shared part of the name of all + typedefs/variables generated. Defines a variable of the given + typedef type, and then a typedef of that typedef and a variable of + that new typedef type. The "double typedef" is useful to checking + that whatis only strips one typedef level. For example, if BASE is + "int", we get: + + int_typedef v_int_typedef; // "v_" stands for variable of typedef type + typedef int_typedef int_typedef2; // typedef-of-typedef + int_typedef2 v_int_typedef2; // var of typedef-of-typedef +*/ +#define DEF(base) \ + base ## _typedef v_ ## base ## _typedef; \ + \ + typedef base ## _typedef base ## _typedef2; \ + base ## _typedef2 v_ ## base ## _typedef2 + +/* Void. */ + +/* (Can't have variables of void type.) */ + +typedef void void_typedef; +typedef void_typedef void_typedef2; + +void_typedef *v_void_typedef_ptr; +void_typedef2 *v_void_typedef_ptr2; + +/* Integers. */ + +typedef int int_typedef; +DEF (int); + +/* Floats. */ + +typedef float float_typedef; +DEF (float); + +/* Enums. */ + +typedef enum colors {red, green, blue} colors_typedef; +DEF (colors); + +/* Structures. */ + +typedef struct t_struct +{ + int member; +} t_struct_typedef; +DEF (t_struct); + +/* Unions. */ + +typedef union t_union +{ + int member; +} t_union_typedef; +DEF (t_union); + +/* Arrays. */ + +typedef int int_array_typedef[3]; +DEF (int_array); + +/* An array the same size of t_struct_typedef, so we can test casting. */ +typedef unsigned char uchar_array_t_struct_typedef[sizeof (t_struct_typedef)]; +DEF (uchar_array_t_struct); + +/* A struct and a eunion the same size as t_struct, so we can test + casting. */ + +typedef struct t_struct_wrapper +{ + struct t_struct base; +} t_struct_wrapper_typedef; +DEF (t_struct_wrapper); + +typedef union t_struct_union_wrapper +{ + struct t_struct base; +} t_struct_union_wrapper_typedef; +DEF (t_struct_union_wrapper); + +/* Functions / function pointers. */ + +typedef void func_ftype (void); +func_ftype *v_func_ftype; + +typedef func_ftype func_ftype2; +func_ftype2 *v_func_ftype2; + +/* C++ methods / method pointers. */ + +#ifdef __cplusplus + +namespace ns { + +struct Struct { void method (); }; +void Struct::method () {} + +typedef Struct Struct_typedef; +DEF (Struct); + +/* Typedefs/vars in a namespace. */ +typedef void (Struct::*method_ptr_typedef) (); +DEF (method_ptr); + +} + +/* Similar, but in the global namespace. */ +typedef ns::Struct ns_Struct_typedef; +DEF (ns_Struct); + +typedef void (ns::Struct::*ns_method_ptr_typedef) (); +DEF (ns_method_ptr); + +#endif + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp b/gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp new file mode 100644 index 0000000..d333d81 --- /dev/null +++ b/gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp @@ -0,0 +1,272 @@ +# Copyright 2017 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Test "whatis"/"ptype" of different typedef types, and of expressions +# involving casts to/from different typedefs. +# +# Particularly, when "whatis" is given a type name directly, it should +# strip one (and only one) typedef level. Otherwise, it should not +# strip any typedef at all. GDB used to incorrectly strip typedefs of +# expressions involving casts to typedef types. E.g., (gdb) print +# (int_typedef)0" shall result in a value of type "int_typedef", not +# "int". + +standard_testfile + +# Prepare for testing in language LANG. Lang can be "c" or "c++". + +proc prepare {lang} { + global srcfile testfile + + if [target_info exists no_long_long] { + set options [list debug additional_flags=-DNO_LONG_LONG] + } else { + set options [list debug] + } + + if {$lang == "c++"} { + lappend options c++ + set out $testfile-cxx + } else { + set out $testfile-c + } + + if { [prepare_for_testing "failed to prepare" \ + ${out} [list $srcfile] $options] } { + return -1 + } + + if ![runto_main] then { + fail "can't run to main" + return 0 + } +} + +# The following list is layed out as a table. It is composed by +# sub-lists (lines), with each line representing one whatis/ptype +# test. The sub-list (line) elements (columns) are (in order): +# +# EXP - The user expression passed to whatis/ptype. +# +# WHATIS - What "whatis" should print. +# +# If the EXP column is a type name, then this will be the same type, +# with one (and only one) typedef level removed. Otherwise, this is +# the type of the expression on the first column, with all typedefs +# preserved. +# +# PTYPE - What "ptype" should print. +# +# This is always the type of the input type/expression stripped from +# all typedefs. +# +# LANGUAGE - If the line is language-specific, which language. +# +# This can be "c" or "c++". +# +# Columns in the table represent: + # EXP # whatis # ptype # language +set table { + {"void_typedef" "void" "void"} + {"void_typedef2" "void_typedef" "void"} + + {"int_typedef" "int" "int"} + {"int_typedef2" "int_typedef" "int"} + {"v_int_typedef" "int_typedef" "int"} + {"v_int_typedef2" "int_typedef2" "int"} + + {"float_typedef" "float" "float"} + {"float_typedef2" "float_typedef" "float"} + {"v_float_typedef" "float_typedef" "float"} + {"v_float_typedef2" "float_typedef2" "float"} + + {"colors_typedef" "(enum )?colors" "enum colors( : unsigned int)? {red, green, blue}"} + {"colors_typedef2" "colors_typedef" "enum colors( : unsigned int)? {red, green, blue}"} + {"v_colors_typedef" "colors_typedef" "enum colors( : unsigned int)? {red, green, blue}"} + {"v_colors_typedef2" "colors_typedef2" "enum colors( : unsigned int)? {red, green, blue}"} + + {"func_ftype" "void \\(void\\)" "void \\(void\\)"} + {"func_ftype2" "func_ftype" "void \\(void\\)"} + + {"func_ftype *" "func_ftype \\*" "void \\(\\*\\)\\(void\\)"} + {"func_ftype2 *" "func_ftype2 \\*" "void \\(\\*\\)\\(void\\)"} + {"v_func_ftype" "func_ftype \\*" "void \\(\\*\\)\\(void\\)"} + {"v_func_ftype2" "func_ftype2 \\*" "void \\(\\*\\)\\(void\\)"} + + {"v_t_struct_typedef" "t_struct_typedef" "struct t_struct {.* member;.*}"} + {"v_t_struct_typedef2" "t_struct_typedef2" "struct t_struct {.* member;.*}"} + {"v_t_struct_union_wrapper_typedef" "t_struct_union_wrapper_typedef" "union t_struct_union_wrapper {.*base;.*}"} + {"v_t_struct_union_wrapper_typedef2" "t_struct_union_wrapper_typedef2" "union t_struct_union_wrapper {.*base;.*}"} + {"v_uchar_array_t_struct_typedef" "uchar_array_t_struct_typedef" "unsigned char \\[.*\\]"} + {"v_uchar_array_t_struct_typedef2" "uchar_array_t_struct_typedef2" "unsigned char \\[.*\\]"} + + {"v_ns_Struct_typedef" "ns_Struct_typedef" "struct ns::Struct {.* method.*}" "c++"} + + {"ns_method_ptr_typedef" + "void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)" + "void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)" + "c++"} + + {"ns::method_ptr_typedef" + "void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)" + "void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)" + "c++"} + + {"ns_method_ptr_typedef2" + "ns_method_ptr_typedef" + "void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)" + "c++"} + + {"ns::method_ptr_typedef2" + "ns::method_ptr_typedef" + "void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)" + "c++"} + + {"ns::Struct::method" + "void \\(ns::Struct \\* const\\)" + "void \\(ns::Struct \\* const\\)" + "c++"} +} + +# The 4th column above is optional. If present, it indicates that the +# line should only be tested in the specified language. This is a +# helper function that checks whether LINE's language matches LANG. +proc line_lang_match {line lang} { + if {[llength $line] <= 3} { + return true + } + + set line_lang [lindex $line 3] + if {$line_lang == "" || $lang == $line_lang} { + return true + } + + return false +} + +# Run tests in language LANG. + +proc run_tests {lang} { + global table + global gdb_prompt + + # Test passing all EXP in the list/table above to whatis/ptype, + # and check what comes out. + with_test_prefix "whatis/ptype" { + foreach line $table { + set type [lindex $line 0] + set whatis [lindex $line 1] + set ptype [lindex $line 2] + + if {![line_lang_match $line $lang]} { + continue + } + + # GCC doesn't record the target type of "typedef of + # typedef of void" types in the DWARF. See + # <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81267>. + # Handle that case manually in order to be able to xfail + # it. + if {$type == "void_typedef2"} { + set test "whatis $type" + gdb_test_multiple $test $test { + -re "type = void\r\n$gdb_prompt $" { + # gcc/81267. + setup_xfail "*-*-*" + fail "$test (void)" + } + -re "type = void_typedef\r\n$gdb_prompt $" { + pass $test + } + } + } else { + gdb_test "whatis $type" "type = $whatis" + } + + gdb_test "ptype $type" "type = $ptype" + } + } + + # Test converting/casting all variables in the first column of the + # table to all types (found in the first column of the table). + # The aggregates are all defined to be the same size so that + # casting actually works. (GDB's casting operator is more general + # than a C cast.) + # + # The main idea here is testing all the different paths in the + # value casting code in GDB (value_cast), making sure typedefs are + # preserved. + with_test_prefix "cast" { + foreach line1 $table { + set from [lindex $line1 0] + + if {![line_lang_match $line1 $lang]} { + continue + } + + foreach line2 $table { + set to [lindex $line2 0] + set whatis [lindex $line2 1] + set ptype [lindex $line2 2] + + if {![line_lang_match $line2 $lang]} { + continue + } + + # We try all combinations, even those that don't + # parse, or are invalid, to catch the case of a + # regression making them inadvertently valid. For + # example, these convertions are invalid: + # + # float <-> array + # array -> function (not function pointer) + # array -> member_ptr + # + # while these are invalid syntax: + # + # (anything) type + # (var) anything + # (method) anything [not method pointer] + # (float) method + # + if {([string match "v_*" $to] + || (![string match "v_*" $from] && ![string match "*method" $from]) + || [string match "*method" $to])} { + gdb_test "whatis ($to) $from" "syntax error.*" "whatis ($to) $from (syntax)" + gdb_test "ptype ($to) $from" "syntax error.*" "ptype ($to) $from (syntax)" + } elseif {([string match "*float*" $from] && [string match "*array*" $to]) + || ([string match "float*" $to] && [string match "*array*" $from]) + || ([string match "float*" $to] && [string match "*method" $from]) + || ([string match "*ftype" $to] && [string match "*array*" $from]) + || ([string match "*ftype2" $to] && [string match "*array*" $from]) + || ([string match "*ftype" $to] && [string match "*method" $from]) + || ([string match "*ftype2" $to] && [string match "*method" $from]) + || ([string match "*method_ptr*" $to] && [string match "*method" $from]) + || ([string match "*method_ptr*" $to] && [string match "*array*" $from])} { + gdb_test "whatis ($to) $from" "Invalid cast." "whatis ($to) $from (invalid)" + gdb_test "ptype ($to) $from" "Invalid cast." "ptype ($to) $from (invalid)" + } else { + gdb_test "whatis ($to) $from" "type = [string_to_regexp $to]" + gdb_test "ptype ($to) $from" "type = $ptype" + } + } + } + } +} + +foreach_with_prefix lang {"c" "c++"} { + prepare $lang + run_tests $lang +} diff --git a/gdb/testsuite/gdb.python/py-prettyprint.c b/gdb/testsuite/gdb.python/py-prettyprint.c index fd58358..82f9fe7 100644 --- a/gdb/testsuite/gdb.python/py-prettyprint.c +++ b/gdb/testsuite/gdb.python/py-prettyprint.c @@ -257,6 +257,15 @@ bug_14741() set_item(&c, 0, 5); } +/* Some typedefs/variables for checking that GDB doesn't lose typedefs + when looking for a printer. */ +typedef int int_type; +typedef int_type int_type2; + +int an_int = -1; +int_type an_int_type = 1; +int_type2 an_int_type2 = 2; + int main () { diff --git a/gdb/testsuite/gdb.python/py-prettyprint.exp b/gdb/testsuite/gdb.python/py-prettyprint.exp index b0a9e32..02300e9 100644 --- a/gdb/testsuite/gdb.python/py-prettyprint.exp +++ b/gdb/testsuite/gdb.python/py-prettyprint.exp @@ -110,6 +110,19 @@ proc run_lang_tests {exefile lang} { gdb_test "print nstype" " = {.0. = 7, .1. = 42}" \ "print nstype on one line" + # Check that GDB doesn't lose typedefs when looking for a printer. + gdb_test "print an_int" " = -1" + gdb_test "print (int) an_int" " = -1" + gdb_test "print (int_type) an_int" " = type=int_type, val=-1" + + gdb_test "print an_int_type" " = type=int_type, val=1" + gdb_test "print (int_type) an_int_type" " = type=int_type, val=1" + + gdb_test "print an_int_type2" " = type=int_type2, val=2" + gdb_test "print (int) an_int_type2" " = 2" + gdb_test "print (int_type) an_int_type2" " = type=int_type, val=2" + gdb_test "print (int_type2) an_int_type2" " = type=int_type2, val=2" + gdb_continue_to_end } diff --git a/gdb/testsuite/gdb.python/py-prettyprint.py b/gdb/testsuite/gdb.python/py-prettyprint.py index c56f564..ec845e4 100644 --- a/gdb/testsuite/gdb.python/py-prettyprint.py +++ b/gdb/testsuite/gdb.python/py-prettyprint.py @@ -227,6 +227,13 @@ class pp_eval_type (object): gdb.execute("bt", to_string=True) return "eval=<" + str(gdb.parse_and_eval("eval_func (123456789, 2, 3, 4, 5, 6, 7, 8)")) + ">" +class pp_int_typedef (object): + def __init__(self, val): + self.val = val + + def to_string(self): + return "type=%s, val=%s" % (self.val.type, int(self.val)) + def lookup_function (val): "Look-up and return a pretty-printer that can print val." @@ -263,6 +270,26 @@ def disable_lookup_function (): def enable_lookup_function (): lookup_function.enabled = True +# Lookup a printer for VAL in the typedefs dict. +def lookup_typedefs_function (val): + "Look-up and return a pretty-printer that can print val (typedefs)." + + # Get the type. + type = val.type + + if type == None or type.name == None or type.code != gdb.TYPE_CODE_TYPEDEF: + return None + + # Iterate over local dictionary of typedef types to determine if a + # printer is registered for that type. Return an instantiation of + # the printer if found. + for function in typedefs_pretty_printers_dict: + if function.match (type.name): + return typedefs_pretty_printers_dict[function] (val) + + # Cannot find a pretty printer. + return None + def register_pretty_printers (): pretty_printers_dict[re.compile ('^struct s$')] = pp_s pretty_printers_dict[re.compile ('^s$')] = pp_s @@ -309,7 +336,14 @@ def register_pretty_printers (): pretty_printers_dict[re.compile ('^eval_type_s$')] = pp_eval_type + typedefs_pretty_printers_dict[re.compile ('^int_type$')] = pp_int_typedef + typedefs_pretty_printers_dict[re.compile ('^int_type2$')] = pp_int_typedef + +# Dict for struct types with typedefs fully stripped. pretty_printers_dict = {} +# Dict for typedef types. +typedefs_pretty_printers_dict = {} register_pretty_printers () gdb.pretty_printers.append (lookup_function) +gdb.pretty_printers.append (lookup_typedefs_function) diff --git a/gdb/typeprint.c b/gdb/typeprint.c index fc687d3..045271a 100644 --- a/gdb/typeprint.c +++ b/gdb/typeprint.c @@ -443,12 +443,40 @@ whatis_exp (char *exp, int show) } expression_up expr = parse_expression (exp); - val = evaluate_type (expr.get ()); + + /* The behavior of "whatis" depends on whether the user + expression names a type directly, or a language expression + (including variable names). If the former, then "whatis" + strips one level of typedefs, only. If an expression, + "whatis" prints the type of the expression without stripping + any typedef level. "ptype" always strips all levels of + typedefs. */ + if (show == -1 && expr->elts[0].opcode == OP_TYPE) + { + /* The user expression names a type directly. */ + type = expr->elts[1].type; + + /* If this is a typedef, then find its immediate target. + Use check_typedef to resolve stubs, but ignore its result + because we do not want to dig past all typedefs. */ + check_typedef (type); + if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) + type = TYPE_TARGET_TYPE (type); + } + else + { + /* The user expression names a type indirectly by naming an + object or expression of that type. Find that + indirectly-named type. */ + val = evaluate_type (expr.get ()); + type = value_type (val); + } } else - val = access_value_history (0); - - type = value_type (val); + { + val = access_value_history (0); + type = value_type (val); + } get_user_print_options (&opts); if (opts.objectprint) diff --git a/gdb/valops.c b/gdb/valops.c index 3668f0b..c1bb937 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -379,6 +379,11 @@ value_cast (struct type *type, struct value *arg2) /* We deref the value and then do the cast. */ return value_cast (type, coerce_ref (arg2)); + /* Strip typedefs / resolve stubs in order to get at the type's + code/length, but remember the original type, to use as the + resulting type of the cast, in case it was a typedef. */ + struct type *to_type = type; + type = check_typedef (type); code1 = TYPE_CODE (type); arg2 = coerce_ref (arg2); @@ -434,7 +439,7 @@ value_cast (struct type *type, struct value *arg2) code2 = TYPE_CODE (type2); if (code1 == TYPE_CODE_COMPLEX) - return cast_into_complex (type, arg2); + return cast_into_complex (to_type, arg2); if (code1 == TYPE_CODE_BOOL) { code1 = TYPE_CODE_INT; @@ -453,14 +458,14 @@ value_cast (struct type *type, struct value *arg2) && (code2 == TYPE_CODE_STRUCT || code2 == TYPE_CODE_UNION) && TYPE_NAME (type) != 0) { - struct value *v = value_cast_structs (type, arg2); + struct value *v = value_cast_structs (to_type, arg2); if (v) return v; } if (code1 == TYPE_CODE_FLT && scalar) - return value_from_double (type, value_as_double (arg2)); + return value_from_double (to_type, value_as_double (arg2)); else if (code1 == TYPE_CODE_DECFLOAT && scalar) { enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type)); @@ -476,7 +481,7 @@ value_cast (struct type *type, struct value *arg2) /* The only option left is an integral type. */ decimal_from_integral (arg2, dec, dec_len, byte_order); - return value_from_decfloat (type, dec); + return value_from_decfloat (to_type, dec); } else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM || code1 == TYPE_CODE_RANGE) @@ -497,7 +502,7 @@ value_cast (struct type *type, struct value *arg2) gdbarch_byte_order (get_type_arch (type2))); else longest = value_as_long (arg2); - return value_from_longest (type, convert_to_boolean ? + return value_from_longest (to_type, convert_to_boolean ? (LONGEST) (longest ? 1 : 0) : longest); } else if (code1 == TYPE_CODE_PTR && (code2 == TYPE_CODE_INT @@ -523,14 +528,14 @@ value_cast (struct type *type, struct value *arg2) || longest <= -((LONGEST) 1 << addr_bit)) warning (_("value truncated")); } - return value_from_longest (type, longest); + return value_from_longest (to_type, longest); } else if (code1 == TYPE_CODE_METHODPTR && code2 == TYPE_CODE_INT && value_as_long (arg2) == 0) { - struct value *result = allocate_value (type); + struct value *result = allocate_value (to_type); - cplus_make_method_ptr (type, value_contents_writeable (result), 0, 0); + cplus_make_method_ptr (to_type, value_contents_writeable (result), 0, 0); return result; } else if (code1 == TYPE_CODE_MEMBERPTR && code2 == TYPE_CODE_INT @@ -538,7 +543,7 @@ value_cast (struct type *type, struct value *arg2) { /* The Itanium C++ ABI represents NULL pointers to members as minus one, instead of biasing the normal case. */ - return value_from_longest (type, -1); + return value_from_longest (to_type, -1); } else if (code1 == TYPE_CODE_ARRAY && TYPE_VECTOR (type) && code2 == TYPE_CODE_ARRAY && TYPE_VECTOR (type2) @@ -549,21 +554,21 @@ value_cast (struct type *type, struct value *arg2) error (_("can only cast scalar to vector of same size")); else if (code1 == TYPE_CODE_VOID) { - return value_zero (type, not_lval); + return value_zero (to_type, not_lval); } else if (TYPE_LENGTH (type) == TYPE_LENGTH (type2)) { if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) - return value_cast_pointers (type, arg2, 0); + return value_cast_pointers (to_type, arg2, 0); arg2 = value_copy (arg2); - deprecated_set_value_type (arg2, type); - set_value_enclosing_type (arg2, type); + deprecated_set_value_type (arg2, to_type); + set_value_enclosing_type (arg2, to_type); set_value_pointed_to_offset (arg2, 0); /* pai: chk_val */ return arg2; } else if (VALUE_LVAL (arg2) == lval_memory) - return value_at_lazy (type, value_address (arg2)); + return value_at_lazy (to_type, value_address (arg2)); else { error (_("Invalid cast.")); |