]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Implement native TLS support on Windows
authorHannes Domani <ssbssa@yahoo.de>
Thu, 7 May 2026 18:54:54 +0000 (20:54 +0200)
committerHannes Domani <ssbssa@yahoo.de>
Sat, 23 May 2026 09:05:11 +0000 (11:05 +0200)
GCC 16 introduced native TLS variables on Windows, so this adds
debugger support for them.

The fetch_tls_load_module_address gdbarch method is used to get the
address of _tls_index of the OBJFILE, which is then forwarded as LM_ADDR
to windows_get_thread_local_address.

The TLS slot for a module can be found in
TIB->thread_local_storage[_tls_index].

Approved-By: Tom Tromey <tom@tromey.com>
gdb/NEWS
gdb/windows-tdep.c

index 48a80856aa15d90d0540e9198837ab9ca7fe07ea..7c8cf9af4c2d2e9e05b2dd2709d10ff4893b471a 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -81,6 +81,8 @@
 * The Windows native target now supports non-stop mode.  This feature
   requires Windows 10 or later.
 
+* Support for native Thread Local Storage (TLS) variables on Windows.
+
 * Configure changes
 
 ** --with-babeltrace has been removed.  The babeltrace library was
index 38ee1d7275e8c16592342b9c16f40a6635edb2d6..78bf49b9c81f4e02304a3e62c1425e474c070dd6 100644 (file)
@@ -954,6 +954,73 @@ windows_init_abi_common (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_get_siginfo_type (gdbarch, windows_get_siginfo_type);
 }
 
+/* Implement the fetch_tls_load_module_address gdbarch method.
+   Usually this method returns an address representing a load module, but this
+   doesn't exist on Windows.  Instead it returns the address of the
+   "_tls_index" variable of OBJFILE, which is then forwarded as LM_ADDR
+   in windows_get_thread_local_address below.  */
+
+static CORE_ADDR
+windows_tls_index_address (struct objfile *objfile)
+{
+  bound_minimal_symbol minsym
+    = lookup_minimal_symbol_linkage ("_tls_index", objfile, false);
+  if (minsym.minsym == nullptr)
+    throw_error (TLS_GENERIC_ERROR, _("Cannot find address of _tls_index"));
+
+  return minsym.value_address ();
+}
+
+/* Implement the get_thread_local_address gdbarch method.
+   Each module (with TLS variables) gets its own TLS slot represented by
+   _tls_index, which can be found in TIB->thread_local_storage[_tls_index].
+   The address of _tls_index is provided by the LM_ADDR argument.  */
+
+static CORE_ADDR
+windows_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
+                                 CORE_ADDR lm_addr, CORE_ADDR offset)
+{
+  int ptr_bytes;
+  int tls_offset; /* Offset of thread_local_storage in TIB.  */
+  if (gdbarch_ptr_bit (gdbarch) == 32)
+    {
+      ptr_bytes = 4;
+      tls_offset = 44;
+    }
+  else
+    {
+      ptr_bytes = 8;
+      tls_offset = 88;
+    }
+
+  gdb_byte buf[8];
+  if (target_read_memory (lm_addr, buf, 4))
+    throw_error (TLS_GENERIC_ERROR, _("Cannot read _tls_index"));
+
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  uint32_t tls_index = extract_unsigned_integer (buf, 4, byte_order);
+
+  CORE_ADDR tlb;
+  if (!target_get_tib_address (ptid, &tlb))
+    throw_error (TLS_GENERIC_ERROR, _("Cannot get tib address"));
+
+  if (target_read_memory (tlb + tls_offset, buf, ptr_bytes))
+    throw_error (TLS_GENERIC_ERROR, _("Cannot read thread_local_storage"));
+
+  CORE_ADDR tls_ptr = extract_unsigned_integer (buf, ptr_bytes, byte_order);
+  if (tls_ptr == 0)
+    throw_error (TLS_NOT_ALLOCATED_YET_ERROR, _("TLS not allocated yet"));
+
+  if (target_read_memory (tls_ptr + tls_index * ptr_bytes, buf, ptr_bytes))
+    throw_error (TLS_GENERIC_ERROR, _("Cannot read TLS slot"));
+
+  CORE_ADDR slot_ptr = extract_unsigned_integer (buf, ptr_bytes, byte_order);
+  if (slot_ptr == 0)
+    throw_error (TLS_NOT_ALLOCATED_YET_ERROR, _("TLS slot not allocated yet"));
+
+  return slot_ptr + offset;
+}
+
 /* See windows-tdep.h.  */
 void
 windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
@@ -963,6 +1030,12 @@ windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   /* On Windows, "long"s are only 32bit.  */
   set_gdbarch_long_bit (gdbarch, 32);
+
+  /* Enable TLS support.  */
+  set_gdbarch_fetch_tls_load_module_address (gdbarch,
+                                            windows_tls_index_address);
+  set_gdbarch_get_thread_local_address (gdbarch,
+                                       windows_get_thread_local_address);
 }
 
 /* See windows-tdep.h.  */