get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2195605/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2195605,
    "url": "http://patchwork.ozlabs.org/api/patches/2195605/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/glibc/patch/20260211135944.2066869-2-fberat@redhat.com/",
    "project": {
        "id": 41,
        "url": "http://patchwork.ozlabs.org/api/projects/41/?format=api",
        "name": "GNU C Library",
        "link_name": "glibc",
        "list_id": "libc-alpha.sourceware.org",
        "list_email": "libc-alpha@sourceware.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260211135944.2066869-2-fberat@redhat.com>",
    "list_archive_url": null,
    "date": "2026-02-11T13:59:43",
    "name": "[v4,1/2] elf(tls): Add debug logging for TLS operations",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "ad14a5704ea0abf301117ca9a8ed9a44f9c8aaa3",
    "submitter": {
        "id": 84672,
        "url": "http://patchwork.ozlabs.org/api/people/84672/?format=api",
        "name": "Frédéric Bérat",
        "email": "fberat@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/glibc/patch/20260211135944.2066869-2-fberat@redhat.com/mbox/",
    "series": [
        {
            "id": 491846,
            "url": "http://patchwork.ozlabs.org/api/series/491846/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/glibc/list/?series=491846",
            "date": "2026-02-11T13:59:44",
            "name": "Enhancing LD_DEBUG with TLS logging and category exclusion support",
            "version": 4,
            "mbox": "http://patchwork.ozlabs.org/series/491846/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2195605/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2195605/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "libc-alpha@sourceware.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@legolas.ozlabs.org",
            "libc-alpha@sourceware.org"
        ],
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=TgOzyHiC;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org;\n receiver=patchwork.ozlabs.org)",
            "sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=TgOzyHiC",
            "sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com",
            "sourceware.org; spf=pass smtp.mailfrom=redhat.com",
            "server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.129.124"
        ],
        "Received": [
            "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fB0Sz56Kyz1xpY\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 12 Feb 2026 01:00:51 +1100 (AEDT)",
            "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id AD9F44BA2E14\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 11 Feb 2026 14:00:49 +0000 (GMT)",
            "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id B415C4BA2E10\n for <libc-alpha@sourceware.org>; Wed, 11 Feb 2026 13:59:58 +0000 (GMT)",
            "from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-21-4XNzhIdFPGaPA5kf8gJFKg-1; Wed,\n 11 Feb 2026 08:59:55 -0500",
            "from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 1F87C195605F; Wed, 11 Feb 2026 13:59:54 +0000 (UTC)",
            "from Nymeria-redhat.redhat.com (unknown [10.44.33.163])\n by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with\n ESMTPS\n id 5C4E7180066F; Wed, 11 Feb 2026 13:59:52 +0000 (UTC)"
        ],
        "DKIM-Filter": [
            "OpenDKIM Filter v2.11.0 sourceware.org AD9F44BA2E14",
            "OpenDKIM Filter v2.11.0 sourceware.org B415C4BA2E10"
        ],
        "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org B415C4BA2E10",
        "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org B415C4BA2E10",
        "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1770818403; cv=none;\n b=CbtkzSD0KjRoWfGBhp7UnC4KBeE7BT5f5p/gHUxm8SupDujUTcCOp/Rnkok3E3IpsyO0TeFOBVNaFP8GwI09KoUZvc40Mq+x7ImLDYU9OOws7NiaGelTdLh9ntF9sEoGTo0xFkG8PgyaV5+2MYPH2G8X152WkvwEEpJt6/2IMcM=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1770818403; c=relaxed/simple;\n bh=e017FjF9fvCUxOdrHC421dWSWKdImTz3GbJbyZAtsAY=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=OOhPw5IROUkLEimGpybP0l6daNtnQ0OBreGZmZ8wixeBGSun583Jz+TDHUBT5w/C46+O1ps+clBVcwa8t2o3mcxZQIDz79ssbfWWzSId9MCxntcB2uGbQRGmqy5MWDwIBDENbChz907BotqJzogNXi7uTFV5iWSZhKDaoTeYu7A=",
        "ARC-Authentication-Results": "i=1; server2.sourceware.org",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1770818398;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=HV61zqFNiBgswjx25mqFtNs+dz6b8LUr0BdfBT6IoTM=;\n b=TgOzyHiCzcMyFfSt+HC9sfqYEh0ARSMoCGty7Wwtm+PH3I6eeNlRqG6ED881UYd3uvu2Pv\n NW3DTm1QjTkJYpObWlRklcWEsFArN/UfjQUa55tNBOXzmR6yk1+njKRMPTH1i41aD3x/92\n EqMnwAPvMoCDBuFbo3T3b0oMUUcBvNI=",
        "X-MC-Unique": "4XNzhIdFPGaPA5kf8gJFKg-1",
        "X-Mimecast-MFC-AGG-ID": "4XNzhIdFPGaPA5kf8gJFKg_1770818394",
        "From": "=?utf-8?b?RnLDqWTDqXJpYyBCw6lyYXQ=?= <fberat@redhat.com>",
        "To": "libc-alpha@sourceware.org, fweimer@redhat.com,\n adhemerval.zanella@linaro.org",
        "Subject": "[PATCH v4 1/2] elf(tls): Add debug logging for TLS operations",
        "Date": "Wed, 11 Feb 2026 14:59:43 +0100",
        "Message-ID": "<20260211135944.2066869-2-fberat@redhat.com>",
        "In-Reply-To": "<20260211135944.2066869-1-fberat@redhat.com>",
        "References": "<20260211135944.2066869-1-fberat@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.93",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-MFC-PROC-ID": "5cto0I1zGpMMtakttRtHUrUQP-7h1LOAtYs6SEmO6Yw_1770818394",
        "X-Mimecast-Originator": "redhat.com",
        "Content-Transfer-Encoding": "8bit",
        "content-type": "text/plain; charset=\"US-ASCII\"; x-default=true",
        "X-BeenThere": "libc-alpha@sourceware.org",
        "X-Mailman-Version": "2.1.30",
        "Precedence": "list",
        "List-Id": "Libc-alpha mailing list <libc-alpha.sourceware.org>",
        "List-Unsubscribe": "<https://sourceware.org/mailman/options/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=unsubscribe>",
        "List-Archive": "<https://sourceware.org/pipermail/libc-alpha/>",
        "List-Post": "<mailto:libc-alpha@sourceware.org>",
        "List-Help": "<mailto:libc-alpha-request@sourceware.org?subject=help>",
        "List-Subscribe": "<https://sourceware.org/mailman/listinfo/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=subscribe>",
        "Errors-To": "libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org"
    },
    "content": "This commit introduces extensive debug logging for thread-local storage\n(TLS) operations within the dynamic linker. When `LD_DEBUG=tls` is\nenabled, messages are printed for:\n- TLS module assignment and release.\n- DTV (Dynamic Thread Vector) resizing events.\n- TLS block allocations and deallocations.\n- `__tls_get_addr` slow path events (DTV updates, lazy allocations, and\n  static TLS usage).\n\nThe log format is standardized to use a \"tls: \" prefix and identifies\nmodules using the \"modid %lu\" convention. To aid in debugging\nmultithreaded applications, thread-specific logs include the Thread\nControl Block (TCB) address to identify the context of the operation.\n\nA new test module `tst-tls-debug-mod.c` and a corresponding shell script\n`tst-tls-debug-recursive.sh` have been added. Additionally, the existing\n`tst-dl-debug-tid` NPTL test has been updated to verify these TLS debug\nmessages in a multithreaded context.\n---\nv4:\n- Replace __func__ prefix with \"tls: \" to provide more meaningful\n  context.\n- Clarify TLS log messages (e.g., \"TLS initialized\") to avoid ambiguity.\n- Remove TCB information from global events (modid assign/release).\n- Fix Lmid_t printing to use %ld (signed long).\n- Add missing glibc headers and descriptive comments to new test files.\n- Update tst-tls-debug-recursive.sh and tst-dl-debug-tid.sh to match the\n  new format.\n\n elf/Makefile                   | 15 ++++++\n elf/dl-close.c                 |  5 ++\n elf/dl-tls.c                   | 83 +++++++++++++++++++++++++++++-----\n elf/rtld.c                     |  5 ++\n elf/tst-tls-debug-recursive.sh | 83 ++++++++++++++++++++++++++++++++++\n nptl/Makefile                  |  5 +-\n nptl/allocatestack.c           | 10 ++--\n nptl/nptl-stack.c              |  6 +--\n nptl/pthread_create.c          |  2 +-\n nptl/tst-dl-debug-tid.c        | 13 ++++++\n nptl/tst-dl-debug-tid.sh       | 33 +++++++++++---\n nptl/tst-tls-debug-mod.c       | 26 +++++++++++\n sysdeps/x86_64/dl-tls.c        | 33 ++++++++++++--\n 13 files changed, 288 insertions(+), 31 deletions(-)\n create mode 100755 elf/tst-tls-debug-recursive.sh\n create mode 100644 nptl/tst-tls-debug-mod.c\n\n\nbase-commit: 60a3b44f603f1410a6fd2a63f96da65095269bad",
    "diff": "diff --git a/elf/Makefile b/elf/Makefile\nindex 396e97b5e7..9d4dfcf4ae 100644\n--- a/elf/Makefile\n+++ b/elf/Makefile\n@@ -3539,3 +3539,18 @@ $(objpfx)tst-origin.out: tst-origin.sh $(objpfx)tst-origin\n \t$(evaluate-test)\n \n $(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so\n+\n+\n+ifeq ($(run-built-tests),yes)\n+tests-special += $(objpfx)tst-tls-debug-recursive.out\n+\n+$(objpfx)tst-tls-debug-recursive.out: tst-tls-debug-recursive.sh \\\n+\t\t\t      $(objpfx)tst-recursive-tls \\\n+\t\t\t      $(objpfx)tst-recursive-tlsmallocmod.so \\\n+\t\t\t      $(patsubst %,$(objpfx)tst-recursive-tlsmod%.so, \\\n+\t\t\t\t0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)\n+\t$(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' \\\n+\t\t '$(rtld-prefix)' '$(run_program_env)' \\\n+\t\t $(objpfx)tst-recursive-tls > $@; \\\n+\t$(evaluate-test)\n+endif\ndiff --git a/elf/dl-close.c b/elf/dl-close.c\nindex fca877534e..92bce07c7a 100644\n--- a/elf/dl-close.c\n+++ b/elf/dl-close.c\n@@ -74,6 +74,11 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,\n       if (__glibc_likely (old_map != NULL))\n \t{\n \t  /* Mark the entry as unused.  These can be read concurrently.  */\n+\t  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+\t    _dl_debug_printf (\n+\t\t\"tls: release modid %lu from %s [%ld]\\n\",\n+\t\t(unsigned long int) idx, DSO_FILENAME (old_map->l_name),\n+\t\t(long int) old_map->l_ns);\n \t  atomic_store_relaxed (&listp->slotinfo[idx - disp].gen,\n \t\t\t\tGL(dl_tls_generation) + 1);\n \t  atomic_store_relaxed (&listp->slotinfo[idx - disp].map, NULL);\ndiff --git a/elf/dl-tls.c b/elf/dl-tls.c\nindex 8cef809261..5bfcb184ed 100644\n--- a/elf/dl-tls.c\n+++ b/elf/dl-tls.c\n@@ -220,6 +220,12 @@ _dl_assign_tls_modid (struct link_map *l)\n     }\n \n   l->l_tls_modid = result;\n+\n+  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+    _dl_debug_printf (\"tls: assign modid %lu to %s [%ld]\\n\",\n+\t\t      (unsigned long int) result,\n+\t\t      DSO_FILENAME (l->l_name),\n+\t\t      (long int) l->l_ns);\n }\n \n \n@@ -538,7 +544,7 @@ _dl_allocate_tls_storage (void)\n   if (result == NULL)\n     free (allocated);\n   else if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n-    _dl_debug_printf (\"TCB allocated: 0x%lx\\n\", (unsigned long int) result);\n+    _dl_debug_printf (\"tls: allocate TCB 0x%lx\\n\", (unsigned long int) result);\n \n   _dl_tls_allocate_end ();\n   return result;\n@@ -551,13 +557,18 @@ extern dtv_t _dl_static_dtv[];\n #endif\n \n static dtv_t *\n-_dl_resize_dtv (dtv_t *dtv, size_t max_modid)\n+_dl_resize_dtv (dtv_t *dtv, size_t max_modid, void *tcb)\n {\n   /* Resize the dtv.  */\n   dtv_t *newp;\n   size_t newsize = max_modid + DTV_SURPLUS;\n   size_t oldsize = dtv[-1].counter;\n \n+  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+    _dl_debug_printf (\"tls: DTV resized for TCB 0x%lx: oldsize=%lu, newsize=%lu\\n\",\n+\t\t      (unsigned long int) tcb,\n+\t\t      (unsigned long int) oldsize, (unsigned long int) newsize);\n+\n   _dl_tls_allocate_begin ();\n   if (dtv == GL(dl_initial_dtv))\n     {\n@@ -626,7 +637,7 @@ _dl_allocate_tls_init (void *result, bool main_thread)\n   if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))\n     {\n       /* Resize the dtv.  */\n-      dtv = _dl_resize_dtv (dtv, GL(dl_tls_max_dtv_idx));\n+      dtv = _dl_resize_dtv (dtv, GL(dl_tls_max_dtv_idx), result);\n \n       /* Install this new dtv in the thread data structures.  */\n       INSTALL_DTV (result, &dtv[-1]);\n@@ -717,9 +728,14 @@ rtld_hidden_def (_dl_allocate_tls_init)\n void *\n _dl_allocate_tls (void *mem)\n {\n-  return _dl_allocate_tls_init (mem == NULL\n-\t\t\t\t? _dl_allocate_tls_storage ()\n-\t\t\t\t: allocate_dtv (mem), false);\n+  void *result = _dl_allocate_tls_init (mem == NULL\n+\t\t\t\t\t? _dl_allocate_tls_storage ()\n+\t\t\t\t\t: allocate_dtv (mem), false);\n+  if (__glibc_unlikely (result != NULL\n+\t\t\t&& (GLRO (dl_debug_mask) & DL_DEBUG_TLS)))\n+    _dl_debug_printf (\"tls: TLS initialized for TCB 0x%lx\\n\",\n+\t\t      (unsigned long int) result);\n+  return result;\n }\n rtld_hidden_def (_dl_allocate_tls)\n \n@@ -728,14 +744,22 @@ void\n _dl_deallocate_tls (void *tcb, bool dealloc_tcb)\n {\n   if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n-    _dl_debug_printf (\"TCB deallocating: 0x%lx (dealloc_tcb=%d)\\n\",\n+    _dl_debug_printf (\"tls: deallocate TCB 0x%lx (dealloc_tcb=%d)\\n\",\n \t\t      (unsigned long int) tcb, dealloc_tcb);\n \n   dtv_t *dtv = GET_DTV (tcb);\n \n   /* We need to free the memory allocated for non-static TLS.  */\n   for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)\n-    free (dtv[1 + cnt].pointer.to_free);\n+    {\n+      if (dtv[1 + cnt].pointer.to_free != NULL\n+\t  && __glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+\t_dl_debug_printf (\n+\t    \"tls: deallocate block 0x%lx for modid %lu; TCB=0x%lx\\n\",\n+\t    (unsigned long int) dtv[1 + cnt].pointer.to_free,\n+\t    (unsigned long int) (1 + cnt), (unsigned long int) tcb);\n+      free (dtv[1 + cnt].pointer.to_free);\n+    }\n \n   /* The array starts with dtv[-1].  */\n   if (dtv != GL(dl_initial_dtv))\n@@ -790,6 +814,12 @@ allocate_and_init (struct link_map *map)\n     (map->l_tls_align, map->l_tls_blocksize);\n   if (result.val == NULL)\n     oom ();\n+  else if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+    _dl_debug_printf (\"tls: allocate block 0x%lx for modid %lu; size=%lu, TCB=0x%lx\\n\",\n+\t\t      (unsigned long int) result.to_free,\n+\t\t      (unsigned long int) map->l_tls_modid,\n+\t\t      (unsigned long int) map->l_tls_blocksize,\n+\t\t      (unsigned long int) THREAD_SELF);\n \n   /* Initialize the memory.  */\n   memset (__mempcpy (result.val, map->l_tls_initimage,\n@@ -891,7 +921,7 @@ _dl_update_slotinfo (unsigned long int req_modid, size_t new_gen)\n \t\t    continue;\n \n \t\t  /* Resizing the dtv aborts on failure: bug 16134.  */\n-\t\t  dtv = _dl_resize_dtv (dtv, max_modid);\n+\t\t  dtv = _dl_resize_dtv (dtv, max_modid, THREAD_SELF);\n \n \t\t  assert (modid <= dtv[-1].counter);\n \n@@ -912,6 +942,12 @@ _dl_update_slotinfo (unsigned long int req_modid, size_t new_gen)\n \t\t least some dynamic TLS usage by interposed mallocs.  */\n \t      if (dtv[modid].pointer.to_free != NULL)\n \t\t{\n+\t\t  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+\t\t    _dl_debug_printf (\n+\t\t\t\"tls: DTV update for TCB 0x%lx: modid %lu deallocated block 0x%lx\\n\",\n+\t\t\t(unsigned long int) THREAD_SELF,\n+\t\t\t(unsigned long int) modid,\n+\t\t\t(unsigned long int) dtv[modid].pointer.to_free);\n \t\t  _dl_tls_allocate_begin ();\n \t\t  free (dtv[modid].pointer.to_free);\n \t\t  _dl_tls_allocate_end ();\n@@ -1004,6 +1040,11 @@ tls_get_addr_tail (tls_index *ti, dtv_t *dtv, struct link_map *the_map)\n \t  dtv[ti->ti_module].pointer.to_free = NULL;\n \t  dtv[ti->ti_module].pointer.val = p;\n \n+\t  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+\t    _dl_debug_printf (\"tls: modid %lu using static TLS; TCB=0x%lx\\n\",\n+\t\t\t      (unsigned long int) ti->ti_module,\n+\t\t\t      (unsigned long int) THREAD_SELF);\n+\n \t  return tls_get_addr_adjust (p, ti);\n \t}\n       else\n@@ -1059,18 +1100,28 @@ __tls_get_addr (tls_index *ti)\n     {\n       if (_dl_tls_allocate_active ()\n \t  && ti->ti_module < _dl_tls_initial_modid_limit)\n+\t{\n \t  /* This is a reentrant __tls_get_addr call, but we can\n \t     satisfy it because it's an initially-loaded module ID.\n \t     These TLS slotinfo slots do not change, so the\n \t     out-of-date generation counter does not matter.  However,\n \t     if not in a TLS update, still update_get_addr below, to\n \t     get off the slow path eventually.  */\n-\t;\n+\t  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+\t    _dl_debug_printf (\"tls: modid %lu reentrant usage; TCB=0x%lx\\n\",\n+\t\t\t      (unsigned long int) ti->ti_module,\n+\t\t\t      (unsigned long int) THREAD_SELF);\n+\t}\n       else\n \t{\n \t  /* Update DTV up to the global generation, see CONCURRENCY NOTES\n \t     in _dl_update_slotinfo.  */\n \t  gen = atomic_load_acquire (&GL(dl_tls_generation));\n+\t  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+\t    _dl_debug_printf (\n+\t\t\"tls: modid %lu update DTV to generation %lu; TCB=0x%lx\\n\",\n+\t\t(unsigned long int) ti->ti_module, (unsigned long int) gen,\n+\t\t(unsigned long int) THREAD_SELF);\n \t  return update_get_addr (ti, gen);\n \t}\n     }\n@@ -1078,7 +1129,13 @@ __tls_get_addr (tls_index *ti)\n   void *p = dtv[ti->ti_module].pointer.val;\n \n   if (__glibc_unlikely (p == TLS_DTV_UNALLOCATED))\n-    return tls_get_addr_tail (ti, dtv, NULL);\n+    {\n+      if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+\t_dl_debug_printf (\"tls: modid %lu lazy allocation; TCB=0x%lx\\n\",\n+\t\t\t  (unsigned long int) ti->ti_module,\n+\t\t\t  (unsigned long int) THREAD_SELF);\n+      return tls_get_addr_tail (ti, dtv, NULL);\n+    }\n \n   return tls_get_addr_adjust (p, ti);\n }\n@@ -1149,6 +1206,10 @@ _dl_tls_initial_modid_limit_setup (void)\n \tbreak;\n     }\n   _dl_tls_initial_modid_limit = idx;\n+\n+  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+    _dl_debug_printf (\"tls: initial modid limit set to %lu\\n\",\n+\t\t      (unsigned long int) idx);\n }\n \n \ndiff --git a/elf/rtld.c b/elf/rtld.c\nindex 29e7a4ddfa..1fc32ebefa 100644\n--- a/elf/rtld.c\n+++ b/elf/rtld.c\n@@ -1192,6 +1192,11 @@ rtld_setup_main_map (struct link_map *main_map)\n \n \t    /* This image gets the ID one.  */\n \t    GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;\n+\t    if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+\t      _dl_debug_printf (\"tls: assign modid %lu to %s [%ld]\\n\",\n+\t\t\t\t(unsigned long int) main_map->l_tls_modid,\n+\t\t\t\tDSO_FILENAME (main_map->l_name),\n+\t\t\t\t(long int) main_map->l_ns);\n \t  }\n \tbreak;\n \ndiff --git a/elf/tst-tls-debug-recursive.sh b/elf/tst-tls-debug-recursive.sh\nnew file mode 100755\nindex 0000000000..083e716f72\n--- /dev/null\n+++ b/elf/tst-tls-debug-recursive.sh\n@@ -0,0 +1,83 @@\n+#!/bin/sh\n+# Test for TLS logging in dynamic linker.\n+# Copyright (C) 2026 Free Software Foundation, Inc.\n+# This file is part of the GNU C Library.\n+#\n+# The GNU C Library is free software; you can redistribute it and/or\n+# modify it under the terms of the GNU Lesser General Public\n+# License as published by the Free Software Foundation; either\n+# version 2.1 of the License, or (at your option) any later version.\n+#\n+# The GNU C Library is distributed in the hope that it will be useful,\n+# but WITHOUT ANY WARRANTY; without even the implied warranty of\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+# Lesser General Public License for more details.\n+#\n+# You should have received a copy of the GNU Lesser General Public\n+# License along with the GNU C Library; if not, see\n+# <https://www.gnu.org/licenses/>.\n+\n+# This script runs the tst-tls-debug-recursive test case and verifies its\n+# LD_DEBUG=tls output. It checks for various TLS-related messages\n+# to ensure the dynamic linker's TLS logging is working correctly.\n+\n+set -e\n+common_objpfx=\"$1\"\n+test_wrapper_env=\"$2\"\n+rtld_prefix=\"$3\"\n+run_program_env=\"$4\"\n+test_program=\"$5\"\n+\n+debug_output=\"${common_objpfx}elf/tst-tls-debug-recursive.debug\"\n+rm -f \"${debug_output}\".*\n+\n+# Run the test program with LD_DEBUG=tls.\n+eval \"${test_wrapper_env}\" LD_DEBUG=tls LD_DEBUG_OUTPUT=\"${debug_output}\" \\\n+    \"${rtld_prefix}\" \"${test_program}\"\n+\n+debug_output=$(ls \"${debug_output}\".*)\n+\n+fail=0\n+\n+# Check for expected messages\n+if ! grep -q 'tls: DTV resized for TCB 0x.*: oldsize' \"${debug_output}\"; then\n+  echo \"FAIL: DTV resized message not found\"\n+  fail=1\n+fi\n+\n+if ! grep -q 'tls: DTV update for TCB 0x.*: modid .* deallocated block' \"${debug_output}\"; then\n+  echo \"FAIL: module deallocated during DTV update message not found\"\n+  fail=1\n+fi\n+\n+if ! grep -q 'tls: assign modid .* to' \"${debug_output}\"; then\n+  echo \"FAIL: module assigned message not found\"\n+  fail=1\n+fi\n+\n+if ! grep -q 'tls: allocate block .* for modid .* size=.*, TCB=0x' \"${debug_output}\"; then\n+  echo \"FAIL: module allocated message not found\"\n+  fail=1\n+fi\n+\n+if ! grep -q 'tls: modid .* update DTV to generation .* TCB=0x' \"${debug_output}\"; then\n+  echo \"FAIL: update DTV message not found\"\n+  fail=1\n+fi\n+\n+if ! grep -q 'tls: initial modid limit set to' \"${debug_output}\"; then\n+  echo \"FAIL: initial modid limit message not found\"\n+  fail=1\n+fi\n+\n+if [ $fail -ne 0 ]; then\n+  echo \"Test FAILED\"\n+  cat \"${debug_output}\"\n+  rm -f \"${debug_output}\"\n+  exit 1\n+fi\n+\n+echo \"Test PASSED\"\n+cat \"${debug_output}\"\n+rm -f \"${debug_output}\"\n+exit 0\ndiff --git a/nptl/Makefile b/nptl/Makefile\nindex 08b8ba8a31..85f95dd0cf 100644\n--- a/nptl/Makefile\n+++ b/nptl/Makefile\n@@ -266,6 +266,7 @@ CFLAGS-tst-thread-exit-clobber.o = -std=gnu++11\n LDLIBS-tst-thread-exit-clobber = -lstdc++\n CFLAGS-tst-minstack-throw.o = -std=gnu++11\n LDLIBS-tst-minstack-throw = -lstdc++\n+LDLIBS-tst-dl-debug-tid = $(libdl)\n \n tests = \\\n   tst-attr2 \\\n@@ -485,6 +486,7 @@ modules-names = \\\n   tst-audit-threads-mod2 \\\n   tst-compat-forwarder-mod \\\n   tst-stack4mod \\\n+  tst-tls-debug-mod \\\n   tst-tls3mod \\\n   tst-tls5mod \\\n   tst-tls5moda \\\n@@ -710,7 +712,8 @@ tst-stackguard1-ARGS = --command \"$(host-test-program-cmd) --child\"\n tst-stackguard1-static-ARGS = --command \"$(objpfx)tst-stackguard1-static --child\"\n \n ifeq ($(run-built-tests),yes)\n-$(objpfx)tst-dl-debug-tid.out: tst-dl-debug-tid.sh $(objpfx)tst-dl-debug-tid\n+$(objpfx)tst-dl-debug-tid.out: tst-dl-debug-tid.sh $(objpfx)tst-dl-debug-tid \\\n+\t\t\t $(objpfx)tst-tls-debug-mod.so\n \t$(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' '$(rtld-prefix)' \\\n \t  '$(run-program-env)' \\\n \t  $(objpfx)tst-dl-debug-tid > $@; $(evaluate-test)\ndiff --git a/nptl/allocatestack.c b/nptl/allocatestack.c\nindex d3a9dbd3d2..b2ecb00113 100644\n--- a/nptl/allocatestack.c\n+++ b/nptl/allocatestack.c\n@@ -117,7 +117,7 @@ get_cached_stack (size_t *sizep, void **memp)\n   lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);\n \n   if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n-    GLRO (dl_debug_printf) (\"TLS TCB reused from cache: 0x%lx\\n\",\n+    GLRO (dl_debug_printf) (\"tls: TCB reused from cache: 0x%lx\\n\",\n \t\t\t    (unsigned long int) result);\n \n   /* Report size and location of the stack to the caller.  */\n@@ -436,9 +436,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,\n \n       if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n \tGLRO (dl_debug_printf) (\n-\t  \"TCB for user-supplied stack created: 0x%lx, stack=0x%lx, size=%lu\\n\",\n-\t  (unsigned long int) pd, (unsigned long int) pd->stackblock,\n-\t  (unsigned long int) pd->stackblock_size);\n+\t  \"tls: TCB created (user-supplied stack); stack=0x%lx, size=%lu, TCB=0x%lx\\n\",\n+\t  (unsigned long int) pd->stackblock,\n+\t  (unsigned long int) pd->stackblock_size, (unsigned long int) pd);\n \n       /* This is at least the second thread.  */\n       pd->header.multiple_threads = 1;\n@@ -561,7 +561,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,\n \t  pd->setxid_futex = -1;\n \n \t  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n-\t    GLRO (dl_debug_printf) (\"TCB for new stack allocated: 0x%lx\\n\",\n+\t    GLRO (dl_debug_printf) (\"tls: TCB allocated (new stack): 0x%lx\\n\",\n \t\t\t\t    (unsigned long int) pd);\n \n \t  /* Allocate the DTV for this thread.  */\ndiff --git a/nptl/nptl-stack.c b/nptl/nptl-stack.c\nindex 4ae081c55e..d327c7f7be 100644\n--- a/nptl/nptl-stack.c\n+++ b/nptl/nptl-stack.c\n@@ -77,7 +77,7 @@ __nptl_free_stacks (size_t limit)\n \n \t  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n \t    GLRO (dl_debug_printf) (\n-\t\t\"TCB cache full, deallocating: TID=%ld, TCB=0x%lx\\n\",\n+\t\t\"tls: TCB deallocating from full cache; TID=%ld, TCB=0x%lx\\n\",\n \t\t(long int) curr->tid, (unsigned long int) curr);\n \n \t  /* Free the memory associated with the ELF TLS.  */\n@@ -104,7 +104,7 @@ queue_stack (struct pthread *stack)\n   /* The 'stack' parameter is a pointer to the TCB (struct pthread),\n      not just the stack.  */\n   if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n-    GLRO (dl_debug_printf) (\"TCB deallocated into cache: TID=%ld, TCB=0x%lx\\n\",\n+    GLRO (dl_debug_printf) (\"tls: TCB deallocated into cache; TID=%ld, TCB=0x%lx\\n\",\n \t\t\t    (long int) stack->tid, (unsigned long int) stack);\n \n   /* We unconditionally add the stack to the list.  The memory may\n@@ -139,7 +139,7 @@ __nptl_deallocate_stack (struct pthread *pd)\n \t the TLS memory.  */\n       if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n \tGLRO (dl_debug_printf) (\n-\t    \"TCB for user-supplied stack deallocated: TID=%ld, TCB=0x%lx\\n\",\n+\t    \"tls: TCB deallocated (user-supplied stack); TID=%ld, TCB=0x%lx\\n\",\n \t    (long int) pd->tid, (unsigned long int) pd);\n       /* Free the memory associated with the ELF TLS.  */\n       _dl_deallocate_tls (TLS_TPADJ (pd), false);\ndiff --git a/nptl/pthread_create.c b/nptl/pthread_create.c\nindex 6e7e0c6435..9a0cefb0f5 100644\n--- a/nptl/pthread_create.c\n+++ b/nptl/pthread_create.c\n@@ -367,7 +367,7 @@ start_thread (void *arg)\n     }\n \n   if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n-    GLRO (dl_debug_printf) (\"Thread starting: TID=%ld, TCB=0x%lx\\n\",\n+    GLRO (dl_debug_printf) (\"tls: thread starting; TID=%ld, TCB=0x%lx\\n\",\n \t\t\t    (long int) pd->tid, (unsigned long int) pd);\n \n   /* Initialize resolver state pointer.  */\ndiff --git a/nptl/tst-dl-debug-tid.c b/nptl/tst-dl-debug-tid.c\nindex b530d2170a..faa3b795b5 100644\n--- a/nptl/tst-dl-debug-tid.c\n+++ b/nptl/tst-dl-debug-tid.c\n@@ -27,12 +27,25 @@\n #include <support/xthread.h>\n #include <stdio.h>\n #include <unistd.h>\n+#include <dlfcn.h>\n+#include <support/xdlfcn.h>\n+#include <support/check.h>\n \n static void *\n thread_function (void *arg)\n {\n   if (arg)\n     pthread_barrier_wait ((pthread_barrier_t *) arg);\n+\n+  /* Load a module with TLS to verify allocation/deallocation logs.  */\n+  void *h = xdlopen (\"tst-tls-debug-mod.so\", RTLD_NOW);\n+\n+  /* Call a function that accesses TLS.  */\n+  int (*fp) (void) = (int (*) (void)) xdlsym (h, \"in_dso\");\n+  TEST_COMPARE (fp (), 0);\n+\n+  xdlclose (h);\n+\n   return NULL;\n }\n \ndiff --git a/nptl/tst-dl-debug-tid.sh b/nptl/tst-dl-debug-tid.sh\nindex 12a4aa2b34..a748865a25 100644\n--- a/nptl/tst-dl-debug-tid.sh\n+++ b/nptl/tst-dl-debug-tid.sh\n@@ -39,7 +39,7 @@ eval \"${test_wrapper_env}\" LD_DEBUG=tls LD_DEBUG_OUTPUT=\"${debug_output}\" \\\n \n debug_output=$(ls \"${debug_output}\".*)\n # Check for the \"Thread starting\" message.\n-if ! grep -q 'Thread starting: TID=' \"${debug_output}\"; then\n+if ! grep -q 'tls: thread starting; TID=.*, TCB=0x' \"${debug_output}\"; then\n     echo \"error: 'Thread starting' message not found\"\n     cat \"${debug_output}\"\n     exit 1\n@@ -47,10 +47,10 @@ fi\n \n # Check that we have a message where the PID (from prefix) is different\n # from the TID (in the message). This indicates a worker thread log.\n-if ! grep 'Thread starting: TID=' \"${debug_output}\" | awk -F '[ \\t:]+' '{\n-  sub(/,/, \"\", $4);\n-  sub(/TID=/, \"\", $4);\n-  if ($1 != $4)\n+if ! grep 'tls: thread starting; TID=.*, TCB=0x' \"${debug_output}\" | awk -F '[ \\t:]+' '{\n+  sub(/TID=/, \"\", $5);\n+  sub(/,/, \"\", $5);\n+  if ($1 != $5)\n     exit 0;\n   exit 1\n }'; then\n@@ -60,12 +60,33 @@ if ! grep 'Thread starting: TID=' \"${debug_output}\" | awk -F '[ \\t:]+' '{\n fi\n \n # We expect messages from thread creation and destruction.\n-if ! grep -q 'TCB allocated\\|TCB deallocating\\|TCB reused\\|TCB deallocated' \\\n+if ! grep -q 'tls: allocate TCB 0x\\|tls: deallocate TCB 0x\\|tls: TCB reused from cache\\|tls: TCB deallocated' \\\n      \"${debug_output}\"; then\n     echo \"error: Expected TCB allocation/deallocation message not found\"\n     cat \"${debug_output}\"\n     exit 1\n fi\n \n+# Check for TLS module ID assignment.\n+if ! grep -q 'tls: assign modid .* to' \"${debug_output}\"; then\n+    echo \"error: Expected 'modid ... assigned to' message not found\"\n+    cat \"${debug_output}\"\n+    exit 1\n+fi\n+\n+# Check for TLS block allocation.\n+if ! grep -q 'tls: allocate block .* for modid .* size=.*, TCB=0x' \"${debug_output}\"; then\n+    echo \"error: Expected 'modid ... allocated' message not found\"\n+    cat \"${debug_output}\"\n+    exit 1\n+fi\n+\n+# TLS block deallocation might be skipped due to DTV surplus.\n+if grep -q 'tls: deallocate block .* for modid .* TCB=0x' \"${debug_output}\"; then\n+    echo \"INFO: module deallocated message found\"\n+else\n+    echo \"INFO: module deallocated message not found (may be due to DTV surplus)\"\n+fi\n+\n cat \"${debug_output}\"\n rm -f \"${debug_output}\"\ndiff --git a/nptl/tst-tls-debug-mod.c b/nptl/tst-tls-debug-mod.c\nnew file mode 100644\nindex 0000000000..0786d3755c\n--- /dev/null\n+++ b/nptl/tst-tls-debug-mod.c\n@@ -0,0 +1,26 @@\n+/* Test for TLS logging in dynamic linker.\n+   Copyright (C) 2026 Free Software Foundation, Inc.\n+   This file is part of the GNU C Library.\n+\n+   The GNU C Library is free software; you can redistribute it and/or\n+   modify it under the terms of the GNU Lesser General Public\n+   License as published by the Free Software Foundation; either\n+   version 2.1 of the License, or (at your option) any later version.\n+\n+   The GNU C Library is distributed in the hope that it will be useful,\n+   but WITHOUT ANY WARRANTY; without even the implied warranty of\n+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n+   Lesser General Public License for more details.\n+\n+   You should have received a copy of the GNU Lesser General Public\n+   License along with the GNU C Library; if not, see\n+   <https://www.gnu.org/licenses/>.  */\n+\n+__thread int tls_var __attribute__ ((tls_model (\"global-dynamic\")));\n+\n+int\n+in_dso (void)\n+{\n+  tls_var = 42;\n+  return tls_var - 42;\n+}\ndiff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c\nindex a1877eeaed..6aee0972bb 100644\n--- a/sysdeps/x86_64/dl-tls.c\n+++ b/sysdeps/x86_64/dl-tls.c\n@@ -41,11 +41,36 @@ __tls_get_addr_slow (tls_index *ti)\n   dtv_t *dtv = THREAD_DTV ();\n \n   size_t gen = atomic_load_acquire (&GL(dl_tls_generation));\n-  if (__glibc_unlikely (dtv[0].counter != gen)\n+  if (__glibc_unlikely (dtv[0].counter != gen))\n+    {\n       /* See comment in __tls_get_addr in elf/dl-tls.c.  */\n-      && !(_dl_tls_allocate_active ()\n-           && ti->ti_module < _dl_tls_initial_modid_limit))\n-    return update_get_addr (ti, gen);\n+      if (_dl_tls_allocate_active ()\n+\t  && ti->ti_module < _dl_tls_initial_modid_limit)\n+\t{\n+\t  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+\t    _dl_debug_printf (\n+\t\t\"tls: modid %lu reentrant usage; TCB=0x%lx\\n\",\n+\t\t(unsigned long int) ti->ti_module,\n+\t\t(unsigned long int) THREAD_SELF);\n+\t}\n+      else\n+\t{\n+\t  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+\t    _dl_debug_printf (\n+\t\t\"tls: modid %lu update DTV to generation %lu; TCB=0x%lx\\n\",\n+\t\t(unsigned long int) ti->ti_module, (unsigned long int) gen,\n+\t\t(unsigned long int) THREAD_SELF);\n+\t  return update_get_addr (ti, gen);\n+\t}\n+    }\n+\n+  if (__glibc_unlikely (dtv[ti->ti_module].pointer.val == TLS_DTV_UNALLOCATED))\n+    {\n+      if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_TLS))\n+\t_dl_debug_printf (\"tls: modid %lu lazy allocation; TCB=0x%lx\\n\",\n+\t\t\t  (unsigned long int) ti->ti_module,\n+\t\t\t  (unsigned long int) THREAD_SELF);\n+    }\n \n   return tls_get_addr_tail (ti, dtv, NULL);\n }\n",
    "prefixes": [
        "v4",
        "1/2"
    ]
}