From 0fa367cc1d8c135c35a6a68fafeb8eb85efb2e41 Mon Sep 17 00:00:00 2001
From: Jeremy Drake <github@jdrake.com>
Date: Fri, 18 Jun 2021 15:39:24 -0700
Subject: [PATCH 45/N] use IsWow64Process2 to detect arm cases.

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.
---
 winsup/cygwin/include/cygwin/exit_process.h | 131 +++++++++++++++-----
 1 file changed, 103 insertions(+), 28 deletions(-)

diff --git a/winsup/cygwin/include/cygwin/exit_process.h b/winsup/cygwin/include/cygwin/exit_process.h
index 5e04c0f..0486a0c 100644
--- a/winsup/cygwin/include/cygwin/exit_process.h
+++ b/winsup/cygwin/include/cygwin/exit_process.h
@@ -46,7 +46,7 @@
 #define small_printf(...) fprintf (stderr, __VA_ARGS__)
 #endif
 
-static BOOL get_wow (HANDLE process, BOOL &is_wow, int &bitness);
+static BOOL get_wow (HANDLE process, BOOL &is_wow, USHORT &process_arch);
 static int exit_process_tree (HANDLE main_process, int exit_code);
 
 static BOOL
@@ -54,24 +54,36 @@ kill_via_console_helper (HANDLE process, wchar_t *function_name, int exit_code,
                          DWORD pid)
 {
   BOOL is_wow;
-  int bitness;
-  if (!get_wow (process, is_wow, bitness))
+  USHORT process_arch;
+  if (!get_wow (process, is_wow, process_arch))
     {
       return FALSE;
     }
 
   const char *name;
-  if (bitness == 32)
-    name = "/usr/libexec/getprocaddr32.exe";
-  else if (bitness == 64)
-    name = "/usr/libexec/getprocaddr64.exe";
-  else
-    return NULL; /* what?!? */
+  switch (process_arch)
+  {
+    case IMAGE_FILE_MACHINE_I386:
+      name = "/usr/libexec/getprocaddr32.exe";
+      break;
+    case IMAGE_FILE_MACHINE_AMD64:
+      name = "/usr/libexec/getprocaddr64.exe";
+      break;
+    /* TODO: provide exes for these */
+    case IMAGE_FILE_MACHINE_ARMNT:
+      name = "/usr/libexec/getprocaddrarm32.exe";
+      break;
+    case IMAGE_FILE_MACHINE_ARM64:
+      name = "/usr/libexec/getprocaddrarm64.exe";
+      break;
+    default:
+      return FALSE; /* what?!? */
+  }
   wchar_t wbuf[PATH_MAX];
 
   if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, name, wbuf, PATH_MAX)
       || GetFileAttributesW (wbuf) == INVALID_FILE_ATTRIBUTES)
-    return NULL;
+    return FALSE;
 
   STARTUPINFOW si = {};
   PROCESS_INFORMATION pi;
@@ -116,33 +128,96 @@ kill_via_console_helper (HANDLE process, wchar_t *function_name, int exit_code,
 static int current_is_wow = -1;
 static int is_32_bit_os = -1;
 
+typedef BOOL (WINAPI * IsWow64Process2_t) (HANDLE, USHORT *, USHORT *);
+static bool wow64process2initialized = false;
+static IsWow64Process2_t pIsWow64Process2 /* = NULL */;
+
+typedef BOOL (WINAPI * GetProcessInformation_t) (HANDLE,
+                                                 PROCESS_INFORMATION_CLASS,
+                                                 LPVOID, DWORD);
+static bool getprocessinfoinitialized = false;
+static GetProcessInformation_t pGetProcessInformation /* = NULL */;
+
 static BOOL
-get_wow (HANDLE process, BOOL &is_wow, int &bitness)
+get_wow (HANDLE process, BOOL &is_wow, USHORT &process_arch)
 {
-  if (is_32_bit_os == -1)
+  USHORT native_arch = IMAGE_FILE_MACHINE_UNKNOWN;
+  if (!wow64process2initialized)
     {
-      SYSTEM_INFO info;
-
-      GetNativeSystemInfo (&info);
-      if (info.wProcessorArchitecture == 0)
-        is_32_bit_os = 1;
-      else if (info.wProcessorArchitecture == 9)
-        is_32_bit_os = 0;
-      else
-        is_32_bit_os = -2;
+      pIsWow64Process2 = (IsWow64Process2_t)
+              GetProcAddress (GetModuleHandle ("KERNEL32"),
+                              "IsWow64Process2");
+      MemoryBarrier ();
+      wow64process2initialized = true;
     }
+  if (!pIsWow64Process2)
+    {
+      if (is_32_bit_os == -1)
+        {
+          SYSTEM_INFO info;
+
+          GetNativeSystemInfo (&info);
+          if (info.wProcessorArchitecture == 0)
+            is_32_bit_os = 1;
+          else if (info.wProcessorArchitecture == 9)
+            is_32_bit_os = 0;
+          else
+            is_32_bit_os = -2;
+        }
 
-  if (current_is_wow == -1
-      && !IsWow64Process (GetCurrentProcess (), &current_is_wow))
-    current_is_wow = -2;
+      if (current_is_wow == -1
+          && !IsWow64Process (GetCurrentProcess (), &current_is_wow))
+        current_is_wow = -2;
 
-  if (is_32_bit_os == -2 || current_is_wow == -2)
-    return FALSE;
+      if (is_32_bit_os == -2 || current_is_wow == -2)
+        return FALSE;
+
+      if (!IsWow64Process (process, &is_wow))
+        return FALSE;
+
+      process_arch = is_32_bit_os || is_wow ? IMAGE_FILE_MACHINE_I386 :
+                                      IMAGE_FILE_MACHINE_AMD64;
+      return TRUE;
+    }
 
-  if (!IsWow64Process (process, &is_wow))
+  if (!pIsWow64Process2 (process, &process_arch, &native_arch))
     return FALSE;
 
-  bitness = is_32_bit_os || is_wow ? 32 : 64;
+  /* The value will be IMAGE_FILE_MACHINE_UNKNOWN if the target process
+   * is not a WOW64 process
+   */
+  if (process_arch == IMAGE_FILE_MACHINE_UNKNOWN)
+    {
+      struct /* _PROCESS_MACHINE_INFORMATION */
+        {
+          /* 0x0000 */ USHORT ProcessMachine;
+          /* 0x0002 */ USHORT Res0;
+          /* 0x0004 */ DWORD MachineAttributes;
+        } /* size: 0x0008 */ process_machine_info;
+
+      is_wow = FALSE;
+      /* However, x86_64 on ARM64 claims not to be WOW64, so we have to
+       * dig harder... */
+      if (!getprocessinfoinitialized)
+        {
+          pGetProcessInformation = (GetProcessInformation_t)
+                  GetProcAddress (GetModuleHandle ("KERNEL32"),
+                                  "GetProcessInformation");
+          MemoryBarrier ();
+          getprocessinfoinitialized = true;
+        }
+      /*#define ProcessMachineTypeInfo 9*/
+      if (pGetProcessInformation &&
+          pGetProcessInformation (process, (PROCESS_INFORMATION_CLASS)9,
+            &process_machine_info, sizeof (process_machine_info)))
+        process_arch = process_machine_info.ProcessMachine;
+      else
+        process_arch = native_arch;
+    }
+  else
+    {
+      is_wow = TRUE;
+    }
   return TRUE;
 }
 
-- 
2.32.0.windows.1

