[binutils-gdb] gdb: preserve type instance flags in 'x' command
Tankut Baris Aktemur via Gdb-cvs <[email protected]>
| Newsgroups | gmane.comp.gdb.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=07519d531b1e858f665ff011d7f1002f38111ec8 commit 07519d531b1e858f665ff011d7f1002f38111ec8 Author: Tankut Baris Aktemur <[email protected]> Date: Tue Mar 24 16:56:05 2026 +0100 gdb: preserve type instance flags in 'x' command The 'x' command takes an arbitrary expression as its argument, evaluates it to a value, and treats the value as the address to read from. How many bytes to read from that address is decided based on the specified format, from which a type is derived. One can see this in the `$_` convenience variable that holds the last address read from. For example, suppose we have an integer variable and we want to examine the memory where the variable is located. (gdb) list 36 int main(int argc, char *argv[]) { 37 int a = 42; 38 39 return 0; 40 } (gdb) print &a $1 = (int *) 0x7fffffffdddc (gdb) Note that `&a` gives us an `int *`. Let's now examine the memory at `&a`. (gdb) x/1dh &a 0x7fffffffdddc: 42 (gdb) print $_ $2 = (int16_t *) 0x7fffffffdddc (gdb) Note the type of `$_`: `int16_t *`, not `int *`, although the argument was a `int *`. This happens because the 'x' command is a low-level command and GDB does not care much about the type of the argument; it is rather interested in using the evaluated value as an address. GDB simply discards the type of the argument. The format 'h' (half word) determines the type `int16_t`, with which GDB creates a lazy value. It is this lazy value with the `int16_t` type that fetches the data from the target. The problem with this is that if the argument type contains address class information, the information would be ignored. Let's use GDB's builtin `@data` modifier: (gdb) x/1dh (@data int *)&a 0x7fffffffdddc: 42 (gdb) print $_ $3 = (int16_t *) 0x7fffffffdddc (gdb) The `@data` modifier was dropped as can be seen in the type of `$_`. On an architecture where data and code pointers have to be distinguished, or where architecture-specific address classes are available, the 'x' command would not work. Address the problem by propagating the type instance flags of the argument to the type constructed from the format. With this patch, we get: (gdb) x/1dh (@data int *)&a 0x7fffffffdddc: 42 (gdb) print $_ $3 = (@data int16_t *) 0x7fffffffdddc (gdb) Side note: The 'x' command remembers the next address and can be re-used without an argument: (gdb) x 0x7fffffffddde: 0 (gdb) x 0x7fffffffdde0: 1 (gdb) x 0x7fffffffdde2: 0 (gdb) x 0x7fffffffdde4: 0 (gdb) print $_ $5 = (@data int16_t *) 0x7fffffffdde4 (gdb) With this patch, it also becomes possible to use the "next address" feature of the 'x' command. End side note. A final remark: There exists a `pointer_to_address` gdbarch method. One can wonder whether it not already solves the problem. The thing is, that gdbarch method would change the bits of the address and this may not be possible/meaningful on some architectures. Regression-tested on X86-64 Linux. Approved-By: Tom Tromey <[email protected]> Diff: --- gdb/printcmd.c | 19 +++++++++--- gdb/testsuite/gdb.base/examine-address-class.c | 23 +++++++++++++++ gdb/testsuite/gdb.base/examine-address-class.exp | 37 ++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/gdb/printcmd.c b/gdb/printcmd.c index 49e97ca336c..38a2e231d88 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -988,10 +988,11 @@ find_string_backward (struct gdbarch *gdbarch, } /* Given format FMT and architecture GDBARCH, return the corresponding - value type. */ + value type. Annotate the resulting type with FLAGS as the type + instance flags. */ static type * -format_to_type (format_data fmt, gdbarch *gdbarch) +format_to_type (format_data fmt, gdbarch *gdbarch, type_instance_flags flags) { char format = fmt.format; char size = fmt.size; @@ -1054,6 +1055,8 @@ format_to_type (format_data fmt, gdbarch *gdbarch) } gdb_assert (val_type != nullptr); + val_type = make_type_with_address_space (val_type, flags); + return val_type; } @@ -1884,7 +1887,11 @@ x_command (const char *exp, int from_tty) else next_address = value_as_address (val); - next_type = format_to_type (fmt, expr->gdbarch); + type_instance_flags flags = 0; + if (val->type ()->is_pointer_or_reference ()) + flags = val->type ()->target_type ()->instance_flags (); + + next_type = format_to_type (fmt, expr->gdbarch, flags); } if (next_type == nullptr) @@ -2167,7 +2174,11 @@ do_one_display (struct display *d) if (d->format.format == 'i') addr = gdbarch_addr_bits_remove (d->exp->gdbarch, addr); - next_type = format_to_type (d->format, d->exp->gdbarch); + type_instance_flags flags = 0; + if (val->type ()->is_pointer_or_reference ()) + flags = val->type ()->target_type ()->instance_flags (); + + next_type = format_to_type (d->format, d->exp->gdbarch, flags); next_address = addr; do_examine_next_address (d->format); } diff --git a/gdb/testsuite/gdb.base/examine-address-class.c b/gdb/testsuite/gdb.base/examine-address-class.c new file mode 100644 index 00000000000..c868b10119f --- /dev/null +++ b/gdb/testsuite/gdb.base/examine-address-class.c @@ -0,0 +1,23 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025-2026 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/>. */ + +int +main (void) +{ + int var = 42; + return 0; /* break-here. */ +} diff --git a/gdb/testsuite/gdb.base/examine-address-class.exp b/gdb/testsuite/gdb.base/examine-address-class.exp new file mode 100644 index 00000000000..058b2d5e0b2 --- /dev/null +++ b/gdb/testsuite/gdb.base/examine-address-class.exp @@ -0,0 +1,37 @@ +# Copyright (C) 2025-2026 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/>. + +# Verify that 'x' command preserves the type instance flags of its +# argument. + +standard_testfile + +if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} { + return +} + +if {![runto_main]} { + return +} + +set linenum [gdb_get_line_number "break-here"] +gdb_test "until $linenum" "break-here.*" "run until the line" + +gdb_test "x/1dh (int *) &var" "$hex:\[ \t\]+42" +gdb_test "print \$_" "\\(int16_t \\*\\) $hex" "type matches the format" + +gdb_test "x/1dh (@data int *) &var" "$hex:\[ \t\]+42" +gdb_test "print \$_" "\\(@data int16_t \\*\\) $hex" \ + "type instance flags are preserved"