From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id ubE3DitBUWpyCgIAWB0awg (envelope-from ) for ; Fri, 10 Jul 2026 14:59:55 -0400 Received: by simark.ca (Postfix, from userid 112) id 35FE51E070; Fri, 10 Jul 2026 14:59:55 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.3 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [IPv6:2620:52:6:3111::32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id AC8661E070 for ; Fri, 10 Jul 2026 14:59:53 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EA2574BA2E19 for ; Fri, 10 Jul 2026 18:59:50 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org EA2574BA2E19 Received: from mail-wm1-f49.google.com (mail-wm1-f49.google.com [209.85.128.49]) by sourceware.org (Postfix) with ESMTPS id 208194BA540B for ; Fri, 10 Jul 2026 18:59:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 208194BA540B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=palves.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 208194BA540B Authentication-Results: sourceware.org; arc=none smtp.remote-ip=209.85.128.49 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1783709962; cv=none; b=oNwzqehhsqHjAHVyFFeydE+WB23Scdsw7hsFcwXUU6lzhaHP1d6QL+SrytMK9h9nxL/VJfIH4QThfpdq6Z6kTRyeADQE7zwLJy0FpQpSKTHWOqL+FgUkCNAghGzcdQZOl9bYGEVfaCJ2CPpP8cdFeMG1r2+3zHzZADolIbblCSc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1783709962; c=relaxed/simple; bh=WAV4iVe/Meenn8bOkdQjypeMzJGLy6KO90Qd6L2hpFg=; h=Message-ID:Date:MIME-Version:Subject:To:From; b=dye0dXlN+DaoM+vcUdWpcpco179XNXzLCxavidhMHyZH6r4D4yxTLhomhkCazsTafqqJUjBrR9TxKzLdKphyPEcimef9uruX9T+lc/RuHHGtPOqNSPVhBay1zKZRYH2q3KX1XrlNaEvRsn0jDCvl/z48ISllHrEvI40qIHmFplQ= ARC-Authentication-Results: i=1; sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 208194BA540B Received: by mail-wm1-f49.google.com with SMTP id 5b1f17b1804b1-493c7902f47so11859395e9.1 for ; Fri, 10 Jul 2026 11:59:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783709961; x=1784314761; h=content-transfer-encoding:content-type:in-reply-to:content-language :from:references:cc:to:subject:user-agent:mime-version:date :message-id:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=hyqVmy0js0fJZKL2T1+MKyKzFeuSSAtIswRwPUD8GNo=; b=m6mhdgU4ld5TWOGYOy2ijdsFVCixWWoWrc9xszpeVnLdoxxoVHyo/TaVBfwCaJ6/gA sL6ohSdWG8l9MHGO1opXXIsMPCeNarzBQgHrqXql+KQqP8S86dSDrwC/faSEaiRbJccH l3uYJzkRAXHjtdOkHpdDeiwjhzIuR5n1gPfMgY1L/SlnPzuw8z3intSSWehXnemOcNtE xpbd3T8yzUGYWXTTdYzKeuwyKN/eCaiq6/9AAQbL23XU0suHkoGgxuJf+cZHL8o/H9Rf 8xpjGh6hN3pw6C5oUwsKhh1UnXzIFg9635iIOFWgEndu7OmgwqWz2HaCSD1f+LM9jdUb mGBQ== X-Gm-Message-State: AOJu0YyuNObmB8GVPFHypWLwxoigoPQOzX4uHcse8d29512/vczvWDvS 6poN6P5hE6jYoOiLJtaGwMaee007q9UKdX+OZ5VQRfOI6593jyxn628qfxNU03vu X-Gm-Gg: AfdE7clF9lfwDGpWOxoDqXdNH1HMT8prbMSGFizO7wUVI3SobxCW1Wyc8qQpy98XYxI 0uq1RgBHXhwLSYdmSnx+L86FZvQlRKg9SlwbFD8ljifQn07EKSRxeOiWXoh7ORrf0pogqBGBZii 7bYlelbsXjsvD0rI3BI88hlRYCEuF8L+GwPfad+033QK3A71HsLtrgZexPbs4ZuGX2guV8r+l7j 3A+KRCLxmILyBbgqA3HEWz7LGlg8AYaHkAAhcDlbioZRT02wYEt3/Wt7Kjk+bUiIYmIvQowsLEL T+SnJLqNOWCtKL5jjStqX9bvr5UuInRepr+tC5Oe/A3N4utfxIRZc7LmT5ajDdS0A6qZWxrSOVl iUnkGqADL5Y7n0PVcFFlavBM7JXlYvWN6MNcv9US5fmQ8oX9K27RMwLhUqOxKx7TYzuwkBCqKCl 4VQaDcE0959nIUrLzBjlpLUmFW2yBbo2b/2Ygn52Gt7W51ah5P9Fg39aU= X-Received: by 2002:a05:600c:3488:b0:493:c83b:50d7 with SMTP id 5b1f17b1804b1-493f87db708mr928515e9.6.1783709960476; Fri, 10 Jul 2026 11:59:20 -0700 (PDT) Received: from ?IPV6:2001:8a0:fae3:3700:f1ac:e6ce:cba9:ebd2? ([2001:8a0:fae3:3700:f1ac:e6ce:cba9:ebd2]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-493eb6df6d9sm172218505e9.7.2026.07.10.11.59.19 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 10 Jul 2026 11:59:19 -0700 (PDT) Message-ID: <17aacd11-cc42-43eb-8328-bdcedcc0dfb5@palves.net> Date: Fri, 10 Jul 2026 19:59:17 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: [PATCH] gdb/Windows testsuite: Embed asInvoker manifest in test executables To: Eli Zaretskii Cc: gdb-patches@sourceware.org References: <20260709174351.431907-1-pedro@palves.net> <86zezzjucz.fsf@gnu.org> From: Pedro Alves Content-Language: en-US In-Reply-To: <86zezzjucz.fsf@gnu.org> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org On 2026-07-10 06:18, Eli Zaretskii wrote: >> From: Pedro Alves >> Turns out that Windows has an "installer detection" heuristic that >> refuses to launch executables whose filename contains keywords like >> "update", "setup", and "install" without elevation (admin rights), >> unless the PE embeds a manifest declaring >> requestedExecutionLevel="asInvoker". >> ... >> - Matches the word (e.g. "update") as a substring anywhere in the >> filename (not just as a prefix). >> ... > Note that IME, not only programs literally called "install.exe", > "update.exe" etc. are blocked, but also programs whose name begins > with these words. For example, I had problems with the Texinfo's > install-info.exe. Right, I mentioned this above. It triggers if the string appears anywhere on the filename as a substring. E.g., fooupdatebar.exe triggers it. It's curious that you bring up patch.exe. In the downstream testcase I mention, the initial comment that I wrote there mentioned "patch" as "bad" word too (as some docs somewhere mention it), and then after the initial fix, I noticed that "patch" is actually OK, and so I dropped it from the comment in a follow up patch. Just tried it again, to confirm: $ ./hello.exe Hello! $ mv hello.exe update.exe $ ./update.exe -bash: /c/msys2/home/alves/update.exe: Permission denied $ mv update.exe patch.exe $ ./patch.exe Hello! So looks like Microsoft decided that "patch" wasn't a bad word after all at some point more recently... > FTR, another way of overcoming this is by providing a manifest file. > Below is an example of such a manifest I use for patch.exe. The > manifest must be named PROGRAM.exe.manifest and should be in the same > directory as the executable. Indeed, I mentioned "unless manifest" further above too. Putting a sidecar manifest file next to every executable wouldn't work very well, as some testcases want to rename the executable after compiling it. It should also be possible to embed a manifest into the binary directly using windres. The problem I ran into the last time I tried this was that windres/llvm-windres wasn't available in the AMD GPU LLVM-based toolchain I need to support. llvm-rc can also be used (with a different interface), and it is available in some distributions, but even that one is not available in the latest daily builds of TheRock for Windows, which I'll need to support. ... several hours of head banging and poking later ... OK, I got it working. Turns out that lld-link has built-in support for embedding a manifest! Nice. So I can cover all the bases after all. Also, I noticed that executables produced by the GCC 16 that comes with MSYS2 do not have the issue. (??!) Digging a bit, it turns out that both MSYS2 and Cygwin ship a default-manifest.o object file that GCC pulls in via a spec file. This default-manifest.o file is in a separate optional package, which may be removed, and GCC keeps working, just won't link in the default manifest. https://gcc.gnu.org/legacy-ml/gcc-patches/2014-04/msg01378.html https://sourceforge.net/p/mingw-w64/wiki2/default_manifest/ I'm normally using the xPack GCC distribution (https://github.com/xpack-dev-tools/gcc-xpack/), which does have that .o file, and thus no default manifest. As for the gdb.rocm/ testcase I saw this first on, that is compiled wit hipcc/llvm/lld-link, which likewise has no manifest by default. Find below the new patch adding a manifest to every executable in the testsuite. WDYT of this one? Note: this caches the windres .o file using the same logic as for set_unbuffered_mode.o, which in parallel mode should hit the same EBUSY failure fixed by the file_rename_atomic proc added by: https://inbox.sourceware.org/gdb-patches/20260709155657.412594-1-pedro@palves.net/T/#u Funny I wrote there "Put the rename in its own procedure, as I expect this will be used in more places.", and then immediately run into such a spot the day after. I'll tweak this new code to use that other patch's proc once that one is in, it's just a one line change. -- >8 -- >From d721c058e8c31a07d1ce188938df8707ef773e04 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Fri, 10 Jul 2026 12:28:34 +0100 Subject: [PATCH] gdb/Windows testsuite: Embed asInvoker manifest in test executables Running gdb.base/execl-update-breakpoints.exp on Windows 11 shows this FAIL: (gdb) run Starting program: .../execl-update-breakpoints1.exe Error creating process .../execl-update-breakpoints1.exe (error 740): The requested operation requires elevation. (gdb) FAIL: gdb.base/execl-update-breakpoints.exp: runto: run to main Error 740 is ERROR_ELEVATION_REQUIRED. Windows has an "installer detection" heuristic that refuses to launch executables whose file name contains keywords like "update", "setup" and "install" without elevation (admin rights), unless the PE embeds an application manifest declaring requestedExecutionLevel="asInvoker". Some older Microsoft documentation claims the heuristic only applies to 32-bit binaries, but what I observe is that: - It triggers with 64-bit PEs on current Windows. And also: - It matches the word (e.g. "update") as a substring anywhere in the file name, not just as a prefix. - It is not drive-dependent. I thought moving the executable to a dev drive might suppress the check, but it does not. I saw this problem first in a downstream ROCgdb testcase, and there I worked around it by renaming that particular testcase. This is the second case now, so rather than teach individual testcases to avoid the "bad" words, fix it once, centrally, in a way that is independent of the executable's file name. The Microsoft-sanctioned escape hatch is to embed an application manifest that declares the "asInvoker" execution level. That's what this commit does, it makes gdb_compile embed one in every Windows executable it builds. How the manifest gets embedded depends on the linker. There are two ways: - GNU ld can't embed a manifest by itself, so compile it into a resource object with windres and link that in. - lld-link is able to embed one directly, with the /manifest:embed and /manifestinput options. Since it's not guaranteed that clang always links with lld-link, and conversely, gcc may also link with lld-link, gdb_compile picks between the two by probing what the linker accepts, rather than keying off the compiler or the target. This whole issue only reproduces with some toolchains, because some MinGW or Cygwin installations already embed an equivalent manifest of their own, via a default-manifest.o that the gcc spec links in. That object comes from the separate windows-default-manifest package, so whether it is embedded depends on the installation rather than the gcc version. Since we're adding a manifest, might as well declare the supported Windows versions there too (a compatibility section listing per-version GUIDs), like default-manifest.o does. Without those, the version-reporting APIs (GetVersionEx and friends) cap out at Windows 8. We should probably add such a manifest to GDB itself too, at some point. Change-Id: Ic0afc925136a61c259cb8b6681627dc1775a8445 --- gdb/testsuite/lib/future.exp | 10 ++ gdb/testsuite/lib/gdb.exp | 150 +++++++++++++++++++++++++++++ gdb/testsuite/lib/windows.manifest | 53 ++++++++++ gdb/testsuite/lib/windows.rc | 23 +++++ 4 files changed, 236 insertions(+) create mode 100644 gdb/testsuite/lib/windows.manifest create mode 100644 gdb/testsuite/lib/windows.rc diff --git a/gdb/testsuite/lib/future.exp b/gdb/testsuite/lib/future.exp index 0f45aa44628..3ab160a05fc 100644 --- a/gdb/testsuite/lib/future.exp +++ b/gdb/testsuite/lib/future.exp @@ -177,6 +177,16 @@ proc gdb_find_readelf {} { return $readelf } +proc gdb_find_windres {} { + global WINDRES_FOR_TARGET + if {[info exists WINDRES_FOR_TARGET]} { + set windres $WINDRES_FOR_TARGET + } else { + set windres [transform windres] + } + return $windres +} + proc gdb_find_eu-unstrip {} { global EU_UNSTRIP_FOR_TARGET if {[info exists EU_UNSTRIP_FOR_TARGET]} { diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index a40c87c6727..9b86d53be08 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -4217,6 +4217,12 @@ proc is_aarch64_target {} { return [expr {![is_aarch32_target]}] } +# Return true if the target is Windows-based. + +proc is_windows_based_target {} { + return [expr {[istarget *-*-cygwin*] || [istarget *-*-mingw*]}] +} + # Return 1 if displaced stepping is supported on target, otherwise, return 0. proc support_displaced_stepping {} { @@ -6402,6 +6408,97 @@ proc quote_for_host { args } { return $str } +# Set while linker_supports_manifest_embed is running its test link, +# so that the inner gdb_compile that link goes through skips the +# manifest-embedding logic and doesn't recurse back into the probe. +set gdb_probing_manifest_embed 0 + +# Return the ldflags (as a list of "ldflags=..." options) that make +# lld-link embed our application manifest into the executable. + +proc gdb_windows_manifest_embed_lld_link_ldflags {} { + global srcdir + + set ldflags {} + + # Turn on embedding (off by default). + lappend ldflags ldflags=-Wl,/manifest:embed + + # Stop lld-link from also generating its own UAC block. With + # this, lld-link embeds our input as-is, while without it lld-link + # runs its manifest merger, which before LLVM 21 reprefixes + # trustInfo into the asm.v1 namespace and produces a manifest the + # Windows loader rejects. See + # . + lappend ldflags ldflags=-Wl,/manifestuac:no + + # Embed our manifest file. Pass it in Windows-native form. + # MSYS2's argument conversion treats a "/foo:/bar" argument as a + # colon-separated list of POSIX paths and mistakenly rewrites it + # to a semicolon-separated list of Windows paths. E.g.: + # + # "/manifestinput:/c/gdb/.../windows.manifest" + # => + # "C:\msys64\manifestinput;C:\gdb\...\windows.manifest" + # + # I.e., the flag name itself gets converted as if it were a path, + # and the ":" becomes ";". + # + # What triggers the conversion is the value after the colon looking + # like an absolute POSIX path (a leading "/"). "/manifest:embed" + # above is left alone because "embed" doesn't. Passing the value + # as a native "C:/..." path likewise avoids it. + set manifest [host_file_normalize ${srcdir}/lib/windows.manifest] + lappend ldflags ldflags=-Wl,/manifestinput:${manifest} + + return $ldflags +} + +# Compile lib/windows.rc into an object embedding our application +# manifest and return the object path, so that gdb_compile can link it +# into every Windows test executable. The result is cached. Returns +# the empty string on failure. This is used when linking with GNU ld, +# which cannot embed a manifest by itself. + +proc gdb_windows_manifest_obj {} { + global srcdir objdir + global gdb_saved_windows_manifest_obj + + if {[info exists gdb_saved_windows_manifest_obj]} { + return $gdb_saved_windows_manifest_obj + } + + set rc_src ${srcdir}/lib/windows.rc + set obj_basename windows-manifest.o + set obj [standard_temp_file $obj_basename] + + set windres [gdb_find_windres] + set cmd [list $windres -I [file dirname $rc_src] \ + -i $rc_src -o $obj -O coff] + verbose -log "Executing $cmd" + if {[catch {exec {*}$cmd} output]} { + verbose -log "gdb_windows_manifest_obj: windres failed: $output" + return "" + } + + if {[is_remote host]} { + set saved $obj_basename + } else { + set saved ${objdir}/$obj_basename + } + # Link a copy of the output object, because the original may be + # automatically deleted. + if {[info exists ::GDB_PARALLEL]} { + # Make sure to write the .o file atomically. (Note + # GDB_PARALLEL mode does not support remote host testing.) + file rename -force -- $obj $saved + } else { + remote_download host $obj $saved + } + set gdb_saved_windows_manifest_obj $saved + return $saved +} + # Compile source files specified by SOURCE into a binary of type TYPE at path # DEST. gdb_compile is implemented using DejaGnu's target_compile, so the type # parameter and most options are passed directly to it. @@ -6942,6 +7039,40 @@ proc gdb_compile {source dest type options} { } } + # On Windows, embed an "asInvoker" application manifest, so that + # Windows doesn't refuse to launch executables (with + # ERROR_ELEVATION_REQUIRED/740) whose file name happens to contain + # an installer-detection keyword such as "update", "setup" or + # "install". + # + # There are two ways to get the manifest in, depending on the + # linker: + # + # - GNU ld can't embed a manifest by itself, so compile the + # manifest into a resource object with windres and link that + # in. + # + # - lld-link can embed a manifest by itself, no resource compiler + # needed. Note that the LLVM toolchain has llvm-windres and + # llvm-rc, but not all LLVM-based toolchain distributions ship + # them. + # + # Probe whether the linker supports embedding a manifest rather + # than trying to guess which linker is in use from the compiler or + # target. + if { $type == "executable" + && [is_windows_based_target] + && !$::gdb_probing_manifest_embed } { + if { [linker_supports_manifest_embed] } { + lappend options {*}[gdb_windows_manifest_embed_lld_link_ldflags] + } else { + set manifest_obj [gdb_windows_manifest_obj] + if { $manifest_obj != "" } { + lappend options "ldflags=$manifest_obj" + } + } + } + # Automatically handle includes in testsuite/lib/. auto_lappend_include_files options $source @@ -11203,6 +11334,25 @@ gdb_caching_proc linker_supports_image_base_flag {} { return [gdb_simple_compile $me $src executable $flags] } +# Return 1 if the linker is lld-link which can embed our application +# manifest by itself, otherwise 0. Probes the exact flag combination +# gdb_compile uses. +gdb_caching_proc linker_supports_manifest_embed {} { + set me "linker_supports_manifest_embed" + set flags [gdb_windows_manifest_embed_lld_link_ldflags] + set src { int main() { return 0; } } + + # Guard against infinite recursion: the test link below itself + # goes through gdb_compile, which consults this proc to decide + # whether to embed the manifest. The guard makes that inner + # gdb_compile skip the manifest logic. + set ::gdb_probing_manifest_embed 1 + set result [gdb_simple_compile $me $src executable $flags] + set ::gdb_probing_manifest_embed 0 + + return $result +} + # Return 1 if compiler supports scalar_storage_order attribute, otherwise # return 0. diff --git a/gdb/testsuite/lib/windows.manifest b/gdb/testsuite/lib/windows.manifest new file mode 100644 index 00000000000..f0e371588f2 --- /dev/null +++ b/gdb/testsuite/lib/windows.manifest @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/testsuite/lib/windows.rc b/gdb/testsuite/lib/windows.rc new file mode 100644 index 00000000000..2c1b2ca81d4 --- /dev/null +++ b/gdb/testsuite/lib/windows.rc @@ -0,0 +1,23 @@ +/* Copyright (C) 2026 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 . */ + +/* Embed the application manifest. + + 1 => CREATEPROCESS_MANIFEST_RESOURCE_ID + 24 => RT_MANIFEST +*/ +1 24 "windows.manifest" base-commit: 490469846dcef89fe53668bdbba73591c64bed61 -- 2.54.0