From: Piotr Rudnicki Date: Fri, 30 May 2025 13:21:49 +0000 (+0200) Subject: gdb: handle struct and union types in evaluate_subexp_for_address_base X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a8f4696286aa48c8c5df6569c10036eaa980c0b2;p=thirdparty%2Fbinutils-gdb.git gdb: handle struct and union types in evaluate_subexp_for_address_base Suppose a function returns a struct and a method of that struct is called. E.g.: struct S { int a; int get () { return a; } }; S f () { S s; s.a = 42; return s; } ... int z = f().get(); ... GDB is able to evaluate the expression: (gdb) print f().get() $1 = 42 However, type-checking the expression fails: (gdb) ptype f().get() Attempt to take address of value not located in memory. This happens because the `get` function takes an implicit `this` pointer, which in this case is the value returned by `f()`, and GDB wants to get an address for that value, as if passing the implicit this pointer. However, during type-checking, the struct value returned by `f()` is a `not_lval`. A similar issue exists for union types, where methods called on temporary union objects would fail type-checking in the same way. Address the problems by handling `TYPE_CODE_STRUCT` and `TYPE_CODE_UNION` in `evaluate_subexp_for_address_base`. With this change, for struct's method call, we get (gdb) ptype f().get() type = int Add new test cases to file gdb.cp/chained-calls.exp to test this change. Regression-tested in X86-64 Linux. --- diff --git a/gdb/eval.c b/gdb/eval.c index 7601c3b0ddd..539b700ad8f 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -2566,11 +2566,13 @@ evaluate_subexp_for_address_base (enum noside noside, value *x) if (noside == EVAL_AVOID_SIDE_EFFECTS) { struct type *type = check_typedef (x->type ()); + enum type_code typecode = type->code (); if (TYPE_IS_REFERENCE (type)) return value::zero (lookup_pointer_type (type->target_type ()), not_lval); - else if (x->lval () == lval_memory || value_must_coerce_to_target (x)) + else if (x->lval () == lval_memory || value_must_coerce_to_target (x) + || typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION) return value::zero (lookup_pointer_type (x->type ()), not_lval); else error (_("Attempt to take address of value not located in memory.")); diff --git a/gdb/testsuite/gdb.cp/chained-calls.cc b/gdb/testsuite/gdb.cp/chained-calls.cc index 9d12c988b4d..9358c716b44 100644 --- a/gdb/testsuite/gdb.cp/chained-calls.cc +++ b/gdb/testsuite/gdb.cp/chained-calls.cc @@ -23,6 +23,8 @@ public: S operator+ (const S &s); + int get (); + int a; }; @@ -41,6 +43,12 @@ S::operator+ (const S &s) return res; } +int +S::get () +{ + return a; +} + S f (int i) { @@ -162,6 +170,8 @@ public: U (type t); type get_type (); + int get (); + int a; char c; type tp[2]; @@ -190,6 +200,12 @@ U::get_type () return tp[TYPE_INDEX]; } +int +U::get () +{ + return a; +} + int main () { @@ -198,6 +214,7 @@ main () B b = makeb (); C c; + int z = f (42).get (); return i + getb(b, 0); /* Break here */ } diff --git a/gdb/testsuite/gdb.cp/chained-calls.exp b/gdb/testsuite/gdb.cp/chained-calls.exp index 4f0597a0005..d34162c355b 100644 --- a/gdb/testsuite/gdb.cp/chained-calls.exp +++ b/gdb/testsuite/gdb.cp/chained-calls.exp @@ -42,3 +42,6 @@ gdb_test "p *c" ".* = {a = 5678}" "*c" gdb_test "p *c + *c" ".* = {a = 11356}" "*c + *c" gdb_test "p q(*c + *c)" ".* = {a = 11356}" "q(*c + *c)" gdb_test "p make_int().get_type ()" ".* = INT" "make_int().get_type ()" +gdb_test "p f(42).get()" " = 42" "f().get()" +gdb_test "ptype f(42).get()" "type = int" "ptype f().get()" +gdb_test "ptype make_int().get()" "type = int" "make_int().get()"