Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

teach MINGW Ctrl+C handling about arm processes #47

Merged

Conversation

jeremyd2019
Copy link
Member

@jeremyd2019 jeremyd2019 commented Jun 19, 2021

From https://github.com/msys2/msys2-runtime/pull/31/files#r637592143

Calling GetNativeSystemInfo on arm/arm64 lies. To get accurate information about native arch and process's emulated arch, use IsWow64Process2 where available. Otherwise, fall back to the GetNativeSystemInfo/IsWow64Process logic.

Unfortunately, IsWow64Process2 doesn't consider x86_64 processes on ARM64 to be Wow64, and returns exactly the same information as it does for native ARM64 processes. Use GetProcessInformation/ProcessMachineTypeInfo to further refine the
answer in that case, when available (see msys2/MINGW-packages#8991)

Because there are more cases than just 32 or 64 bit, change out bitness out param for IMAGE_FILE_MACHINE_* constants like IsWow64Process2 uses, and assume I386/AMD64 to be 32/64 bit in the old case.

While cygwin already 'knows' how to autoload IsWow64Process2, and will make it return FALSE/ERROR_PROC_NOT_FOUND if it isn't present, this magic does not seem to be present in kill.exe so go back to manual GetModuleHandle/GetProcAddress. ☹️

@Biswa96
Copy link
Member

Biswa96 commented Jun 19, 2021

Jsut FYI, IsWow64Process2 is available from Win10 only.

@jeremyd2019
Copy link
Member Author

Jsut FYI, IsWow64Process2 is available from Win10 only.

Yes, specifically 1511

@jeremyd2019 jeremyd2019 force-pushed the msys2-3_2_0-arm-ctrlc branch 3 times, most recently from 40d491c to 2db43c9 Compare June 21, 2021 23:00
@jeremyd2019 jeremyd2019 requested a review from dscho June 22, 2021 00:20
@jeremyd2019
Copy link
Member Author

I've tested this on 20H2 Win10 arm64, against arm32 arm64 and i686 native processes, and it works as expected (quickly terminating the arm processes, and launching getprocaddr32 for i686). I still need to test on the insider preview with x86_64 processes.

@jeremyd2019 jeremyd2019 marked this pull request as ready for review June 22, 2021 00:24
@jeremyd2019
Copy link
Member Author

jeremyd2019 commented Jun 22, 2021

Depending on prevailing opinion, I can either drop a1431aa or squash it before merging. Unfortunately I am not seriously considering actually building arm32/arm64 executables, as that would require mingw-w64-cross-clang, and among other concerns mingw-w64-cross-clang-crt/headers conflict with their gcc cousins.

For the curious, here are the binaries I built with mingw-w64-cross-clang:
getprocaddrarm.zip

@jeremyd2019
Copy link
Member Author

jeremyd2019 commented Jun 22, 2021

Unfortunately arm32 and arm64 say "Could not get symbol info" for CtrlRoutine, but they can ExitProcess ok

@jeremyd2019
Copy link
Member Author

Poked around with windbg. CtrlRoutine is there, but it's just not finding it for whatever reason...

 # RetAddr           : Args to Child                                                           : Call Site
07 00007ff8`2f9284f8 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : getprocaddrarm64+0x1f1c
08 00007ff8`3178cc64 : 00000000`00000002 00000000`00000001 00000000`00000000 00000000`00000000 : KERNELBASE!CtrlRoutine+0x148
09 00007ff8`31eab1f4 : 00000034`f61fff50 00007ff8`31eab1f4 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x34
0a 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x44

@jeremyd2019
Copy link
Member Author

jeremyd2019 commented Jun 22, 2021

Oddly enough, this hack seems to work:

diff --git a/winsup/utils/getprocaddr.c b/winsup/utils/getprocaddr.c
index 80b399c..beafc10 100644
--- a/winsup/utils/getprocaddr.c
+++ b/winsup/utils/getprocaddr.c
@@ -164,9 +164,9 @@ main (int argc, char **argv)
    * because here because that symbol isn't exported.
    */

-  if (strcmp (argv[1], "CtrlRoutine"))
+  if (TRUE || strcmp (argv[1], "CtrlRoutine"))
     {
-      HINSTANCE kernel32 = GetModuleHandle ("kernel32");
+      HINSTANCE kernel32 = GetModuleHandle (strcmp(argv[1], "CtrlRoutine") ? "kernel32" : "kernelbase");
       if (!kernel32)
         return 1;
       void *address = (void *)GetProcAddress (kernel32, argv[1]);

Maybe it could look in KERNELBASE for CtrlRoutine the same way it looks in KERNEL32 for ExitProcess, and if it's not found fall back to using dbghelp (assuming there's a downlevel version of Windows for which that didn't work, that prompted the dbghelp approach in the first place).

@jeremyd2019
Copy link
Member Author

The CtrlHandler stuff is not working on the insider preview arm64 at all, 32/64/arm32/arm64. Could not find address in stack

@jeremyd2019
Copy link
Member Author

jeremyd2019 commented Jun 22, 2021

Aargh, hopefully this is a bug in the insider preview, but IsWow64Process2 from x86_64 process to x86_64 process on ARM64 is returning TRUE, process_arch = IMAGE_FILE_MACHINE_UNKNOWN, native_arch = IMAGE_FILE_MACHINE_ARM64, exactly the same as it does from x86_64 process to an aarch64 process.

It appears to be the same from i686 process querying x86_64 process. 🤯

@jeremyd2019 jeremyd2019 marked this pull request as draft June 22, 2021 06:32
Copy link
Collaborator

@dscho dscho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am in favor of integrating this as-is, even if it is unclear so far how we could get the ARM versions of getprocaddr to compile and to work.

@jeremyd2019
Copy link
Member Author

I was too, until the behavior on the insider preview build of arm64 with x86_64 processes completely blew up my assumptions about IsWow64Process2. @dscho do you happen to know the proper way to ask a question about an API of Microsoft, where you might get a response from somebody who knows how it works?

@dscho
Copy link
Collaborator

dscho commented Jun 23, 2021

the behavior on the insider preview build of arm64 with x86_64 processes completely blew up my assumptions about IsWow64Process2

How so?

@jeremyd2019
Copy link
Member Author

the behavior on the insider preview build of arm64 with x86_64 processes completely blew up my assumptions about IsWow64Process2

How so?

I figured it would return IMAGE_FILE_MACHINE_AMD64 for *pProcessMachine, and IMAGE_FILE_MACHINE_ARM64 for *pNativeMachine
but I observed IMAGE_FILE_MACHINE_UNKNOWN for *pProcessMachine and IMAGE_FILE_MACHINE_ARM64 for *pNativeMachine (the same as for an ARM64 process)
which it documents as being expected " if the target process is not a WOW64 process"
if x86_64 on arm64 is "not a WOW64 process" what is it, and how am I supposed to tell?

And what you want to achive or detect? Is it for detecting x86_64 process in arm64 only?

basically that's the only case I know of that doesn't work
I would like to know the arch of a process, on any arch and any arch of process
I can tell i686 and arm32, but I can't tell x86_64 from "native", which AFAIK only matters on arm64 (because x86_64 running on x86_64 is native)

(From https://discord.com/channels/792780131906617355/797787562706075659/856948456437448715)

@jeremyd2019
Copy link
Member Author

https://docs.microsoft.com/en-us/answers/questions/449019/detect-x86-64-process-on-arm64.html

@jeremyd2019
Copy link
Member Author

I don't think I'm going to get a reasonable answer on the MS Q&A site... I did a deep dive, IsWow64Process2 calls RtlWow64GetProcessMachines, which in turn calls NtQuerySystemInformationEx with system information class 0xb5 (SystemSuppportedProcessorArchitectures) and the process handle as the input buffer. What comes back out appear to be a list of 32-bit values. The lower 16-bits are the IMAGE_FILE_MACHINE_* constants, and the upper bits seem to contain flags. The RtlWow64GetProcessMachines on 21H1 ands the flags with 0xC and checks for 0x8 or 0x4. the 0x8 bit seems to mean "this is the architecture of the process" and the 0x4 bit seems to mean "this is the native architecture of the machine". 0x2 seems to be set on all returned arches, and 0x1 is also set on the native arch.

On the insider preview build on arm64, there is also a 0x10 bit which is set on both i686 and arm32. BUT x86_64 is not present in the list at all!!!. an x86_64 process come back as 0xfaa64, exactly the same as native arm64 processes.

Should we just ignore the insider preview, assuming it is buggy, and go ahead with this as it works perfectly in released versions of Windows?

@Biswa96
Copy link
Member

Biswa96 commented Jun 25, 2021

Please join the discussion here msys2/MINGW-packages#8991

@jeremyd2019 jeremyd2019 force-pushed the msys2-3_2_0-arm-ctrlc branch 3 times, most recently from fa77b9c to 1f06c46 Compare June 25, 2021 18:36
@jeremyd2019
Copy link
Member Author

1f06c46 works for properly detecting and running the correct getprocaddr variant to inject Ctrl+C into aarch64 i686 and x86_64 python, and at least cancels arm32 FINDSTR on the Insider Preview build! I will squash and mark this ready for review. Thanks @Biswa96 !

@jeremyd2019 jeremyd2019 marked this pull request as ready for review June 25, 2021 19:35
@jeremyd2019
Copy link
Member Author

jeremyd2019 commented Jun 25, 2021

I have tested this (before squashing) on the ARM64 Insider Preview in both i686 and x86_64 msys, against mingw32 mingw64 and clangarm64 pythons interrupting time.sleep(1000). I did some cursory testing against ARM32 FINDSTR from x86_64 msys as well.

Copy link
Member Author

@jeremyd2019 jeremyd2019 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made an attempt at conforming to style, with a couple of cases where I wasn't sure exactly.

winsup/cygwin/include/cygwin/exit_process.h Outdated Show resolved Hide resolved
winsup/cygwin/include/cygwin/exit_process.h Outdated Show resolved Hide resolved
@jeremyd2019

This comment has been minimized.

@jeremyd2019
Copy link
Member Author

jeremyd2019 commented Jun 27, 2021

Originally posted by @Biswa96 in msys2/MINGW-packages#8991 (reply in thread)
The aforementioned structures and enum are in WinSDK version 10.0.22000.0. I shall add those symbols in mingw-w64. In future, if mingw-w64/w32api cygwin package were updated there will be some redeclaration error.

Risk should be minimal because I used GetProcAddress, and avoided defining things since the code was in a header and I didn't want to 'leak' any definitions. The only thing that might get a redeclaration error is the struct, and depending on what's 'allowed' the struct could probably be 'anonymous' in this case, as I declared it right on the variable definition.

kill doesn't appear to have the cygwin autoload stuff, so use
GetProcAddress manually

Unfortunately, IsWow64Process2 doesn't consider x86_64 processes on
ARM64 to be Wow64, and returns exactly the same information as it does
for native ARM64 processes.  Use
GetProcessInformation/ProcessMachineTypeInfo to further refine the
answer in that case, when available (see #8991)

add exe names for arm, but they are not built as the tooling for
targeting arm is complicated.
@jeremyd2019
Copy link
Member Author

I just got the "Windows 11" update on my insider preview arm64 vm. This all continues to work there for all 4 arches. I think this may be ready to merge.

@jeremyd2019
Copy link
Member Author

Hearing no objection, the motion is adopted.

@hmartinez82
Copy link

the behavior on the insider preview build of arm64 with x86_64 processes completely blew up my assumptions about IsWow64Process2

How so?

I figured it would return IMAGE_FILE_MACHINE_AMD64 for *pProcessMachine, and IMAGE_FILE_MACHINE_ARM64 for *pNativeMachine but I observed IMAGE_FILE_MACHINE_UNKNOWN for *pProcessMachine and IMAGE_FILE_MACHINE_ARM64 for *pNativeMachine (the same as for an ARM64 process) which it documents as being expected " if the target process is not a WOW64 process" if x86_64 on arm64 is "not a WOW64 process" what is it, and how am I supposed to tell?

That's because there is, in fact, no "Windows-on-Windows" going on.
x64 processes in Windows 11 do not suffer Registry or Filesystem redirection (like classic WOW does). Both ARM64 and x64's Program Files is C:\Program Files.

Windows 11 has the classic WOW (WOW6432Node, for 32 bits x86) and WOWA (WowAA32Node, for 32 bits ARM). Btw, C:\Program Files (Arm) is actually for 32 bits ARM. I've seen some confusion in the wild where people thought that C:\Program Files (Arm) was for ARM64 software.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants