trad-frame cleanups
[deliverable/binutils-gdb.git] / gdb / windows-nat.c
index 2ee7a2412a9b1dd5e93756871e40bcf185c655f6..fc32d71a7398694532b2ad94ffbf0a2b85b98119 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-vector operations for controlling windows child processes, for GDB.
 
-   Copyright (C) 1995-2020 Free Software Foundation, Inc.
+   Copyright (C) 1995-2021 Free Software Foundation, Inc.
 
    Contributed by Cygnus Solutions, A Red Hat Company.
 
@@ -71,6 +71,7 @@
 #include "gdbsupport/pathstuff.h"
 #include "gdbsupport/gdb_wait.h"
 #include "nat/windows-nat.h"
+#include "gdbsupport/symbol.h"
 
 using namespace windows_nat;
 
@@ -200,8 +201,8 @@ enum
 #endif
 
 #define CONTEXT_DEBUGGER_DR CONTEXT_FULL | CONTEXT_FLOATING_POINT \
-        | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS \
-        | CONTEXT_EXTENDED_REGISTERS
+       | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS \
+       | CONTEXT_EXTENDED_REGISTERS
 
 static uintptr_t dr[8];
 static int debug_registers_changed;
@@ -217,10 +218,10 @@ static int windows_initialization_done;
 #endif
 
 #define CHECK(x)       check (x, __FILE__,__LINE__)
-#define DEBUG_EXEC(x)  if (debug_exec)         printf_unfiltered x
-#define DEBUG_EVENTS(x)        if (debug_events)       printf_unfiltered x
-#define DEBUG_MEM(x)   if (debug_memory)       printf_unfiltered x
-#define DEBUG_EXCEPT(x)        if (debug_exceptions)   printf_unfiltered x
+#define DEBUG_EXEC(x)  if (debug_exec)         debug_printf x
+#define DEBUG_EVENTS(x)        if (debug_events)       debug_printf x
+#define DEBUG_MEM(x)   if (debug_memory)       debug_printf x
+#define DEBUG_EXCEPT(x)        if (debug_exceptions)   debug_printf x
 
 static void cygwin_set_dr (int i, CORE_ADDR addr);
 static void cygwin_set_dr7 (unsigned long val);
@@ -234,8 +235,7 @@ static std::vector<windows_thread_info *> thread_list;
 static int saw_create;
 static int open_process_used = 0;
 #ifdef __x86_64__
-static bool wow64_process = false;
-static bool ignore_first_breakpoint = false;
+static void *wow64_dbgbreak;
 #endif
 
 /* User options.  */
@@ -311,14 +311,16 @@ struct windows_nat_target final : public x86_nat_target<inf_child_target>
 
   void resume (ptid_t, int , enum gdb_signal) override;
 
-  ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
+  ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
 
   void fetch_registers (struct regcache *, int) override;
   void store_registers (struct regcache *, int) override;
 
   bool stopped_by_sw_breakpoint () override
   {
-    return current_windows_thread->stopped_at_software_breakpoint;
+    windows_thread_info *th
+      = thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
+    return th->stopped_at_software_breakpoint;
   }
 
   bool supports_stopped_by_sw_breakpoint () override
@@ -357,6 +359,8 @@ struct windows_nat_target final : public x86_nat_target<inf_child_target>
   const char *thread_name (struct thread_info *) override;
 
   int get_windows_debug_event (int pid, struct target_waitstatus *ourstatus);
+
+  void do_initial_windows_stuff (DWORD pid, bool attaching);
 };
 
 static windows_nat_target the_windows_nat_target;
@@ -605,6 +609,7 @@ windows_fetch_one_register (struct regcache *regcache,
   else
     {
       if (th->stopped_at_software_breakpoint
+         && !th->pc_adjusted
          && r == gdbarch_pc_regnum (gdbarch))
        {
          int size = register_size (gdbarch, r);
@@ -623,6 +628,8 @@ windows_fetch_one_register (struct regcache *regcache,
              value -= gdbarch_decr_pc_after_break (gdbarch);
              memcpy (context_offset, &value, size);
            }
+         /* Make sure we only rewrite the PC a single time.  */
+         th->pc_adjusted = true;
        }
       regcache->raw_supply (r, context_offset);
     }
@@ -821,7 +828,10 @@ windows_make_so (const char *name, LPVOID load_addr)
          free (rname);
        }
       else
-       error (_("dll path too long"));
+       {
+         warning (_("dll path for \"%s\" too long or inaccessible"), name);
+         strcpy (so->so_name, so->so_original_name);
+       }
     }
   /* Record cygwin1.dll .text start/end.  */
   p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1);
@@ -829,7 +839,7 @@ windows_make_so (const char *name, LPVOID load_addr)
     {
       asection *text = NULL;
 
-      gdb_bfd_ref_ptr abfd (gdb_bfd_open (so->so_name, "pei-i386", -1));
+      gdb_bfd_ref_ptr abfd (gdb_bfd_open (so->so_name, "pei-i386"));
 
       if (abfd == NULL)
        return so;
@@ -980,13 +990,13 @@ signal_event_command (const char *args, int from_tty)
 int
 windows_nat::handle_output_debug_string (struct target_waitstatus *ourstatus)
 {
-  gdb::unique_xmalloc_ptr<char> s;
   int retval = 0;
 
-  if (!target_read_string
-       ((CORE_ADDR) (uintptr_t) current_event.u.DebugString.lpDebugStringData,
-        &s, 1024, 0)
-      || !s || !*(s.get ()))
+  gdb::unique_xmalloc_ptr<char> s
+    = (target_read_string
+       ((CORE_ADDR) (uintptr_t) current_event.u.DebugString.lpDebugStringData,
+       1024));
+  if (s == nullptr || !*(s.get ()))
     /* nothing to do */;
   else if (!startswith (s.get (), _CYGWIN_SIGNAL_STRING))
     {
@@ -1126,11 +1136,15 @@ display_selector (HANDLE thread, DWORD sel)
 static void
 display_selectors (const char * args, int from_tty)
 {
-  if (!current_windows_thread)
+  if (inferior_ptid == null_ptid)
     {
       puts_filtered ("Impossible to display selectors now.\n");
       return;
     }
+
+  windows_thread_info *current_windows_thread
+    = thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
+
   if (!args)
     {
 #ifdef __x86_64__
@@ -1211,10 +1225,8 @@ windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
       if (named_thread != NULL)
        {
          int thread_name_len;
-         gdb::unique_xmalloc_ptr<char> thread_name;
-
-         thread_name_len = target_read_string (thread_name_target,
-                                               &thread_name, 1025, NULL);
+         gdb::unique_xmalloc_ptr<char> thread_name
+           = target_read_string (thread_name_target, 1025, &thread_name_len);
          if (thread_name_len > 0)
            {
              thread_name.get ()[thread_name_len - 1] = '\0';
@@ -1228,6 +1240,31 @@ windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
   return false;
 }
 
+/* See nat/windows-nat.h.  */
+
+bool
+windows_nat::handle_access_violation (const EXCEPTION_RECORD *rec)
+{
+#ifdef __CYGWIN__
+  /* See if the access violation happened within the cygwin DLL
+     itself.  Cygwin uses a kind of exception handling to deal with
+     passed-in invalid addresses.  gdb should not treat these as real
+     SEGVs since they will be silently handled by cygwin.  A real SEGV
+     will (theoretically) be caught by cygwin later in the process and
+     will be sent as a cygwin-specific-signal.  So, ignore SEGVs if
+     they show up within the text segment of the DLL itself.  */
+  const char *fn;
+  CORE_ADDR addr = (CORE_ADDR) (uintptr_t) rec->ExceptionAddress;
+
+  if ((!cygwin_exceptions && (addr >= cygwin_load_start
+                             && addr < cygwin_load_end))
+      || (find_pc_partial_function (addr, &fn, NULL, NULL)
+         && startswith (fn, "KERNEL32!IsBad")))
+    return true;
+#endif
+  return false;
+}
+
 /* Resume thread specified by ID, or all artificially suspended
    threads, if we are continuing execution.  KILLED non-zero means we
    have killed the inferior, so we should ignore weird errors due to
@@ -1339,12 +1376,11 @@ fake_create_process (void)
        (unsigned) GetLastError ());
       /*  We can not debug anything in that case.  */
     }
-  current_windows_thread
-    = windows_add_thread (ptid_t (current_event.dwProcessId,
-                                 current_event.dwThreadId, 0),
-                         current_event.u.CreateThread.hThread,
-                         current_event.u.CreateThread.lpThreadLocalBase,
-                         true /* main_thread_p */);
+  windows_add_thread (ptid_t (current_event.dwProcessId, 0,
+                             current_event.dwThreadId),
+                     current_event.u.CreateThread.hThread,
+                     current_event.u.CreateThread.lpThreadLocalBase,
+                     true /* main_thread_p */);
   return current_event.dwThreadId;
 }
 
@@ -1487,25 +1523,41 @@ ctrl_c_handler (DWORD event_type)
   if (!new_console && !attach_flag)
     return TRUE;
 
-  if (!DebugBreakProcess (current_process_handle))
-    warning (_("Could not interrupt program.  "
-              "Press Ctrl-c in the program console."));
+#ifdef __x86_64__
+  if (wow64_process)
+    {
+      /* Call DbgUiRemoteBreakin of the 32bit ntdll.dll in the target process.
+        DebugBreakProcess would call the one of the 64bit ntdll.dll, which
+        can't be correctly handled by gdb.  */
+      if (wow64_dbgbreak == nullptr)
+       {
+         CORE_ADDR addr;
+         if (!find_minimal_symbol_address ("ntdll!DbgUiRemoteBreakin",
+                                           &addr, 0))
+           wow64_dbgbreak = (void *) addr;
+       }
+
+      if (wow64_dbgbreak != nullptr)
+       {
+         HANDLE thread = CreateRemoteThread (current_process_handle, NULL,
+                                             0, (LPTHREAD_START_ROUTINE)
+                                             wow64_dbgbreak, NULL, 0, NULL);
+         if (thread)
+           CloseHandle (thread);
+       }
+    }
+  else
+#endif
+    {
+      if (!DebugBreakProcess (current_process_handle))
+       warning (_("Could not interrupt program.  "
+                  "Press Ctrl-c in the program console."));
+    }
 
   /* Return true to tell that Ctrl-C has been handled.  */
   return TRUE;
 }
 
-/* A wrapper for WaitForDebugEvent that sets "last_wait_event"
-   appropriately.  */
-static BOOL
-wait_for_debug_event (DEBUG_EVENT *event, DWORD timeout)
-{
-  BOOL result = WaitForDebugEvent (event, timeout);
-  if (result)
-    last_wait_event = *event;
-  return result;
-}
-
 /* Get the next event from the child.  Returns a non-zero thread id if the event
    requires handling by WFI (or whatever).  */
 
@@ -1515,8 +1567,6 @@ windows_nat_target::get_windows_debug_event (int pid,
 {
   BOOL debug_event;
   DWORD continue_status, event_code;
-  windows_thread_info *th;
-  static windows_thread_info dummy_thread_info (0, 0, 0);
   DWORD thread_id = 0;
 
   /* If there is a relevant pending stop, report it now.  See the
@@ -1528,10 +1578,9 @@ windows_nat_target::get_windows_debug_event (int pid,
       thread_id = stop->thread_id;
       *ourstatus = stop->status;
 
-      inferior_ptid = ptid_t (current_event.dwProcessId, thread_id, 0);
-      current_windows_thread = thread_rec (inferior_ptid,
-                                          INVALIDATE_CONTEXT);
-      current_windows_thread->reload_context = 1;
+      ptid_t ptid (current_event.dwProcessId, thread_id);
+      windows_thread_info *th = thread_rec (ptid, INVALIDATE_CONTEXT);
+      th->reload_context = 1;
 
       return thread_id;
     }
@@ -1545,7 +1594,6 @@ windows_nat_target::get_windows_debug_event (int pid,
 
   event_code = current_event.dwDebugEventCode;
   ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
-  th = NULL;
   have_saved_context = 0;
 
   switch (event_code)
@@ -1571,8 +1619,8 @@ windows_nat_target::get_windows_debug_event (int pid,
        }
       /* Record the existence of this thread.  */
       thread_id = current_event.dwThreadId;
-      th = windows_add_thread
-        (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0),
+      windows_add_thread
+       (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0),
         current_event.u.CreateThread.hThread,
         current_event.u.CreateThread.lpThreadLocalBase,
         false /* main_thread_p */);
@@ -1588,7 +1636,6 @@ windows_nat_target::get_windows_debug_event (int pid,
                                     current_event.dwThreadId, 0),
                             current_event.u.ExitThread.dwExitCode,
                             false /* main_thread_p */);
-      th = &dummy_thread_info;
       break;
 
     case CREATE_PROCESS_DEBUG_EVENT:
@@ -1602,8 +1649,8 @@ windows_nat_target::get_windows_debug_event (int pid,
 
       current_process_handle = current_event.u.CreateProcessInfo.hProcess;
       /* Add the main thread.  */
-      th = windows_add_thread
-        (ptid_t (current_event.dwProcessId,
+      windows_add_thread
+       (ptid_t (current_event.dwProcessId,
                 current_event.dwThreadId, 0),
         current_event.u.CreateProcessInfo.hThread,
         current_event.u.CreateProcessInfo.lpThreadLocalBase,
@@ -1732,26 +1779,21 @@ windows_nat_target::get_windows_debug_event (int pid,
                     thread_id, desired_stop_thread_id));
 
       if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
-         && (current_event.u.Exception.ExceptionRecord.ExceptionCode
-             == EXCEPTION_BREAKPOINT)
+         && ((current_event.u.Exception.ExceptionRecord.ExceptionCode
+              == EXCEPTION_BREAKPOINT)
+             || (current_event.u.Exception.ExceptionRecord.ExceptionCode
+                 == STATUS_WX86_BREAKPOINT))
          && windows_initialization_done)
        {
          ptid_t ptid = ptid_t (current_event.dwProcessId, thread_id, 0);
-         th = thread_rec (ptid, INVALIDATE_CONTEXT);
+         windows_thread_info *th = thread_rec (ptid, INVALIDATE_CONTEXT);
          th->stopped_at_software_breakpoint = true;
+         th->pc_adjusted = false;
        }
       pending_stops.push_back ({thread_id, *ourstatus, current_event});
       thread_id = 0;
       CHECK (windows_continue (continue_status, desired_stop_thread_id, 0));
     }
-  else
-    {
-      inferior_ptid = ptid_t (current_event.dwProcessId, thread_id, 0);
-      current_windows_thread = th;
-      if (!current_windows_thread)
-       current_windows_thread = thread_rec (inferior_ptid,
-                                            INVALIDATE_CONTEXT);
-    }
 
 out:
   return thread_id;
@@ -1760,7 +1802,7 @@ out:
 /* Wait for interesting events to occur in the target process.  */
 ptid_t
 windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
-                         int options)
+                         target_wait_flags options)
 {
   int pid = -1;
 
@@ -1808,14 +1850,25 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
        {
          ptid_t result = ptid_t (current_event.dwProcessId, retval, 0);
 
-         if (current_windows_thread != nullptr)
+         if (ourstatus->kind != TARGET_WAITKIND_EXITED
+             && ourstatus->kind !=  TARGET_WAITKIND_SIGNALLED)
            {
-             current_windows_thread->stopped_at_software_breakpoint = false;
-             if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
-                 && (current_event.u.Exception.ExceptionRecord.ExceptionCode
-                     == EXCEPTION_BREAKPOINT)
-                 && windows_initialization_done)
-               current_windows_thread->stopped_at_software_breakpoint = true;
+             windows_thread_info *th = thread_rec (result, INVALIDATE_CONTEXT);
+
+             if (th != nullptr)
+               {
+                 th->stopped_at_software_breakpoint = false;
+                 if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
+                     && ((current_event.u.Exception.ExceptionRecord.ExceptionCode
+                          == EXCEPTION_BREAKPOINT)
+                         || (current_event.u.Exception.ExceptionRecord.ExceptionCode
+                             == STATUS_WX86_BREAKPOINT))
+                     && windows_initialization_done)
+                   {
+                     th->stopped_at_software_breakpoint = true;
+                     th->pc_adjusted = false;
+                   }
+               }
            }
 
          return result;
@@ -1950,8 +2003,8 @@ windows_add_all_dlls (void)
     }
 }
 
-static void
-do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
+void
+windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
 {
   int i;
   struct inferior *inf;
@@ -1967,8 +2020,8 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
 #endif
   current_event.dwProcessId = pid;
   memset (&current_event, 0, sizeof (current_event));
-  if (!target_is_pushed (ops))
-    push_target (ops);
+  if (!target_is_pushed (this))
+    push_target (this);
   disable_breakpoints_in_shlibs ();
   windows_clear_solib ();
   clear_proceed_status (0);
@@ -1993,22 +2046,18 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
   inferior_appeared (inf, pid);
   inf->attach_flag = attaching;
 
-  /* Make the new process the current inferior, so terminal handling
-     can rely on it.  When attaching, we don't know about any thread
-     id here, but that's OK --- nothing should be referencing the
-     current thread until we report an event out of windows_wait.  */
-  inferior_ptid = ptid_t (pid);
-
   target_terminal::init ();
   target_terminal::inferior ();
 
   windows_initialization_done = 0;
 
+  ptid_t last_ptid;
+
   while (1)
     {
       struct target_waitstatus status;
 
-      ops->wait (minus_one_ptid, &status, 0);
+      last_ptid = this->wait (minus_one_ptid, &status, 0);
 
       /* Note windows_wait returns TARGET_WAITKIND_SPURIOUS for thread
         events.  */
@@ -2016,9 +2065,11 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
          && status.kind != TARGET_WAITKIND_SPURIOUS)
        break;
 
-      ops->resume (minus_one_ptid, 0, GDB_SIGNAL_0);
+      this->resume (minus_one_ptid, 0, GDB_SIGNAL_0);
     }
 
+  switch_to_thread (find_thread_ptid (this, last_ptid));
+
   /* Now that the inferior has been started and all DLLs have been mapped,
      we can iterate over all DLLs and load them in.
 
@@ -2150,7 +2201,7 @@ windows_nat_target::attach (const char *args, int from_tty)
     }
 #endif
 
-  do_initial_windows_stuff (this, pid, 1);
+  do_initial_windows_stuff (pid, 1);
   target_terminal::ours ();
 }
 
@@ -2180,7 +2231,7 @@ windows_nat_target::detach (inferior *inf, int from_tty)
     }
 
   x86_cleanup_dregs ();
-  inferior_ptid = null_ptid;
+  switch_to_no_thread ();
   detach_inferior (inf);
 
   maybe_unpush_target ();
@@ -2362,7 +2413,7 @@ clear_win32_environment (char **env)
       mbstowcs (copy, env[i], len);
       equalpos = wcschr (copy, L'=');
       if (equalpos)
-        *equalpos = L'\0';
+       *equalpos = L'\0';
       SetEnvironmentVariableW (copy, NULL);
     }
   xfree (copy);
@@ -2707,7 +2758,7 @@ windows_nat_target::create_inferior (const char *exec_file,
   PROCESS_INFORMATION pi;
   BOOL ret;
   DWORD flags = 0;
-  const char *inferior_io_terminal = get_inferior_io_terminal ();
+  const char *inferior_tty = current_inferior ()->tty ();
 
   if (!exec_file)
     error (_("No executable specified, use `target exec'."));
@@ -2806,14 +2857,14 @@ windows_nat_target::create_inferior (const char *exec_file,
       w32_env = NULL;
     }
 
-  if (!inferior_io_terminal)
+  if (inferior_tty == nullptr)
     tty = ostdin = ostdout = ostderr = -1;
   else
     {
-      tty = open (inferior_io_terminal, O_RDWR | O_NOCTTY);
+      tty = open (inferior_tty, O_RDWR | O_NOCTTY);
       if (tty < 0)
        {
-         print_sys_errmsg (inferior_io_terminal, errno);
+         print_sys_errmsg (inferior_tty, errno);
          ostdin = ostdout = ostderr = -1;
        }
       else
@@ -2878,19 +2929,19 @@ windows_nat_target::create_inferior (const char *exec_file,
       allargs_len = strlen (allargs_copy);
     }
   /* If not all the standard streams are redirected by the command
-     line, use inferior_io_terminal for those which aren't.  */
-  if (inferior_io_terminal
+     line, use INFERIOR_TTY for those which aren't.  */
+  if (inferior_tty != nullptr
       && !(fd_inp >= 0 && fd_out >= 0 && fd_err >= 0))
     {
       SECURITY_ATTRIBUTES sa;
       sa.nLength = sizeof(sa);
       sa.lpSecurityDescriptor = 0;
       sa.bInheritHandle = TRUE;
-      tty = CreateFileA (inferior_io_terminal, GENERIC_READ | GENERIC_WRITE,
+      tty = CreateFileA (inferior_tty, GENERIC_READ | GENERIC_WRITE,
                         0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
       if (tty == INVALID_HANDLE_VALUE)
        warning (_("Warning: Failed to open TTY %s, error %#x."),
-                inferior_io_terminal, (unsigned) GetLastError ());
+                inferior_tty, (unsigned) GetLastError ());
     }
   if (redirected || tty != INVALID_HANDLE_VALUE)
     {
@@ -2990,7 +3041,7 @@ windows_nat_target::create_inferior (const char *exec_file,
   else
     saw_create = 0;
 
-  do_initial_windows_stuff (this, pi.dwProcessId, 0);
+  do_initial_windows_stuff (pi.dwProcessId, 0);
 
   /* windows_continue (DBG_CONTINUE, -1, 0); */
 }
@@ -3559,7 +3610,7 @@ _initialize_loadable ()
 #endif
       GPA (hm, GetModuleInformation);
       GetModuleFileNameEx = (GetModuleFileNameEx_ftype *)
-        GetProcAddress (hm, GetModuleFileNameEx_name);
+       GetProcAddress (hm, GetModuleFileNameEx_name);
     }
 
   if (!EnumProcessModules || !GetModuleInformation || !GetModuleFileNameEx)
This page took 0.030527 seconds and 4 git commands to generate.