Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Keith Seitz <keiths@redhat.com>
To: Andrew Burgess <aburgess@redhat.com>, gdb-patches@sourceware.org
Subject: Re: [PATCHv4] gdb: include NT_I386_TLS note in generated core files
Date: Thu, 6 Nov 2025 13:20:02 -0800	[thread overview]
Message-ID: <83120a5b-3448-421b-9ac5-8d1c12ed2fa6@redhat.com> (raw)
In-Reply-To: <aca276e8d328ca8a794a40e8e9e641ecd4e6ba98.1762350702.git.aburgess@redhat.com>

Hi,

On 11/5/25 5:57 AM, Andrew Burgess wrote:
> In v4:
> 
>    - Updated based on Christina's feedback.
> 
>    - Removed excessive use of 'struct' throughout the patch.
> 
>    - Fixed whitespace issue in comment.
> 
>    - Renamed test to remove 'linux-', this is inline with all the other
>      Linux specific tests, which don't have 'linux' in their name.
> 
>    - Changed 'return -1' to 'return' in the test script.
> 
>    - Updated test to handle case where kernel produced core file
>      doesn't work, e.g. system is configured to not allow the kernel to
>      dump core.  Test will now report 'unsupported'.
> 
>    - Updated gdbserver changes so fetch_tls_area_register and
>      store_tls_area_register now return 'void'.  These functions have
>      been updated to give a warning if something goes wrong.
> 
>    - Rebased onto something more recent, reran the patch specific test
>      only as the changes above are all minor and shouldn't impact
>      anything outside of this change.

Thank you for these updates. I have tested this patch as thoroughly
as I am able, and you have fixed all the issues about which we have
spoken (privately).

I am quite a bit outside my comfort zone, so take my review with a
very large grain of salt.

Nonetheless, I've only detected one trivial matter that needs addressing.

Reviewed-By: Keith Seitz <keiths@redhat.com>

Keith

> diff --git a/gdb/testsuite/gdb.arch/i386-tls-regs.exp b/gdb/testsuite/gdb.arch/i386-tls-regs.exp
> new file mode 100644
> index 00000000000..1753f8762c6
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/i386-tls-regs.exp
> @@ -0,0 +1,335 @@
> +# Copyright 2025 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/>.
> +
> +# Check that the TLS GDT registers are available for i386 executable.
> +
> +require {is_any_target "i?86-*-linux*" "x86_64-*-linux*"}
> +
> +standard_testfile
> +
> +set options {debug pthreads}
> +if {![istarget "i386-*-*"]} {
> +    lappend options "additional_flags=-m32"
> +}
> +
> +# Check that we can actually compile a 32-bit executable.
> +#
> +# It is possible that even with the above setting of OPTIONS, we might
> +# still get a 64-bit executable, for example, running on x86-64 with
> +# '--target_board=unix/-m64' will add the -m64 after the above -m32,
> +# meaning we always end up with a 64-bit executable.
> +#
> +# If the following compiles then we are getting a 32-bit executable.
> +if {![gdb_can_simple_compile is_lp64_target {
> +	int dummy[sizeof (int) == 4
> +		  && sizeof (void *) == 4
> +		  && sizeof (long) == 4 ? 1 : -1];} \
> +	  object $options]} {
> +    unsupported "cannot compile 32-bit executable"
> +    return
> +}
> +
> +if { [build_executable "failed to prepare" $testfile $srcfile $options] } {
> +    return
> +}
> +
> +# Start an inferior and check we can read and modify the TLS registers.
> +proc_with_prefix test_tls_reg_availability {} {
> +    clean_restart $::testfile
> +
> +    if {![runto_main]} {
> +	return
> +    }
> +
> +    set tls_reg_vals { "" "" "" }
> +    gdb_test_multiple "info registers system" "check for TLS regs" {
> +	-re "^info registers system\r\n" {
> +	    exp_continue
> +	}
> +	-re "^i386_tls_gdt_(\\d) \\{($::hex), ($::hex), ($::hex), ($::hex)\\}\r\n" {
> +	    set idx $expect_out(1,string)
> +	    set val0 $expect_out(2,string)
> +	    set val1 $expect_out(3,string)
> +	    set val2 $expect_out(4,string)
> +	    set val3 $expect_out(5,string)
> +	    set val [list $val0 $val1 $val2 $val3]
> +	    set tls_reg_vals [lreplace $tls_reg_vals $idx $idx $val]
> +	    exp_continue
> +	}
> +	-re "^$::gdb_prompt $" {
> +	    gdb_assert {[lsearch -exact $tls_reg_vals ""] == -1} $gdb_test_name
> +	}
> +	-re "^\[^\r\n\]+\r\n" {
> +	    exp_continue
> +	}
> +    }
> +
> +    if { [lindex $tls_reg_vals 0] != [lindex $tls_reg_vals 1] } {
> +	set new_vals [lindex $tls_reg_vals 0]
> +	set old_vals [lindex $tls_reg_vals 1]
> +
> +	set val0 [lindex $old_vals 0]
> +	set val1 [lindex $new_vals 1]
> +	set val2 [lindex $new_vals 2]
> +	set val3 [lindex $new_vals 3]
> +
> +	set new_val_str "{$val0, $val1, $val2, $val3}"
> +
> +	gdb_test_no_output "set \$i386_tls_gdt_1 = $new_val_str"
> +	set re [string_to_regexp $new_val_str]
> +	gdb_test "print /x \$i386_tls_gdt_1" " = $re"
> +    }
> +
> +    gdb_test_no_output "set should_dump_core_p=0"
> +    gdb_test_no_output "set wait_for_gdb_p=0"
> +
> +    gdb_continue_to_end "" continue true
> +}
> +
> +# Start GDB using global BINFILE, load COREFILE (which must match
> +# BINFILE), and check that the core has two threads, that the TLS
> +# registers are visible in both threads, and that the TLS register
> +# values are different in each thread.
> +proc load_core_and_test_tls_regs { corefile } {
> +    clean_restart $::testfile
> +
> +    gdb_core_cmd $corefile "load corefile"
> +
> +    gdb_test "info threads" \
> +	[multi_line \
> +	     "\\*\\s+1\\s+Thread \[^\r\n\]+" \
> +	     "\\s+2\\s+Thread \[^\r\n\]+"] \
> +	"check for two threads"
> +
> +    # Record the TLS values in thread 1.
> +    set tls_reg_vals_thr_1 { "" "" "" }
> +    gdb_test_multiple "info registers system" "check for TLS regs thread 1" {
> +	-re "^info registers system\r\n" {
> +	    exp_continue
> +	}
> +	-re "^i386_tls_gdt_(\\d) (\\{$::hex, $::hex, $::hex, $::hex\\})\r\n" {
> +	    set idx $expect_out(1,string)
> +	    set val $expect_out(2,string)
> +	    set tls_reg_vals_thr_1 [lreplace $tls_reg_vals_thr_1 $idx $idx $val]
> +	    exp_continue
> +	}
> +	-re "^$::gdb_prompt $" {
> +	    gdb_assert {[lsearch -exact $tls_reg_vals_thr_1 ""] == -1} $gdb_test_name
> +	}
> +	-re "^\[^\r\n\]+\r\n" {
> +	    exp_continue
> +	}
> +    }
> +
> +    # Check a TLS variable in thread 1.
> +    gdb_test "print local_var" " = 1" \
> +	"check TLS variable in thread 1"
> +
> +    # Switch to thread 2 and confirm the values are different.
> +    gdb_test "thread 2"
> +
> +    set tls_reg_vals_thr_2 { "" "" "" }
> +    gdb_test_multiple "info registers system" "check for TLS regs thread 2" {
> +	-re "^info registers system\r\n" {
> +	    exp_continue
> +	}
> +	-re "^i386_tls_gdt_(\\d) (\\{$::hex, $::hex, $::hex, $::hex\\})\r\n" {
> +	    set idx $expect_out(1,string)
> +	    set val $expect_out(2,string)
> +	    set tls_reg_vals_thr_2 \
> +		[lreplace $tls_reg_vals_thr_2 $idx $idx $val]
> +	    exp_continue
> +	}
> +	-re "^$::gdb_prompt $" {
> +	    gdb_assert {[lsearch -exact $tls_reg_vals_thr_2 ""] == -1} \
> +		$gdb_test_name
> +	}
> +	-re "^\[^\r\n\]+\r\n" {
> +	    exp_continue
> +	}
> +    }
> +
> +    # Check a TLS variable in thread 2.
> +    gdb_test "print local_var" " = 2" \
> +	"check TLS variable in thread 2"
> +
> +    set all_same [expr [lindex $tls_reg_vals_thr_1 0] == [lindex $tls_reg_vals_thr_2 0] \
> +		      && [lindex $tls_reg_vals_thr_1 1] == [lindex $tls_reg_vals_thr_2 1] \
> +		      && [lindex $tls_reg_vals_thr_1 2] == [lindex $tls_reg_vals_thr_2 2]]

gdb.src/pre-commit.exp flags this line as a tclint violation of
unbraced-expr (the test fails):

https://wiki.tcl-lang.org/page/Brace+your+expr-essions

> +    gdb_assert {!$all_same} \
> +	"tls regs are different between threads"
> +}
> +
> +# Generate a core file using the gcore command.  Load it into GDB and
> +# check we can still read the TLS registers.
> +proc_with_prefix test_gcore_tls {} {
> +
> +    if {![gcore_cmd_available]} {
> +	unsupported "gcore command not available"
> +	return
> +    }
> +
> +    clean_restart $::testfile
> +
> +    if {![runto_main]} {
> +	return
> +    }
> +
> +    gdb_test_no_output "set should_dump_core_p=0"
> +
> +    gdb_breakpoint crash_func
> +    gdb_continue_to_breakpoint "stop at crash_func"
> +
> +    set corefile [standard_output_file ${::testfile}.gcore]
> +    if {![gdb_gcore_cmd $corefile "dump core"]} {
> +	return
> +    }
> +
> +    set readelf_program [gdb_find_readelf]
> +    set res [catch {exec $readelf_program -n $corefile} output]
> +    if { $res != 0 } {
> +	unresolved "unable to run readelf to check for TLS notes"
> +	return
> +    }
> +    set lines [split $output \n]
> +    set tls_count 0
> +    foreach line $lines {
> +	if {[regexp "^\\s+LINUX\\s+$::hex\\s+NT_386_TLS" $line]} {
> +	    incr tls_count
> +	}
> +    }
> +    gdb_assert {$tls_count == 2} \
> +	"expected number of TLS notes"
> +
> +    load_core_and_test_tls_regs $corefile
> +}
> +
> +# Generate a core file using the gcore command, but before doing so,
> +# clear all the TLS related GDT entries.  When the TLS GDT entries
> +# have a base address and limit of zero the kernel doesn't emit the
> +# NT_386_TLS note, GDB copies this behaviour.
> +proc_with_prefix test_gcore_no_tls {} {
> +
> +    if {![gcore_cmd_available]} {
> +	unsupported "gcore command not available"
> +	return
> +    }
> +
> +    clean_restart $::testfile
> +
> +    if {![runto_main]} {
> +	return
> +    }
> +
> +    gdb_test_no_output "set should_dump_core_p=0"
> +
> +    gdb_breakpoint crash_func
> +    gdb_continue_to_breakpoint "stop at crash_func"
> +
> +    # Clear the TLS registers in each thread.
> +    foreach_with_prefix thr { 1 2 } {
> +	gdb_test "thread $thr" ".*" \
> +	    "switch thread to clear tls regs"
> +	gdb_test_no_output "set \$i386_tls_gdt_0 = { 0x0, 0x0, 0x0, 0x28 }"
> +	gdb_test_no_output "set \$i386_tls_gdt_1 = { 0x0, 0x0, 0x0, 0x28 }"
> +	gdb_test_no_output "set \$i386_tls_gdt_2 = { 0x0, 0x0, 0x0, 0x28 }"
> +    }
> +
> +    set corefile [standard_output_file ${::testfile}.gcore]
> +    if {![gdb_gcore_cmd $corefile "dump core"]} {
> +	return
> +    }
> +
> +    # Look in the core file for NT_386_TLS entries.  There should be
> +    # none.
> +    set readelf_program [gdb_find_readelf]
> +    set res [catch {exec $readelf_program -n $corefile} output]
> +    if { $res != 0 } {
> +	unresolved "unable to run readelf to check for TLS notes"
> +	return
> +    }
> +    set lines [split $output \n]
> +    set tls_count 0
> +    foreach line $lines {
> +	if {[regexp "^\\s+LINUX\\s+$::hex\\s+NT_386_TLS" $line]} {
> +	    incr tls_count
> +	}
> +    }
> +    gdb_assert {$tls_count == 0} \
> +	"expected number of TLS notes"
> +
> +    # Restart GDB and load the core file.  As there are no NT_386_TLS
> +    # entries the TLS registers should show as unavailable.
> +    clean_restart $::testfile
> +
> +    gdb_core_cmd $corefile "load corefile"
> +
> +    gdb_test "info threads" \
> +	[multi_line \
> +	     "\\*\\s+1\\s+Thread \[^\r\n\]+" \
> +	     "\\s+2\\s+Thread \[^\r\n\]+"] \
> +	"check for two threads"
> +
> +    foreach_with_prefix thr { 1 2 } {
> +	set unavailable_tls_count 0
> +	set valid_tls_count 0
> +	gdb_test "thread $thr" ".*" \
> +	    "switch thread to check TLS register status"
> +	gdb_test_multiple "info registers system" "check TLS reg values" {
> +	    -re "^info registers system\r\n" {
> +		exp_continue
> +	    }
> +	    -re "^i386_tls_gdt_\\d \\{<unavailable>, <unavailable>, <unavailable>, <unavailable>\\}\r\n" {
> +		incr unavailable_tls_count
> +		exp_continue
> +	    }
> +	    -re "^i386_tls_gdt_\\d \[^\r\n\]+\r\n" {
> +		incr valid_tls_count
> +		exp_continue
> +	    }
> +
> +	    -re "^$::gdb_prompt $" {
> +		gdb_assert {$valid_tls_count == 0 && \
> +				$unavailable_tls_count == 3} \
> +		    $gdb_test_name
> +	    }
> +	    -re "^\[^\r\n\]+\r\n" {
> +		exp_continue
> +	    }
> +	}
> +
> +	# Check a TLS variable in this thread.
> +	gdb_test "print local_var" " = $thr" \
> +	    "check TLS variable in thread $thr"
> +    }
> +}
> +
> +# Generate a native core file.  Load it into GDB and check the TLS
> +# registers can be read.
> +proc_with_prefix test_native_core {} {
> +    set corefile [core_find $::binfile]
> +    if { $corefile eq "" } {
> +	unsupported "unable to generate core file"
> +	return
> +    }
> +
> +    load_core_and_test_tls_regs $corefile
> +}
> +
> +# Run the tests.
> +test_tls_reg_availability
> +test_gcore_tls
> +test_gcore_no_tls
> +test_native_core


  reply	other threads:[~2025-11-06 21:24 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-02 11:22 [PATCH] " Andrew Burgess
2025-09-23 17:31 ` Andrew Burgess
2025-09-23 17:33   ` [PATCHv2] " Andrew Burgess
2025-10-14 13:54     ` [PATCHv3] " Andrew Burgess
2025-10-14 14:12       ` Eli Zaretskii
2025-10-29  9:49       ` Schimpe, Christina
2025-11-05 13:57       ` [PATCHv4] " Andrew Burgess
2025-11-06 21:20         ` Keith Seitz [this message]
2025-11-12  9:44         ` Schimpe, Christina
2025-11-13 19:35           ` Andrew Burgess
2025-11-14  9:37             ` Schimpe, Christina
2025-11-20 17:19         ` Andrew Burgess
2025-09-23 19:41   ` [PATCH] " Eli Zaretskii
2025-09-23 20:19     ` Andrew Burgess

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=83120a5b-3448-421b-9ac5-8d1c12ed2fa6@redhat.com \
    --to=keiths@redhat.com \
    --cc=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox