forked from Imagelibrary/binutils-gdb
Compare commits
35 Commits
gdb-16.1-r
...
users/palv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41330f5d32 | ||
|
|
5223cde0d5 | ||
|
|
7d6c04c580 | ||
|
|
650daf1818 | ||
|
|
6b25d11b01 | ||
|
|
af7fc7ff9e | ||
|
|
acd3803fa9 | ||
|
|
13c13b58d2 | ||
|
|
7ad98390f7 | ||
|
|
467b267632 | ||
|
|
a0bc4291f1 | ||
|
|
41f9f2d609 | ||
|
|
0c6b048236 | ||
|
|
f5e5342583 | ||
|
|
f428cac615 | ||
|
|
11adfeba32 | ||
|
|
5ad78cc624 | ||
|
|
02ff02e05f | ||
|
|
4ae1d3c664 | ||
|
|
3a84bb42a3 | ||
|
|
3f6f23ee4e | ||
|
|
734404845d | ||
|
|
8055ea0bb6 | ||
|
|
49fcf1ccc7 | ||
|
|
44fff407b7 | ||
|
|
552616cbb7 | ||
|
|
87e727c0c6 | ||
|
|
f99b2890dd | ||
|
|
b67852992b | ||
|
|
c151e663fa | ||
|
|
78ef7c48d1 | ||
|
|
ea80c32fa7 | ||
|
|
446babcd70 | ||
|
|
cefdca26f9 | ||
|
|
b93d04b777 |
3
gdb/NEWS
3
gdb/NEWS
@@ -9,6 +9,9 @@
|
|||||||
* Building GDB and GDBserver now requires a C++17 compiler.
|
* Building GDB and GDBserver now requires a C++17 compiler.
|
||||||
For example, GCC 9 or later.
|
For example, GCC 9 or later.
|
||||||
|
|
||||||
|
* The Windows native target now supports non-stop mode. This feature
|
||||||
|
requires Windows 10 or later.
|
||||||
|
|
||||||
* GDB index now contains information about the main function. This speeds up
|
* GDB index now contains information about the main function. This speeds up
|
||||||
startup when it is being used for some large binaries.
|
startup when it is being used for some large binaries.
|
||||||
|
|
||||||
|
|||||||
36
gdb/infrun.c
36
gdb/infrun.c
@@ -365,6 +365,42 @@ update_signals_program_target (void)
|
|||||||
target_program_signals (signal_program);
|
target_program_signals (signal_program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See infrun.h. */
|
||||||
|
|
||||||
|
gdb_signal
|
||||||
|
get_detach_signal (process_stratum_target *proc_target, ptid_t ptid)
|
||||||
|
{
|
||||||
|
thread_info *tp = proc_target->find_thread (ptid);
|
||||||
|
gdb_signal signo = GDB_SIGNAL_0;
|
||||||
|
|
||||||
|
if (target_is_non_stop_p () && !tp->executing ())
|
||||||
|
{
|
||||||
|
if (tp->has_pending_waitstatus ())
|
||||||
|
{
|
||||||
|
/* If the thread has a pending event, and it was stopped
|
||||||
|
with a signal, use that signal to resume it. If it has a
|
||||||
|
pending event of another kind, it was not stopped with a
|
||||||
|
signal, so resume it without a signal. */
|
||||||
|
if (tp->pending_waitstatus ().kind () == TARGET_WAITKIND_STOPPED)
|
||||||
|
signo = tp->pending_waitstatus ().sig ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
signo = tp->stop_signal ();
|
||||||
|
}
|
||||||
|
else if (!target_is_non_stop_p ())
|
||||||
|
{
|
||||||
|
ptid_t last_ptid;
|
||||||
|
process_stratum_target *last_target;
|
||||||
|
|
||||||
|
get_last_target_status (&last_target, &last_ptid, nullptr);
|
||||||
|
|
||||||
|
if (last_target == proc_target && ptid == last_ptid)
|
||||||
|
signo = tp->stop_signal ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return signo;
|
||||||
|
}
|
||||||
|
|
||||||
/* Value to pass to target_resume() to cause all threads to resume. */
|
/* Value to pass to target_resume() to cause all threads to resume. */
|
||||||
|
|
||||||
#define RESUME_ALL minus_one_ptid
|
#define RESUME_ALL minus_one_ptid
|
||||||
|
|||||||
@@ -319,6 +319,12 @@ extern void all_uis_on_sync_execution_starting (void);
|
|||||||
detach. */
|
detach. */
|
||||||
extern void restart_after_all_stop_detach (process_stratum_target *proc_target);
|
extern void restart_after_all_stop_detach (process_stratum_target *proc_target);
|
||||||
|
|
||||||
|
/* While detaching, return the signal PTID was supposed to be resumed
|
||||||
|
with, if it were resumed, so we can pass it down to PTID while
|
||||||
|
detaching. */
|
||||||
|
extern gdb_signal get_detach_signal (process_stratum_target *proc_target,
|
||||||
|
ptid_t ptid);
|
||||||
|
|
||||||
/* RAII object to temporarily disable the requirement for target
|
/* RAII object to temporarily disable the requirement for target
|
||||||
stacks to commit their resumed threads.
|
stacks to commit their resumed threads.
|
||||||
|
|
||||||
|
|||||||
@@ -1286,13 +1286,13 @@ detach_one_pid (int pid, int signo)
|
|||||||
pid, strsignal (signo));
|
pid, strsignal (signo));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get pending signal of THREAD as a host signal number, for detaching
|
/* Get pending signal of LP as a host signal number, for detaching
|
||||||
purposes. This is the signal the thread last stopped for, which we
|
purposes. This is the signal the thread last stopped for, which we
|
||||||
need to deliver to the thread when detaching, otherwise, it'd be
|
need to deliver to the thread when detaching, otherwise, it'd be
|
||||||
suppressed/lost. */
|
suppressed/lost. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_detach_signal (struct lwp_info *lp)
|
get_lwp_detach_signal (struct lwp_info *lp)
|
||||||
{
|
{
|
||||||
enum gdb_signal signo = GDB_SIGNAL_0;
|
enum gdb_signal signo = GDB_SIGNAL_0;
|
||||||
|
|
||||||
@@ -1322,37 +1322,7 @@ get_detach_signal (struct lwp_info *lp)
|
|||||||
else if (lp->status)
|
else if (lp->status)
|
||||||
signo = gdb_signal_from_host (WSTOPSIG (lp->status));
|
signo = gdb_signal_from_host (WSTOPSIG (lp->status));
|
||||||
else
|
else
|
||||||
{
|
signo = get_detach_signal (linux_target, lp->ptid);
|
||||||
thread_info *tp = linux_target->find_thread (lp->ptid);
|
|
||||||
|
|
||||||
if (target_is_non_stop_p () && !tp->executing ())
|
|
||||||
{
|
|
||||||
if (tp->has_pending_waitstatus ())
|
|
||||||
{
|
|
||||||
/* If the thread has a pending event, and it was stopped with a
|
|
||||||
signal, use that signal to resume it. If it has a pending
|
|
||||||
event of another kind, it was not stopped with a signal, so
|
|
||||||
resume it without a signal. */
|
|
||||||
if (tp->pending_waitstatus ().kind () == TARGET_WAITKIND_STOPPED)
|
|
||||||
signo = tp->pending_waitstatus ().sig ();
|
|
||||||
else
|
|
||||||
signo = GDB_SIGNAL_0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
signo = tp->stop_signal ();
|
|
||||||
}
|
|
||||||
else if (!target_is_non_stop_p ())
|
|
||||||
{
|
|
||||||
ptid_t last_ptid;
|
|
||||||
process_stratum_target *last_target;
|
|
||||||
|
|
||||||
get_last_target_status (&last_target, &last_ptid, nullptr);
|
|
||||||
|
|
||||||
if (last_target == linux_target
|
|
||||||
&& lp->ptid.lwp () == last_ptid.lwp ())
|
|
||||||
signo = tp->stop_signal ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signo == GDB_SIGNAL_0)
|
if (signo == GDB_SIGNAL_0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -153,6 +153,55 @@ windows_thread_info::thread_name ()
|
|||||||
return name.get ();
|
return name.get ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read Windows signal info. See nat/windows-nat.h. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
windows_thread_info::xfer_siginfo (gdb_byte *readbuf,
|
||||||
|
ULONGEST offset, ULONGEST len,
|
||||||
|
ULONGEST *xfered_len)
|
||||||
|
{
|
||||||
|
if (last_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (readbuf == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
EXCEPTION_RECORD &er = last_event.u.Exception.ExceptionRecord;
|
||||||
|
|
||||||
|
char *buf = (char *) &er;
|
||||||
|
size_t bufsize = sizeof (er);
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
EXCEPTION_RECORD32 er32;
|
||||||
|
if (proc->wow64_process)
|
||||||
|
{
|
||||||
|
buf = (char *) &er32;
|
||||||
|
bufsize = sizeof (er32);
|
||||||
|
|
||||||
|
er32.ExceptionCode = er.ExceptionCode;
|
||||||
|
er32.ExceptionFlags = er.ExceptionFlags;
|
||||||
|
er32.ExceptionRecord
|
||||||
|
= (uintptr_t) er.ExceptionRecord;
|
||||||
|
er32.ExceptionAddress
|
||||||
|
= (uintptr_t) er.ExceptionAddress;
|
||||||
|
er32.NumberParameters = er.NumberParameters;
|
||||||
|
for (int i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
|
||||||
|
er32.ExceptionInformation[i] = er.ExceptionInformation[i];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (offset > bufsize)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (offset + len > bufsize)
|
||||||
|
len = bufsize - offset;
|
||||||
|
|
||||||
|
memcpy (readbuf, buf + offset, len);
|
||||||
|
*xfered_len = len;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to determine the executable filename.
|
/* Try to determine the executable filename.
|
||||||
|
|
||||||
EXE_NAME_RET is a pointer to a buffer whose size is EXE_NAME_MAX_LEN.
|
EXE_NAME_RET is a pointer to a buffer whose size is EXE_NAME_MAX_LEN.
|
||||||
@@ -310,8 +359,10 @@ get_image_name (HANDLE h, void *address, int unicode)
|
|||||||
/* See nat/windows-nat.h. */
|
/* See nat/windows-nat.h. */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
windows_process_info::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
|
windows_process_info::handle_ms_vc_exception (const DEBUG_EVENT ¤t_event)
|
||||||
{
|
{
|
||||||
|
const EXCEPTION_RECORD *rec = ¤t_event.u.Exception.ExceptionRecord;
|
||||||
|
|
||||||
if (rec->NumberParameters >= 3
|
if (rec->NumberParameters >= 3
|
||||||
&& (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000)
|
&& (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000)
|
||||||
{
|
{
|
||||||
@@ -325,9 +376,8 @@ windows_process_info::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
|
|||||||
if (named_thread_id == (DWORD) -1)
|
if (named_thread_id == (DWORD) -1)
|
||||||
named_thread_id = current_event.dwThreadId;
|
named_thread_id = current_event.dwThreadId;
|
||||||
|
|
||||||
named_thread = thread_rec (ptid_t (current_event.dwProcessId,
|
named_thread = find_thread (ptid_t (current_event.dwProcessId,
|
||||||
named_thread_id, 0),
|
named_thread_id, 0));
|
||||||
DONT_INVALIDATE_CONTEXT);
|
|
||||||
if (named_thread != NULL)
|
if (named_thread != NULL)
|
||||||
{
|
{
|
||||||
int thread_name_len;
|
int thread_name_len;
|
||||||
@@ -353,7 +403,8 @@ windows_process_info::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
|
|||||||
#define MS_VC_EXCEPTION 0x406d1388
|
#define MS_VC_EXCEPTION 0x406d1388
|
||||||
|
|
||||||
handle_exception_result
|
handle_exception_result
|
||||||
windows_process_info::handle_exception (struct target_waitstatus *ourstatus,
|
windows_process_info::handle_exception (DEBUG_EVENT ¤t_event,
|
||||||
|
struct target_waitstatus *ourstatus,
|
||||||
bool debug_exceptions)
|
bool debug_exceptions)
|
||||||
{
|
{
|
||||||
#define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \
|
#define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \
|
||||||
@@ -365,14 +416,6 @@ windows_process_info::handle_exception (struct target_waitstatus *ourstatus,
|
|||||||
DWORD code = rec->ExceptionCode;
|
DWORD code = rec->ExceptionCode;
|
||||||
handle_exception_result result = HANDLE_EXCEPTION_HANDLED;
|
handle_exception_result result = HANDLE_EXCEPTION_HANDLED;
|
||||||
|
|
||||||
memcpy (&siginfo_er, rec, sizeof siginfo_er);
|
|
||||||
|
|
||||||
/* Record the context of the current thread. */
|
|
||||||
thread_rec (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0),
|
|
||||||
DONT_SUSPEND);
|
|
||||||
|
|
||||||
last_sig = GDB_SIGNAL_0;
|
|
||||||
|
|
||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case EXCEPTION_ACCESS_VIOLATION:
|
case EXCEPTION_ACCESS_VIOLATION:
|
||||||
@@ -485,7 +528,7 @@ windows_process_info::handle_exception (struct target_waitstatus *ourstatus,
|
|||||||
break;
|
break;
|
||||||
case MS_VC_EXCEPTION:
|
case MS_VC_EXCEPTION:
|
||||||
DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION");
|
DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION");
|
||||||
if (handle_ms_vc_exception (rec))
|
if (handle_ms_vc_exception (current_event))
|
||||||
{
|
{
|
||||||
ourstatus->set_stopped (GDB_SIGNAL_TRAP);
|
ourstatus->set_stopped (GDB_SIGNAL_TRAP);
|
||||||
result = HANDLE_EXCEPTION_IGNORED;
|
result = HANDLE_EXCEPTION_IGNORED;
|
||||||
@@ -506,7 +549,11 @@ windows_process_info::handle_exception (struct target_waitstatus *ourstatus,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ourstatus->kind () == TARGET_WAITKIND_STOPPED)
|
if (ourstatus->kind () == TARGET_WAITKIND_STOPPED)
|
||||||
last_sig = ourstatus->sig ();
|
{
|
||||||
|
ptid_t ptid (current_event.dwProcessId, current_event.dwThreadId, 0);
|
||||||
|
windows_thread_info *th = find_thread (ptid);
|
||||||
|
th->last_sig = ourstatus->sig ();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@@ -639,11 +686,11 @@ windows_process_info::add_dll (LPVOID load_addr)
|
|||||||
/* See nat/windows-nat.h. */
|
/* See nat/windows-nat.h. */
|
||||||
|
|
||||||
void
|
void
|
||||||
windows_process_info::dll_loaded_event ()
|
windows_process_info::dll_loaded_event (const DEBUG_EVENT ¤t_event)
|
||||||
{
|
{
|
||||||
gdb_assert (current_event.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT);
|
gdb_assert (current_event.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT);
|
||||||
|
|
||||||
LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
|
const LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
|
||||||
const char *dll_name;
|
const char *dll_name;
|
||||||
|
|
||||||
/* Try getting the DLL name via the lpImageName field of the event.
|
/* Try getting the DLL name via the lpImageName field of the event.
|
||||||
@@ -671,69 +718,29 @@ windows_process_info::add_all_dlls ()
|
|||||||
|
|
||||||
/* See nat/windows-nat.h. */
|
/* See nat/windows-nat.h. */
|
||||||
|
|
||||||
bool
|
ptid_t
|
||||||
windows_process_info::matching_pending_stop (bool debug_events)
|
get_last_debug_event_ptid ()
|
||||||
{
|
{
|
||||||
/* If there are pending stops, and we might plausibly hit one of
|
return ptid_t (last_wait_event.dwProcessId, last_wait_event.dwThreadId, 0);
|
||||||
them, we don't want to actually continue the inferior -- we just
|
|
||||||
want to report the stop. In this case, we just pretend to
|
|
||||||
continue. See the comment by the definition of "pending_stops"
|
|
||||||
for details on why this is needed. */
|
|
||||||
for (const auto &item : pending_stops)
|
|
||||||
{
|
|
||||||
if (desired_stop_thread_id == -1
|
|
||||||
|| desired_stop_thread_id == item.thread_id)
|
|
||||||
{
|
|
||||||
DEBUG_EVENTS ("pending stop anticipated, desired=0x%x, item=0x%x",
|
|
||||||
desired_stop_thread_id, item.thread_id);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See nat/windows-nat.h. */
|
|
||||||
|
|
||||||
std::optional<pending_stop>
|
|
||||||
windows_process_info::fetch_pending_stop (bool debug_events)
|
|
||||||
{
|
|
||||||
std::optional<pending_stop> result;
|
|
||||||
for (auto iter = pending_stops.begin ();
|
|
||||||
iter != pending_stops.end ();
|
|
||||||
++iter)
|
|
||||||
{
|
|
||||||
if (desired_stop_thread_id == -1
|
|
||||||
|| desired_stop_thread_id == iter->thread_id)
|
|
||||||
{
|
|
||||||
result = *iter;
|
|
||||||
current_event = iter->event;
|
|
||||||
|
|
||||||
DEBUG_EVENTS ("pending stop found in 0x%x (desired=0x%x)",
|
|
||||||
iter->thread_id, desired_stop_thread_id);
|
|
||||||
|
|
||||||
pending_stops.erase (iter);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See nat/windows-nat.h. */
|
/* See nat/windows-nat.h. */
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
continue_last_debug_event (DWORD continue_status, bool debug_events)
|
continue_last_debug_event (DWORD cont_status, bool debug_events)
|
||||||
{
|
{
|
||||||
DEBUG_EVENTS ("ContinueDebugEvent (cpid=%d, ctid=0x%x, %s)",
|
DEBUG_EVENTS
|
||||||
(unsigned) last_wait_event.dwProcessId,
|
("ContinueDebugEvent (cpid=%d, ctid=0x%x, %s)",
|
||||||
(unsigned) last_wait_event.dwThreadId,
|
(unsigned) last_wait_event.dwProcessId,
|
||||||
continue_status == DBG_CONTINUE ?
|
(unsigned) last_wait_event.dwThreadId,
|
||||||
"DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED");
|
cont_status == DBG_CONTINUE ? "DBG_CONTINUE" :
|
||||||
|
cont_status == DBG_EXCEPTION_NOT_HANDLED ? "DBG_EXCEPTION_NOT_HANDLED" :
|
||||||
|
cont_status == DBG_REPLY_LATER ? "DBG_REPLY_LATER" :
|
||||||
|
"DBG_???");
|
||||||
|
|
||||||
return ContinueDebugEvent (last_wait_event.dwProcessId,
|
return ContinueDebugEvent (last_wait_event.dwProcessId,
|
||||||
last_wait_event.dwThreadId,
|
last_wait_event.dwThreadId,
|
||||||
continue_status);
|
cont_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See nat/windows-nat.h. */
|
/* See nat/windows-nat.h. */
|
||||||
@@ -937,6 +944,26 @@ disable_randomization_available ()
|
|||||||
|
|
||||||
/* See windows-nat.h. */
|
/* See windows-nat.h. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
dbg_reply_later_available ()
|
||||||
|
{
|
||||||
|
static int available = -1;
|
||||||
|
if (available == -1)
|
||||||
|
{
|
||||||
|
/* DBG_REPLY_LATER is supported since Windows 10, Version 1507.
|
||||||
|
If supported, this fails with ERROR_INVALID_HANDLE (tested on
|
||||||
|
Win10 and Win11). If not supported, it fails with
|
||||||
|
ERROR_INVALID_PARAMETER (tested on Win7). */
|
||||||
|
if (ContinueDebugEvent (0, 0, DBG_REPLY_LATER))
|
||||||
|
internal_error (_("ContinueDebugEvent call should not "
|
||||||
|
"have succeeded"));
|
||||||
|
available = (GetLastError () != ERROR_INVALID_PARAMETER);
|
||||||
|
}
|
||||||
|
return available;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See windows-nat.h. */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
initialize_loadable ()
|
initialize_loadable ()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,12 +32,34 @@
|
|||||||
namespace windows_nat
|
namespace windows_nat
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct windows_process_info;
|
||||||
|
|
||||||
|
/* The reason for explicitly stopping a thread. Note the enumerators
|
||||||
|
are ordered such that when comparing two stopping_kind's numerical
|
||||||
|
value, the highest should prevail. */
|
||||||
|
enum stopping_kind
|
||||||
|
{
|
||||||
|
/* Not really stopping the thread. */
|
||||||
|
SK_NOT_STOPPING = 0,
|
||||||
|
|
||||||
|
/* We're stopping the thread for internal reasons, the stop should
|
||||||
|
not be reported as an event to the core. */
|
||||||
|
SK_INTERNAL = 1,
|
||||||
|
|
||||||
|
/* We're stopping the thread for external reasons, meaning, the
|
||||||
|
core/user asked us to stop the thread, so we must report a stop
|
||||||
|
event to the core. */
|
||||||
|
SK_EXTERNAL = 2,
|
||||||
|
};
|
||||||
|
|
||||||
/* Thread information structure used to track extra information about
|
/* Thread information structure used to track extra information about
|
||||||
each thread. */
|
each thread. */
|
||||||
struct windows_thread_info
|
struct windows_thread_info
|
||||||
{
|
{
|
||||||
windows_thread_info (DWORD tid_, HANDLE h_, CORE_ADDR tlb)
|
windows_thread_info (windows_process_info *proc_,
|
||||||
: tid (tid_),
|
DWORD tid_, HANDLE h_, CORE_ADDR tlb)
|
||||||
|
: proc (proc_),
|
||||||
|
tid (tid_),
|
||||||
h (h_),
|
h (h_),
|
||||||
thread_local_base (tlb)
|
thread_local_base (tlb)
|
||||||
{
|
{
|
||||||
@@ -56,6 +78,18 @@ struct windows_thread_info
|
|||||||
the next call. */
|
the next call. */
|
||||||
const char *thread_name ();
|
const char *thread_name ();
|
||||||
|
|
||||||
|
/* Read LEN bytes of the thread's $_siginfo into READBUF, starting
|
||||||
|
at OFFSET. Store the number of actually-read bytes in
|
||||||
|
XFERED_LEN. Returns true on success, false on failure. Passing
|
||||||
|
READBUF as NULL indicates that the caller is trying to write to
|
||||||
|
$_siginfo, which is a failure case. */
|
||||||
|
bool xfer_siginfo (gdb_byte *readbuf,
|
||||||
|
ULONGEST offset, ULONGEST len,
|
||||||
|
ULONGEST *xfered_len);
|
||||||
|
|
||||||
|
/* The process this thread belongs to. */
|
||||||
|
windows_process_info *proc;
|
||||||
|
|
||||||
/* The Win32 thread identifier. */
|
/* The Win32 thread identifier. */
|
||||||
DWORD tid;
|
DWORD tid;
|
||||||
|
|
||||||
@@ -65,12 +99,79 @@ struct windows_thread_info
|
|||||||
/* Thread Information Block address. */
|
/* Thread Information Block address. */
|
||||||
CORE_ADDR thread_local_base;
|
CORE_ADDR thread_local_base;
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
/* These two fields are used to handle Cygwin signals. When a
|
||||||
|
thread is signaled, the "sig" thread inside the Cygwin runtime
|
||||||
|
reports the fact to us via a special OutputDebugString message.
|
||||||
|
In order to make stepping into a signal handler work, we can only
|
||||||
|
resume the "sig" thread when we also resume the target signaled
|
||||||
|
thread. When we intercept a Cygwin signal, we set up a cross
|
||||||
|
link between the two threads using the two fields below, so we
|
||||||
|
can always identify one from the other. See the "Cygwin signals"
|
||||||
|
description in gdb/windows-nat.c for more. */
|
||||||
|
|
||||||
|
/* If this thread received a signal, then 'cygwin_sig_thread' points
|
||||||
|
to the "sig" thread within the Cygwin runtime. */
|
||||||
|
windows_thread_info *cygwin_sig_thread = nullptr;
|
||||||
|
|
||||||
|
/* If this thread is the Cygwin runtime's "sig" thread, then
|
||||||
|
'signaled_thread' points at the thread that received a
|
||||||
|
signal. */
|
||||||
|
windows_thread_info *signaled_thread = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If the thread had its event postponed with DBG_REPLY_LATER, when
|
||||||
|
we later ResumeThread this thread, WaitForDebugEvent will
|
||||||
|
re-report the postponed event. This field holds the continue
|
||||||
|
status value to be automatically passed to ContinueDebugEvent
|
||||||
|
when we encounter this re-reported event. 0 if the thread has
|
||||||
|
not had its event postponed with DBG_REPLY_LATER. */
|
||||||
|
DWORD reply_later = 0;
|
||||||
|
|
||||||
/* This keeps track of whether SuspendThread was called on this
|
/* This keeps track of whether SuspendThread was called on this
|
||||||
thread. -1 means there was a failure or that the thread was
|
thread. -1 means there was a failure or that the thread was
|
||||||
explicitly not suspended, 1 means it was called, and 0 means it
|
explicitly not suspended, 1 means it was called, and 0 means it
|
||||||
was not. */
|
was not. */
|
||||||
int suspended = 0;
|
int suspended = 0;
|
||||||
|
|
||||||
|
/* This flag indicates whether we are explicitly stopping this
|
||||||
|
thread in response to a target_stop request or for
|
||||||
|
backend-internal reasons. This allows distinguishing between
|
||||||
|
threads that are explicitly stopped by the debugger and threads
|
||||||
|
that are stopped due to other reasons.
|
||||||
|
|
||||||
|
Typically, when we want to stop a thread, we suspend it, enqueue
|
||||||
|
a pending GDB_SIGNAL_0 stop status on the thread, and then set
|
||||||
|
this flag to true. However, if the thread has had its event
|
||||||
|
previously postponed with DBG_REPLY_LATER, it means that it
|
||||||
|
already has an event to report. In such case, we simply set the
|
||||||
|
'stopping' flag without suspending the thread or enqueueing a
|
||||||
|
pending stop. See stop_one_thread. */
|
||||||
|
stopping_kind stopping = SK_NOT_STOPPING;
|
||||||
|
|
||||||
|
/* Info about a potential pending stop.
|
||||||
|
|
||||||
|
Sometimes, Windows will report a stop on a thread that has been
|
||||||
|
ostensibly suspended. We believe what happens here is that two
|
||||||
|
threads hit a breakpoint simultaneously, and the Windows kernel
|
||||||
|
queues the stop events. However, this can result in the strange
|
||||||
|
effect of trying to single step thread A -- leaving all other
|
||||||
|
threads suspended -- and then seeing a stop in thread B. To handle
|
||||||
|
this scenario, we queue all such "pending" stops here, and then
|
||||||
|
process them once the step has completed. See PR gdb/22992.
|
||||||
|
|
||||||
|
TARGET_WAITKIND_IGNORE if the thread does not have a pending
|
||||||
|
stop. */
|
||||||
|
target_waitstatus pending_status;
|
||||||
|
|
||||||
|
/* The last Windows event returned by WaitForDebugEvent for this
|
||||||
|
thread. */
|
||||||
|
DEBUG_EVENT last_event {};
|
||||||
|
|
||||||
|
/* The last signal reported for this thread, extracted out of
|
||||||
|
last_event. */
|
||||||
|
enum gdb_signal last_sig = GDB_SIGNAL_0;
|
||||||
|
|
||||||
/* The context of the thread, including any manipulations. */
|
/* The context of the thread, including any manipulations. */
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
@@ -84,10 +185,6 @@ struct windows_thread_info
|
|||||||
the thread. */
|
the thread. */
|
||||||
bool debug_registers_changed = false;
|
bool debug_registers_changed = false;
|
||||||
|
|
||||||
/* Nonzero if CONTEXT is invalidated and must be re-read from the
|
|
||||||
inferior thread. */
|
|
||||||
bool reload_context = false;
|
|
||||||
|
|
||||||
/* True if this thread is currently stopped at a software
|
/* True if this thread is currently stopped at a software
|
||||||
breakpoint. This is used to offset the PC when needed. */
|
breakpoint. This is used to offset the PC when needed. */
|
||||||
bool stopped_at_software_breakpoint = false;
|
bool stopped_at_software_breakpoint = false;
|
||||||
@@ -101,34 +198,6 @@ struct windows_thread_info
|
|||||||
gdb::unique_xmalloc_ptr<char> name;
|
gdb::unique_xmalloc_ptr<char> name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Possible values to pass to 'thread_rec'. */
|
|
||||||
enum thread_disposition_type
|
|
||||||
{
|
|
||||||
/* Do not invalidate the thread's context, and do not suspend the
|
|
||||||
thread. */
|
|
||||||
DONT_INVALIDATE_CONTEXT,
|
|
||||||
/* Invalidate the context, but do not suspend the thread. */
|
|
||||||
DONT_SUSPEND,
|
|
||||||
/* Invalidate the context and suspend the thread. */
|
|
||||||
INVALIDATE_CONTEXT
|
|
||||||
};
|
|
||||||
|
|
||||||
/* A single pending stop. See "pending_stops" for more
|
|
||||||
information. */
|
|
||||||
struct pending_stop
|
|
||||||
{
|
|
||||||
/* The thread id. */
|
|
||||||
DWORD thread_id;
|
|
||||||
|
|
||||||
/* The target waitstatus we computed. */
|
|
||||||
target_waitstatus status;
|
|
||||||
|
|
||||||
/* The event. A few fields of this can be referenced after a stop,
|
|
||||||
and it seemed simplest to store the entire event. */
|
|
||||||
DEBUG_EVENT event;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum handle_exception_result
|
enum handle_exception_result
|
||||||
{
|
{
|
||||||
HANDLE_EXCEPTION_UNHANDLED = 0,
|
HANDLE_EXCEPTION_UNHANDLED = 0,
|
||||||
@@ -144,31 +213,8 @@ struct windows_process_info
|
|||||||
{
|
{
|
||||||
/* The process handle */
|
/* The process handle */
|
||||||
HANDLE handle = 0;
|
HANDLE handle = 0;
|
||||||
|
DWORD process_id = 0;
|
||||||
DWORD main_thread_id = 0;
|
DWORD main_thread_id = 0;
|
||||||
enum gdb_signal last_sig = GDB_SIGNAL_0;
|
|
||||||
|
|
||||||
/* The current debug event from WaitForDebugEvent or from a pending
|
|
||||||
stop. */
|
|
||||||
DEBUG_EVENT current_event {};
|
|
||||||
|
|
||||||
/* The ID of the thread for which we anticipate a stop event.
|
|
||||||
Normally this is -1, meaning we'll accept an event in any
|
|
||||||
thread. */
|
|
||||||
DWORD desired_stop_thread_id = -1;
|
|
||||||
|
|
||||||
/* A vector of pending stops. Sometimes, Windows will report a stop
|
|
||||||
on a thread that has been ostensibly suspended. We believe what
|
|
||||||
happens here is that two threads hit a breakpoint simultaneously,
|
|
||||||
and the Windows kernel queues the stop events. However, this can
|
|
||||||
result in the strange effect of trying to single step thread A --
|
|
||||||
leaving all other threads suspended -- and then seeing a stop in
|
|
||||||
thread B. To handle this scenario, we queue all such "pending"
|
|
||||||
stops here, and then process them once the step has completed. See
|
|
||||||
PR gdb/22992. */
|
|
||||||
std::vector<pending_stop> pending_stops;
|
|
||||||
|
|
||||||
/* Contents of $_siginfo */
|
|
||||||
EXCEPTION_RECORD siginfo_er {};
|
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
/* The target is a WOW64 process */
|
/* The target is a WOW64 process */
|
||||||
@@ -177,24 +223,21 @@ struct windows_process_info
|
|||||||
bool ignore_first_breakpoint = false;
|
bool ignore_first_breakpoint = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Find a thread record given a thread id.
|
||||||
/* Find a thread record given a thread id. THREAD_DISPOSITION
|
|
||||||
controls whether the thread is suspended, and whether the context
|
|
||||||
is invalidated.
|
|
||||||
|
|
||||||
This function must be supplied by the embedding application. */
|
This function must be supplied by the embedding application. */
|
||||||
virtual windows_thread_info *thread_rec (ptid_t ptid,
|
virtual windows_thread_info *find_thread (ptid_t ptid) = 0;
|
||||||
thread_disposition_type disposition) = 0;
|
|
||||||
|
|
||||||
/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. Updates
|
/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. Updates
|
||||||
OURSTATUS and returns the thread id if this represents a thread
|
OURSTATUS and returns true if this represents a Cygwin signal,
|
||||||
change (this is specific to Cygwin), otherwise 0.
|
otherwise false.
|
||||||
|
|
||||||
Cygwin prepends its messages with a "cygwin:". Interpret this as
|
Cygwin prepends its messages with a "cygwin:". Interpret this as
|
||||||
a Cygwin signal. Otherwise just print the string as a warning.
|
a Cygwin signal. Otherwise just print the string as a warning.
|
||||||
|
|
||||||
This function must be supplied by the embedding application. */
|
This function must be supplied by the embedding application. */
|
||||||
virtual int handle_output_debug_string (struct target_waitstatus *ourstatus) = 0;
|
virtual bool handle_output_debug_string (const DEBUG_EVENT ¤t_event,
|
||||||
|
struct target_waitstatus *ourstatus) = 0;
|
||||||
|
|
||||||
/* Handle a DLL load event.
|
/* Handle a DLL load event.
|
||||||
|
|
||||||
@@ -215,7 +258,7 @@ struct windows_process_info
|
|||||||
|
|
||||||
This function must be supplied by the embedding application. */
|
This function must be supplied by the embedding application. */
|
||||||
|
|
||||||
virtual void handle_unload_dll () = 0;
|
virtual void handle_unload_dll (const DEBUG_EVENT ¤t_event) = 0;
|
||||||
|
|
||||||
/* When EXCEPTION_ACCESS_VIOLATION is processed, we give the embedding
|
/* When EXCEPTION_ACCESS_VIOLATION is processed, we give the embedding
|
||||||
application a chance to change it to be considered "unhandled".
|
application a chance to change it to be considered "unhandled".
|
||||||
@@ -224,30 +267,26 @@ struct windows_process_info
|
|||||||
|
|
||||||
virtual bool handle_access_violation (const EXCEPTION_RECORD *rec) = 0;
|
virtual bool handle_access_violation (const EXCEPTION_RECORD *rec) = 0;
|
||||||
|
|
||||||
|
/* Fill in the thread's CONTEXT/WOW64_CONTEXT, if it wasn't filled
|
||||||
|
in yet.
|
||||||
|
|
||||||
|
This function must be supplied by the embedding application. */
|
||||||
|
|
||||||
|
virtual void fill_thread_context (windows_thread_info *th) = 0;
|
||||||
|
|
||||||
handle_exception_result handle_exception
|
handle_exception_result handle_exception
|
||||||
(struct target_waitstatus *ourstatus, bool debug_exceptions);
|
(DEBUG_EVENT ¤t_event,
|
||||||
|
struct target_waitstatus *ourstatus, bool debug_exceptions);
|
||||||
|
|
||||||
/* Call to indicate that a DLL was loaded. */
|
/* Call to indicate that a DLL was loaded. */
|
||||||
|
|
||||||
void dll_loaded_event ();
|
void dll_loaded_event (const DEBUG_EVENT ¤t_event);
|
||||||
|
|
||||||
/* Iterate over all DLLs currently mapped by our inferior, and
|
/* Iterate over all DLLs currently mapped by our inferior, and
|
||||||
add them to our list of solibs. */
|
add them to our list of solibs. */
|
||||||
|
|
||||||
void add_all_dlls ();
|
void add_all_dlls ();
|
||||||
|
|
||||||
/* Return true if there is a pending stop matching
|
|
||||||
desired_stop_thread_id. If DEBUG_EVENTS is true, logging will be
|
|
||||||
enabled. */
|
|
||||||
|
|
||||||
bool matching_pending_stop (bool debug_events);
|
|
||||||
|
|
||||||
/* See if a pending stop matches DESIRED_STOP_THREAD_ID. If so,
|
|
||||||
remove it from the list of pending stops, set 'current_event', and
|
|
||||||
return it. Otherwise, return an empty optional. */
|
|
||||||
|
|
||||||
std::optional<pending_stop> fetch_pending_stop (bool debug_events);
|
|
||||||
|
|
||||||
const char *pid_to_exec_file (int);
|
const char *pid_to_exec_file (int);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -258,7 +297,7 @@ private:
|
|||||||
|
|
||||||
Return true if the exception was handled; return false otherwise. */
|
Return true if the exception was handled; return false otherwise. */
|
||||||
|
|
||||||
bool handle_ms_vc_exception (const EXCEPTION_RECORD *rec);
|
bool handle_ms_vc_exception (const DEBUG_EVENT ¤t_event);
|
||||||
|
|
||||||
/* Iterate over all DLLs currently mapped by our inferior, looking for
|
/* Iterate over all DLLs currently mapped by our inferior, looking for
|
||||||
a DLL which is loaded at LOAD_ADDR. If found, add the DLL to our
|
a DLL which is loaded at LOAD_ADDR. If found, add the DLL to our
|
||||||
@@ -289,6 +328,11 @@ private:
|
|||||||
extern BOOL continue_last_debug_event (DWORD continue_status,
|
extern BOOL continue_last_debug_event (DWORD continue_status,
|
||||||
bool debug_events);
|
bool debug_events);
|
||||||
|
|
||||||
|
/* Return the ptid_t of the thread that the last waited-for event was
|
||||||
|
for. */
|
||||||
|
|
||||||
|
extern ptid_t get_last_debug_event_ptid ();
|
||||||
|
|
||||||
/* A simple wrapper for WaitForDebugEvent that also sets the internal
|
/* A simple wrapper for WaitForDebugEvent that also sets the internal
|
||||||
'last_wait_event' on success. */
|
'last_wait_event' on success. */
|
||||||
|
|
||||||
@@ -433,6 +477,15 @@ extern DeleteProcThreadAttributeList_ftype *DeleteProcThreadAttributeList;
|
|||||||
|
|
||||||
extern bool disable_randomization_available ();
|
extern bool disable_randomization_available ();
|
||||||
|
|
||||||
|
/* This is available starting with Windows 10. */
|
||||||
|
#ifndef DBG_REPLY_LATER
|
||||||
|
# define DBG_REPLY_LATER 0x40010001L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Return true if it's possible to use DBG_REPLY_LATER with
|
||||||
|
ContinueDebugEvent on this host. */
|
||||||
|
extern bool dbg_reply_later_available ();
|
||||||
|
|
||||||
/* Load any functions which may not be available in ancient versions
|
/* Load any functions which may not be available in ancient versions
|
||||||
of Windows. */
|
of Windows. */
|
||||||
|
|
||||||
|
|||||||
1799
gdb/windows-nat.c
1799
gdb/windows-nat.c
File diff suppressed because it is too large
Load Diff
@@ -141,18 +141,21 @@ win32_require_context (windows_thread_info *th)
|
|||||||
|
|
||||||
/* See nat/windows-nat.h. */
|
/* See nat/windows-nat.h. */
|
||||||
|
|
||||||
|
void
|
||||||
|
gdbserver_windows_process::fill_thread_context (windows_thread_info *th)
|
||||||
|
{
|
||||||
|
win32_require_context (th);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See nat/windows-nat.h. */
|
||||||
|
|
||||||
windows_thread_info *
|
windows_thread_info *
|
||||||
gdbserver_windows_process::thread_rec
|
gdbserver_windows_process::find_thread (ptid_t ptid)
|
||||||
(ptid_t ptid, thread_disposition_type disposition)
|
|
||||||
{
|
{
|
||||||
thread_info *thread = find_thread_ptid (ptid);
|
thread_info *thread = find_thread_ptid (ptid);
|
||||||
if (thread == NULL)
|
if (thread == nullptr)
|
||||||
return NULL;
|
return nullptr;
|
||||||
|
return (windows_thread_info *) thread_target_data (thread);
|
||||||
windows_thread_info *th = (windows_thread_info *) thread_target_data (thread);
|
|
||||||
if (disposition != DONT_INVALIDATE_CONTEXT)
|
|
||||||
win32_require_context (th);
|
|
||||||
return th;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a thread to the thread list. */
|
/* Add a thread to the thread list. */
|
||||||
@@ -162,7 +165,7 @@ child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
|
|||||||
windows_thread_info *th;
|
windows_thread_info *th;
|
||||||
ptid_t ptid = ptid_t (pid, tid, 0);
|
ptid_t ptid = ptid_t (pid, tid, 0);
|
||||||
|
|
||||||
if ((th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT)))
|
if ((th = windows_process.find_thread (ptid)))
|
||||||
return th;
|
return th;
|
||||||
|
|
||||||
CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb;
|
CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb;
|
||||||
@@ -172,7 +175,7 @@ child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
|
|||||||
if (windows_process.wow64_process)
|
if (windows_process.wow64_process)
|
||||||
base += 2 * 4096; /* page size = 4096 */
|
base += 2 * 4096; /* page size = 4096 */
|
||||||
#endif
|
#endif
|
||||||
th = new windows_thread_info (tid, h, base);
|
th = new windows_thread_info (&windows_process, tid, h, base);
|
||||||
|
|
||||||
add_thread (ptid, th);
|
add_thread (ptid, th);
|
||||||
|
|
||||||
@@ -307,17 +310,12 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
|
|||||||
{
|
{
|
||||||
struct process_info *proc;
|
struct process_info *proc;
|
||||||
|
|
||||||
windows_process.last_sig = GDB_SIGNAL_0;
|
|
||||||
windows_process.handle = proch;
|
windows_process.handle = proch;
|
||||||
|
windows_process.process_id = pid;
|
||||||
windows_process.main_thread_id = 0;
|
windows_process.main_thread_id = 0;
|
||||||
|
|
||||||
windows_process.soft_interrupt_requested = 0;
|
|
||||||
windows_process.faked_breakpoint = 0;
|
|
||||||
windows_process.open_process_used = true;
|
windows_process.open_process_used = true;
|
||||||
|
|
||||||
memset (&windows_process.current_event, 0,
|
|
||||||
sizeof (windows_process.current_event));
|
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
BOOL wow64;
|
BOOL wow64;
|
||||||
if (!IsWow64Process (proch, &wow64))
|
if (!IsWow64Process (proch, &wow64))
|
||||||
@@ -424,24 +422,20 @@ continue_one_thread (thread_info *thread, int thread_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
th->resume ();
|
th->resume ();
|
||||||
|
th->last_sig = GDB_SIGNAL_0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL
|
static BOOL
|
||||||
child_continue (DWORD continue_status, int thread_id)
|
child_continue_for_kill (DWORD continue_status, int thread_id)
|
||||||
{
|
{
|
||||||
windows_process.desired_stop_thread_id = thread_id;
|
|
||||||
if (windows_process.matching_pending_stop (debug_threads))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
/* The inferior will only continue after the ContinueDebugEvent
|
/* The inferior will only continue after the ContinueDebugEvent
|
||||||
call. */
|
call. */
|
||||||
for_each_thread ([&] (thread_info *thread)
|
for_each_thread ([&] (thread_info *thread)
|
||||||
{
|
{
|
||||||
continue_one_thread (thread, thread_id);
|
continue_one_thread (thread, thread_id);
|
||||||
});
|
});
|
||||||
windows_process.faked_breakpoint = 0;
|
|
||||||
|
|
||||||
return continue_last_debug_event (continue_status, debug_threads);
|
return continue_last_debug_event (continue_status, debug_threads);
|
||||||
}
|
}
|
||||||
@@ -452,8 +446,8 @@ child_fetch_inferior_registers (struct regcache *regcache, int r)
|
|||||||
{
|
{
|
||||||
int regno;
|
int regno;
|
||||||
windows_thread_info *th
|
windows_thread_info *th
|
||||||
= windows_process.thread_rec (current_thread_ptid (),
|
= windows_process.find_thread (current_thread_ptid ());
|
||||||
INVALIDATE_CONTEXT);
|
win32_require_context (th);
|
||||||
if (r == -1 || r > NUM_REGS)
|
if (r == -1 || r > NUM_REGS)
|
||||||
child_fetch_inferior_registers (regcache, NUM_REGS);
|
child_fetch_inferior_registers (regcache, NUM_REGS);
|
||||||
else
|
else
|
||||||
@@ -468,8 +462,8 @@ child_store_inferior_registers (struct regcache *regcache, int r)
|
|||||||
{
|
{
|
||||||
int regno;
|
int regno;
|
||||||
windows_thread_info *th
|
windows_thread_info *th
|
||||||
= windows_process.thread_rec (current_thread_ptid (),
|
= windows_process.find_thread (current_thread_ptid ());
|
||||||
INVALIDATE_CONTEXT);
|
win32_require_context (th);
|
||||||
if (r == -1 || r == 0 || r > NUM_REGS)
|
if (r == -1 || r == 0 || r > NUM_REGS)
|
||||||
child_store_inferior_registers (regcache, NUM_REGS);
|
child_store_inferior_registers (regcache, NUM_REGS);
|
||||||
else
|
else
|
||||||
@@ -631,9 +625,10 @@ win32_process_target::attach (unsigned long pid)
|
|||||||
|
|
||||||
/* See nat/windows-nat.h. */
|
/* See nat/windows-nat.h. */
|
||||||
|
|
||||||
int
|
bool
|
||||||
gdbserver_windows_process::handle_output_debug_string
|
gdbserver_windows_process::handle_output_debug_string
|
||||||
(struct target_waitstatus *ourstatus)
|
(const DEBUG_EVENT ¤t_event,
|
||||||
|
struct target_waitstatus *ourstatus)
|
||||||
{
|
{
|
||||||
#define READ_BUFFER_LEN 1024
|
#define READ_BUFFER_LEN 1024
|
||||||
CORE_ADDR addr;
|
CORE_ADDR addr;
|
||||||
@@ -641,7 +636,7 @@ gdbserver_windows_process::handle_output_debug_string
|
|||||||
DWORD nbytes = current_event.u.DebugString.nDebugStringLength;
|
DWORD nbytes = current_event.u.DebugString.nDebugStringLength;
|
||||||
|
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
if (nbytes > READ_BUFFER_LEN)
|
if (nbytes > READ_BUFFER_LEN)
|
||||||
nbytes = READ_BUFFER_LEN;
|
nbytes = READ_BUFFER_LEN;
|
||||||
@@ -660,7 +655,7 @@ gdbserver_windows_process::handle_output_debug_string
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (read_inferior_memory (addr, (unsigned char *) s, nbytes) != 0)
|
if (read_inferior_memory (addr, (unsigned char *) s, nbytes) != 0)
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!startswith (s, "cYg"))
|
if (!startswith (s, "cYg"))
|
||||||
@@ -668,14 +663,14 @@ gdbserver_windows_process::handle_output_debug_string
|
|||||||
if (!server_waiting)
|
if (!server_waiting)
|
||||||
{
|
{
|
||||||
OUTMSG2(("%s", s));
|
OUTMSG2(("%s", s));
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor_output (s);
|
monitor_output (s);
|
||||||
}
|
}
|
||||||
#undef READ_BUFFER_LEN
|
#undef READ_BUFFER_LEN
|
||||||
|
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -688,7 +683,6 @@ win32_clear_inferiors (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for_each_thread (delete_thread_info);
|
for_each_thread (delete_thread_info);
|
||||||
windows_process.siginfo_er.ExceptionCode = 0;
|
|
||||||
clear_inferiors ();
|
clear_inferiors ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -700,16 +694,15 @@ win32_process_target::kill (process_info *process)
|
|||||||
TerminateProcess (windows_process.handle, 0);
|
TerminateProcess (windows_process.handle, 0);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (!child_continue (DBG_CONTINUE, -1))
|
if (!child_continue_for_kill (DBG_CONTINUE, -1))
|
||||||
break;
|
break;
|
||||||
if (!wait_for_debug_event (&windows_process.current_event, INFINITE))
|
DEBUG_EVENT current_event;
|
||||||
|
if (!wait_for_debug_event (¤t_event, INFINITE))
|
||||||
break;
|
break;
|
||||||
if (windows_process.current_event.dwDebugEventCode
|
if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
|
||||||
== EXIT_PROCESS_DEBUG_EVENT)
|
|
||||||
break;
|
break;
|
||||||
else if (windows_process.current_event.dwDebugEventCode
|
else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
|
||||||
== OUTPUT_DEBUG_STRING_EVENT)
|
windows_process.handle_output_debug_string (current_event, nullptr);
|
||||||
windows_process.handle_output_debug_string (nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
win32_clear_inferiors ();
|
win32_clear_inferiors ();
|
||||||
@@ -767,96 +760,108 @@ win32_process_target::thread_alive (ptid_t ptid)
|
|||||||
return find_thread_ptid (ptid) != NULL;
|
return find_thread_ptid (ptid) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
resume_one_thread (thread_info *thread, bool step, gdb_signal sig,
|
||||||
|
DWORD *continue_status)
|
||||||
|
{
|
||||||
|
auto *th = (windows_thread_info *) thread_target_data (thread);
|
||||||
|
|
||||||
|
if (sig != GDB_SIGNAL_0)
|
||||||
|
{
|
||||||
|
/* Allow continuing with the same signal that interrupted us.
|
||||||
|
Otherwise complain. */
|
||||||
|
if (thread->id != get_last_debug_event_ptid ())
|
||||||
|
{
|
||||||
|
/* ContinueDebugEvent will be for a different thread. */
|
||||||
|
OUTMSG (("Cannot continue with signal %d here. "
|
||||||
|
"Not last-event thread", sig));
|
||||||
|
}
|
||||||
|
else if (th->last_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
|
||||||
|
{
|
||||||
|
OUTMSG (("Cannot continue with signal %s here. "
|
||||||
|
"Not stopped for EXCEPTION_DEBUG_EVENT.\n",
|
||||||
|
gdb_signal_to_string (sig)));
|
||||||
|
}
|
||||||
|
else if (sig == th->last_sig)
|
||||||
|
*continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||||
|
else
|
||||||
|
OUTMSG (("Can only continue with received signal %s.\n",
|
||||||
|
gdb_signal_to_string (th->last_sig)));
|
||||||
|
}
|
||||||
|
|
||||||
|
win32_prepare_to_resume (th);
|
||||||
|
|
||||||
|
DWORD *context_flags;
|
||||||
|
#ifdef __x86_64__
|
||||||
|
if (windows_process.wow64_process)
|
||||||
|
context_flags = &th->wow64_context.ContextFlags;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
context_flags = &th->context.ContextFlags;
|
||||||
|
if (*context_flags)
|
||||||
|
{
|
||||||
|
/* Move register values from the inferior into the thread
|
||||||
|
context structure. */
|
||||||
|
regcache_invalidate ();
|
||||||
|
|
||||||
|
if (step)
|
||||||
|
{
|
||||||
|
if (the_low_target.single_step != NULL)
|
||||||
|
(*the_low_target.single_step) (th);
|
||||||
|
else
|
||||||
|
error ("Single stepping is not supported "
|
||||||
|
"in this configuration.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
win32_set_thread_context (th);
|
||||||
|
*context_flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue_one_thread (thread, th->tid);
|
||||||
|
}
|
||||||
|
|
||||||
/* Resume the inferior process. RESUME_INFO describes how we want
|
/* Resume the inferior process. RESUME_INFO describes how we want
|
||||||
to resume. */
|
to resume. */
|
||||||
void
|
void
|
||||||
win32_process_target::resume (thread_resume *resume_info, size_t n)
|
win32_process_target::resume (thread_resume *resume_info, size_t n)
|
||||||
{
|
{
|
||||||
DWORD tid;
|
|
||||||
enum gdb_signal sig;
|
|
||||||
int step;
|
|
||||||
windows_thread_info *th;
|
|
||||||
DWORD continue_status = DBG_CONTINUE;
|
DWORD continue_status = DBG_CONTINUE;
|
||||||
ptid_t ptid;
|
bool any_pending = false;
|
||||||
|
|
||||||
/* This handles the very limited set of resume packets that GDB can
|
for (thread_info *thread : all_threads)
|
||||||
currently produce. */
|
|
||||||
|
|
||||||
if (n == 1 && resume_info[0].thread == minus_one_ptid)
|
|
||||||
tid = -1;
|
|
||||||
else if (n > 1)
|
|
||||||
tid = -1;
|
|
||||||
else
|
|
||||||
/* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make
|
|
||||||
the Windows resume code do the right thing for thread switching. */
|
|
||||||
tid = windows_process.current_event.dwThreadId;
|
|
||||||
|
|
||||||
if (resume_info[0].thread != minus_one_ptid)
|
|
||||||
{
|
{
|
||||||
sig = gdb_signal_from_host (resume_info[0].sig);
|
auto *th = (windows_thread_info *) thread_target_data (thread);
|
||||||
step = resume_info[0].kind == resume_step;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sig = GDB_SIGNAL_0;
|
|
||||||
step = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sig != GDB_SIGNAL_0)
|
for (int ndx = 0; ndx < n; ndx++)
|
||||||
{
|
|
||||||
if (windows_process.current_event.dwDebugEventCode
|
|
||||||
!= EXCEPTION_DEBUG_EVENT)
|
|
||||||
{
|
{
|
||||||
OUTMSG (("Cannot continue with signal %s here.\n",
|
thread_resume &r = resume_info[ndx];
|
||||||
gdb_signal_to_string (sig)));
|
ptid_t ptid = r.thread;
|
||||||
}
|
gdb_signal sig = gdb_signal_from_host (r.sig);
|
||||||
else if (sig == windows_process.last_sig)
|
bool step = r.kind == resume_step;
|
||||||
continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
|
||||||
else
|
|
||||||
OUTMSG (("Can only continue with received signal %s.\n",
|
|
||||||
gdb_signal_to_string (windows_process.last_sig)));
|
|
||||||
}
|
|
||||||
|
|
||||||
windows_process.last_sig = GDB_SIGNAL_0;
|
if (ptid == minus_one_ptid || ptid == thread->id
|
||||||
|
/* Handle both 'pPID' and 'pPID.-1' as meaning 'all threads
|
||||||
/* Get context for the currently selected thread. */
|
of PID'. */
|
||||||
ptid = debug_event_ptid (&windows_process.current_event);
|
|| (ptid.pid () == pid_of (thread)
|
||||||
th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
|
&& (ptid.is_pid () || ptid.lwp () == -1)))
|
||||||
if (th)
|
|
||||||
{
|
|
||||||
win32_prepare_to_resume (th);
|
|
||||||
|
|
||||||
DWORD *context_flags;
|
|
||||||
#ifdef __x86_64__
|
|
||||||
if (windows_process.wow64_process)
|
|
||||||
context_flags = &th->wow64_context.ContextFlags;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
context_flags = &th->context.ContextFlags;
|
|
||||||
if (*context_flags)
|
|
||||||
{
|
|
||||||
/* Move register values from the inferior into the thread
|
|
||||||
context structure. */
|
|
||||||
regcache_invalidate ();
|
|
||||||
|
|
||||||
if (step)
|
|
||||||
{
|
{
|
||||||
if (the_low_target.single_step != NULL)
|
/* Ignore (wildcard) resume requests for already-resumed
|
||||||
(*the_low_target.single_step) (th);
|
threads. */
|
||||||
else
|
if (!th->suspended)
|
||||||
error ("Single stepping is not supported "
|
continue;
|
||||||
"in this configuration.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
win32_set_thread_context (th);
|
resume_one_thread (thread, step, sig, &continue_status);
|
||||||
*context_flags = 0;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!th->suspended
|
||||||
|
&& th->pending_status.kind () != TARGET_WAITKIND_IGNORE)
|
||||||
|
any_pending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allow continuing with the same signal that interrupted us.
|
if (!any_pending)
|
||||||
Otherwise complain. */
|
continue_last_debug_event (continue_status, debug_threads);
|
||||||
|
|
||||||
child_continue (continue_status, tid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See nat/windows-nat.h. */
|
/* See nat/windows-nat.h. */
|
||||||
@@ -916,7 +921,7 @@ gdbserver_windows_process::handle_load_dll (const char *name, LPVOID base)
|
|||||||
/* See nat/windows-nat.h. */
|
/* See nat/windows-nat.h. */
|
||||||
|
|
||||||
void
|
void
|
||||||
gdbserver_windows_process::handle_unload_dll ()
|
gdbserver_windows_process::handle_unload_dll (const DEBUG_EVENT ¤t_event)
|
||||||
{
|
{
|
||||||
CORE_ADDR load_addr =
|
CORE_ADDR load_addr =
|
||||||
(CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll;
|
(CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll;
|
||||||
@@ -936,23 +941,6 @@ suspend_one_thread (thread_info *thread)
|
|||||||
th->suspend ();
|
th->suspend ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
fake_breakpoint_event (void)
|
|
||||||
{
|
|
||||||
OUTMSG2(("fake_breakpoint_event\n"));
|
|
||||||
|
|
||||||
windows_process.faked_breakpoint = 1;
|
|
||||||
|
|
||||||
memset (&windows_process.current_event, 0,
|
|
||||||
sizeof (windows_process.current_event));
|
|
||||||
windows_process.current_event.dwThreadId = windows_process.main_thread_id;
|
|
||||||
windows_process.current_event.dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
|
|
||||||
windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
|
|
||||||
= EXCEPTION_BREAKPOINT;
|
|
||||||
|
|
||||||
for_each_thread (suspend_one_thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See nat/windows-nat.h. */
|
/* See nat/windows-nat.h. */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -967,20 +955,19 @@ gdbserver_windows_process::handle_access_violation
|
|||||||
PC. */
|
PC. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
maybe_adjust_pc ()
|
maybe_adjust_pc (const DEBUG_EVENT ¤t_event)
|
||||||
{
|
{
|
||||||
struct regcache *regcache = get_thread_regcache (current_thread, 1);
|
struct regcache *regcache = get_thread_regcache (current_thread, 1);
|
||||||
child_fetch_inferior_registers (regcache, -1);
|
child_fetch_inferior_registers (regcache, -1);
|
||||||
|
|
||||||
windows_thread_info *th
|
windows_thread_info *th
|
||||||
= windows_process.thread_rec (current_thread_ptid (),
|
= windows_process.find_thread (current_thread_ptid ());
|
||||||
DONT_INVALIDATE_CONTEXT);
|
|
||||||
th->stopped_at_software_breakpoint = false;
|
th->stopped_at_software_breakpoint = false;
|
||||||
|
|
||||||
if (windows_process.current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
|
if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
|
||||||
&& ((windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
|
&& ((current_event.u.Exception.ExceptionRecord.ExceptionCode
|
||||||
== EXCEPTION_BREAKPOINT)
|
== EXCEPTION_BREAKPOINT)
|
||||||
|| (windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
|
|| (current_event.u.Exception.ExceptionRecord.ExceptionCode
|
||||||
== STATUS_WX86_BREAKPOINT))
|
== STATUS_WX86_BREAKPOINT))
|
||||||
&& windows_process.child_initialization_done)
|
&& windows_process.child_initialization_done)
|
||||||
{
|
{
|
||||||
@@ -995,43 +982,39 @@ maybe_adjust_pc ()
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
get_child_debug_event (DWORD *continue_status,
|
get_child_debug_event (DWORD *continue_status,
|
||||||
struct target_waitstatus *ourstatus)
|
struct target_waitstatus *ourstatus,
|
||||||
|
DEBUG_EVENT *current_event)
|
||||||
{
|
{
|
||||||
ptid_t ptid;
|
ptid_t ptid;
|
||||||
|
|
||||||
windows_process.last_sig = GDB_SIGNAL_0;
|
|
||||||
ourstatus->set_spurious ();
|
ourstatus->set_spurious ();
|
||||||
*continue_status = DBG_CONTINUE;
|
*continue_status = DBG_CONTINUE;
|
||||||
|
|
||||||
/* Check if GDB sent us an interrupt request. */
|
/* Check if GDB sent us an interrupt request. */
|
||||||
check_remote_input_interrupt_request ();
|
check_remote_input_interrupt_request ();
|
||||||
|
|
||||||
DEBUG_EVENT *current_event = &windows_process.current_event;
|
|
||||||
|
|
||||||
if (windows_process.soft_interrupt_requested)
|
|
||||||
{
|
|
||||||
windows_process.soft_interrupt_requested = 0;
|
|
||||||
fake_breakpoint_event ();
|
|
||||||
goto gotevent;
|
|
||||||
}
|
|
||||||
|
|
||||||
windows_process.attaching = 0;
|
windows_process.attaching = 0;
|
||||||
{
|
{
|
||||||
std::optional<pending_stop> stop
|
for (thread_info *thread : all_threads)
|
||||||
= windows_process.fetch_pending_stop (debug_threads);
|
|
||||||
if (stop.has_value ())
|
|
||||||
{
|
{
|
||||||
*ourstatus = stop->status;
|
auto *th = (windows_thread_info *) thread_target_data (thread);
|
||||||
windows_process.current_event = stop->event;
|
|
||||||
ptid = debug_event_ptid (&windows_process.current_event);
|
if (!th->suspended
|
||||||
switch_to_thread (find_thread_ptid (ptid));
|
&& th->pending_status.kind () != TARGET_WAITKIND_IGNORE)
|
||||||
return 1;
|
{
|
||||||
|
*ourstatus = th->pending_status;
|
||||||
|
th->pending_status.set_ignore ();
|
||||||
|
*current_event = th->last_event;
|
||||||
|
ptid = debug_event_ptid (current_event);
|
||||||
|
switch_to_thread (find_thread_ptid (ptid));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep the wait time low enough for comfortable remote
|
/* Keep the wait time low enough for comfortable remote
|
||||||
interruption, but high enough so gdbserver doesn't become a
|
interruption, but high enough so gdbserver doesn't become a
|
||||||
bottleneck. */
|
bottleneck. */
|
||||||
if (!wait_for_debug_event (&windows_process.current_event, 250))
|
if (!wait_for_debug_event (current_event, 250))
|
||||||
{
|
{
|
||||||
DWORD e = GetLastError();
|
DWORD e = GetLastError();
|
||||||
|
|
||||||
@@ -1049,8 +1032,6 @@ get_child_debug_event (DWORD *continue_status,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gotevent:
|
|
||||||
|
|
||||||
switch (current_event->dwDebugEventCode)
|
switch (current_event->dwDebugEventCode)
|
||||||
{
|
{
|
||||||
case CREATE_THREAD_DEBUG_EVENT:
|
case CREATE_THREAD_DEBUG_EVENT:
|
||||||
@@ -1117,7 +1098,7 @@ get_child_debug_event (DWORD *continue_status,
|
|||||||
else
|
else
|
||||||
ourstatus->set_signalled (gdb_signal_from_host (exit_signal));
|
ourstatus->set_signalled (gdb_signal_from_host (exit_signal));
|
||||||
}
|
}
|
||||||
child_continue (DBG_CONTINUE, windows_process.desired_stop_thread_id);
|
continue_last_debug_event (DBG_CONTINUE, debug_threads);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOAD_DLL_DEBUG_EVENT:
|
case LOAD_DLL_DEBUG_EVENT:
|
||||||
@@ -1128,7 +1109,7 @@ get_child_debug_event (DWORD *continue_status,
|
|||||||
CloseHandle (current_event->u.LoadDll.hFile);
|
CloseHandle (current_event->u.LoadDll.hFile);
|
||||||
if (! windows_process.child_initialization_done)
|
if (! windows_process.child_initialization_done)
|
||||||
break;
|
break;
|
||||||
windows_process.dll_loaded_event ();
|
windows_process.dll_loaded_event (*current_event);
|
||||||
|
|
||||||
ourstatus->set_loaded ();
|
ourstatus->set_loaded ();
|
||||||
break;
|
break;
|
||||||
@@ -1140,7 +1121,7 @@ get_child_debug_event (DWORD *continue_status,
|
|||||||
(unsigned) current_event->dwThreadId));
|
(unsigned) current_event->dwThreadId));
|
||||||
if (! windows_process.child_initialization_done)
|
if (! windows_process.child_initialization_done)
|
||||||
break;
|
break;
|
||||||
windows_process.handle_unload_dll ();
|
windows_process.handle_unload_dll (*current_event);
|
||||||
ourstatus->set_loaded ();
|
ourstatus->set_loaded ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1149,7 +1130,8 @@ get_child_debug_event (DWORD *continue_status,
|
|||||||
"for pid=%u tid=%x\n",
|
"for pid=%u tid=%x\n",
|
||||||
(unsigned) current_event->dwProcessId,
|
(unsigned) current_event->dwProcessId,
|
||||||
(unsigned) current_event->dwThreadId));
|
(unsigned) current_event->dwThreadId));
|
||||||
if (windows_process.handle_exception (ourstatus, debug_threads)
|
if (windows_process.handle_exception (*current_event,
|
||||||
|
ourstatus, debug_threads)
|
||||||
== HANDLE_EXCEPTION_UNHANDLED)
|
== HANDLE_EXCEPTION_UNHANDLED)
|
||||||
*continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
*continue_status = DBG_EXCEPTION_NOT_HANDLED;
|
||||||
break;
|
break;
|
||||||
@@ -1160,7 +1142,7 @@ get_child_debug_event (DWORD *continue_status,
|
|||||||
"for pid=%u tid=%x\n",
|
"for pid=%u tid=%x\n",
|
||||||
(unsigned) current_event->dwProcessId,
|
(unsigned) current_event->dwProcessId,
|
||||||
(unsigned) current_event->dwThreadId));
|
(unsigned) current_event->dwThreadId));
|
||||||
windows_process.handle_output_debug_string (nullptr);
|
windows_process.handle_output_debug_string (*current_event, nullptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -1172,19 +1154,22 @@ get_child_debug_event (DWORD *continue_status,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptid = debug_event_ptid (&windows_process.current_event);
|
ptid = debug_event_ptid (current_event);
|
||||||
|
|
||||||
if (windows_process.desired_stop_thread_id != -1
|
windows_thread_info *th = windows_process.find_thread (ptid);
|
||||||
&& windows_process.desired_stop_thread_id != ptid.lwp ())
|
|
||||||
|
th->last_event = *current_event;
|
||||||
|
|
||||||
|
if (th != nullptr && th->suspended)
|
||||||
{
|
{
|
||||||
/* Pending stop. See the comment by the definition of
|
/* Pending stop. See the comment by the definition of
|
||||||
"pending_stops" for details on why this is needed. */
|
"windows_thread_info::pending_status" for details on why this
|
||||||
|
is needed. */
|
||||||
OUTMSG2 (("get_windows_debug_event - "
|
OUTMSG2 (("get_windows_debug_event - "
|
||||||
"unexpected stop in 0x%lx (expecting 0x%x)\n",
|
"unexpected stop in suspended thread 0x%x\n",
|
||||||
ptid.lwp (), windows_process.desired_stop_thread_id));
|
th->tid));
|
||||||
maybe_adjust_pc ();
|
maybe_adjust_pc (*current_event);
|
||||||
windows_process.pending_stops.push_back
|
th->pending_status = *ourstatus;
|
||||||
({(DWORD) ptid.lwp (), *ourstatus, *current_event});
|
|
||||||
ourstatus->set_spurious ();
|
ourstatus->set_spurious ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1208,13 +1193,16 @@ win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
|
|||||||
fails). Report it now. */
|
fails). Report it now. */
|
||||||
*ourstatus = windows_process.cached_status;
|
*ourstatus = windows_process.cached_status;
|
||||||
windows_process.cached_status.set_ignore ();
|
windows_process.cached_status.set_ignore ();
|
||||||
return debug_event_ptid (&windows_process.current_event);
|
return ptid_t (windows_process.process_id,
|
||||||
|
windows_process.main_thread_id, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
DWORD continue_status;
|
DWORD continue_status;
|
||||||
if (!get_child_debug_event (&continue_status, ourstatus))
|
DEBUG_EVENT current_event;
|
||||||
|
if (!get_child_debug_event (&continue_status, ourstatus,
|
||||||
|
¤t_event))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch (ourstatus->kind ())
|
switch (ourstatus->kind ())
|
||||||
@@ -1223,15 +1211,20 @@ win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
|
|||||||
OUTMSG2 (("Child exited with retcode = %x\n",
|
OUTMSG2 (("Child exited with retcode = %x\n",
|
||||||
ourstatus->exit_status ()));
|
ourstatus->exit_status ()));
|
||||||
win32_clear_inferiors ();
|
win32_clear_inferiors ();
|
||||||
return ptid_t (windows_process.current_event.dwProcessId);
|
return ptid_t (windows_process.process_id);
|
||||||
case TARGET_WAITKIND_STOPPED:
|
case TARGET_WAITKIND_STOPPED:
|
||||||
case TARGET_WAITKIND_SIGNALLED:
|
case TARGET_WAITKIND_SIGNALLED:
|
||||||
case TARGET_WAITKIND_LOADED:
|
case TARGET_WAITKIND_LOADED:
|
||||||
{
|
{
|
||||||
OUTMSG2 (("Child Stopped with signal = %d \n",
|
OUTMSG2 (("Child Stopped with signal = %d \n",
|
||||||
ourstatus->sig ()));
|
ourstatus->sig ()));
|
||||||
maybe_adjust_pc ();
|
maybe_adjust_pc (current_event);
|
||||||
return debug_event_ptid (&windows_process.current_event);
|
|
||||||
|
/* All-stop, suspend all threads until they are explicitly
|
||||||
|
resumed. */
|
||||||
|
for_each_thread (suspend_one_thread);
|
||||||
|
|
||||||
|
return debug_event_ptid (¤t_event);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
OUTMSG (("Ignoring unknown internal event, %d\n",
|
OUTMSG (("Ignoring unknown internal event, %d\n",
|
||||||
@@ -1239,8 +1232,7 @@ win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
|
|||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case TARGET_WAITKIND_SPURIOUS:
|
case TARGET_WAITKIND_SPURIOUS:
|
||||||
/* do nothing, just continue */
|
/* do nothing, just continue */
|
||||||
child_continue (continue_status,
|
continue_last_debug_event (continue_status, debug_threads);
|
||||||
windows_process.desired_stop_thread_id);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1298,8 +1290,7 @@ win32_process_target::request_interrupt ()
|
|||||||
if (DebugBreakProcess (windows_process.handle))
|
if (DebugBreakProcess (windows_process.handle))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Last resort, suspend all threads manually. */
|
OUTMSG2 (("Could not interrupt.\n"));
|
||||||
windows_process.soft_interrupt_requested = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -1322,45 +1313,14 @@ win32_process_target::qxfer_siginfo (const char *annex,
|
|||||||
unsigned const char *writebuf,
|
unsigned const char *writebuf,
|
||||||
CORE_ADDR offset, int len)
|
CORE_ADDR offset, int len)
|
||||||
{
|
{
|
||||||
if (windows_process.siginfo_er.ExceptionCode == 0)
|
windows_thread_info *th
|
||||||
|
= windows_process.find_thread (current_thread_ptid ());
|
||||||
|
|
||||||
|
ULONGEST xfered_len;
|
||||||
|
if (th->xfer_siginfo (readbuf, offset, len, &xfered_len))
|
||||||
|
return xfered_len;
|
||||||
|
else
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (readbuf == nullptr)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
char *buf = (char *) &windows_process.siginfo_er;
|
|
||||||
size_t bufsize = sizeof (windows_process.siginfo_er);
|
|
||||||
|
|
||||||
#ifdef __x86_64__
|
|
||||||
EXCEPTION_RECORD32 er32;
|
|
||||||
if (windows_process.wow64_process)
|
|
||||||
{
|
|
||||||
buf = (char *) &er32;
|
|
||||||
bufsize = sizeof (er32);
|
|
||||||
|
|
||||||
er32.ExceptionCode = windows_process.siginfo_er.ExceptionCode;
|
|
||||||
er32.ExceptionFlags = windows_process.siginfo_er.ExceptionFlags;
|
|
||||||
er32.ExceptionRecord
|
|
||||||
= (uintptr_t) windows_process.siginfo_er.ExceptionRecord;
|
|
||||||
er32.ExceptionAddress
|
|
||||||
= (uintptr_t) windows_process.siginfo_er.ExceptionAddress;
|
|
||||||
er32.NumberParameters = windows_process.siginfo_er.NumberParameters;
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
|
|
||||||
er32.ExceptionInformation[i]
|
|
||||||
= windows_process.siginfo_er.ExceptionInformation[i];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (offset > bufsize)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (offset + len > bufsize)
|
|
||||||
len = bufsize - offset;
|
|
||||||
|
|
||||||
memcpy (readbuf, buf + offset, len);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -1374,8 +1334,7 @@ win32_process_target::supports_get_tib_address ()
|
|||||||
int
|
int
|
||||||
win32_process_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr)
|
win32_process_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr)
|
||||||
{
|
{
|
||||||
windows_thread_info *th;
|
windows_thread_info *th = windows_process.find_thread (ptid);
|
||||||
th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
|
|
||||||
if (th == NULL)
|
if (th == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
if (addr != NULL)
|
if (addr != NULL)
|
||||||
@@ -1396,8 +1355,7 @@ bool
|
|||||||
win32_process_target::stopped_by_sw_breakpoint ()
|
win32_process_target::stopped_by_sw_breakpoint ()
|
||||||
{
|
{
|
||||||
windows_thread_info *th
|
windows_thread_info *th
|
||||||
= windows_process.thread_rec (current_thread_ptid (),
|
= windows_process.find_thread (current_thread_ptid ());
|
||||||
DONT_INVALIDATE_CONTEXT);
|
|
||||||
return th == nullptr ? false : th->stopped_at_software_breakpoint;
|
return th == nullptr ? false : th->stopped_at_software_breakpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1423,8 +1381,7 @@ const char *
|
|||||||
win32_process_target::thread_name (ptid_t thread)
|
win32_process_target::thread_name (ptid_t thread)
|
||||||
{
|
{
|
||||||
windows_thread_info *th
|
windows_thread_info *th
|
||||||
= windows_process.thread_rec (current_thread_ptid (),
|
= windows_process.find_thread (current_thread_ptid ());
|
||||||
DONT_INVALIDATE_CONTEXT);
|
|
||||||
return th->thread_name ();
|
return th->thread_name ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -174,14 +174,15 @@ public:
|
|||||||
|
|
||||||
struct gdbserver_windows_process : public windows_nat::windows_process_info
|
struct gdbserver_windows_process : public windows_nat::windows_process_info
|
||||||
{
|
{
|
||||||
windows_nat::windows_thread_info *thread_rec
|
windows_nat::windows_thread_info *find_thread (ptid_t ptid) override;
|
||||||
(ptid_t ptid,
|
bool handle_output_debug_string (const DEBUG_EVENT ¤t_event,
|
||||||
windows_nat::thread_disposition_type disposition) override;
|
struct target_waitstatus *ourstatus) override;
|
||||||
int handle_output_debug_string (struct target_waitstatus *ourstatus) override;
|
|
||||||
void handle_load_dll (const char *dll_name, LPVOID base) override;
|
void handle_load_dll (const char *dll_name, LPVOID base) override;
|
||||||
void handle_unload_dll () override;
|
void handle_unload_dll (const DEBUG_EVENT ¤t_event) override;
|
||||||
bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
|
bool handle_access_violation (const EXCEPTION_RECORD *rec) override;
|
||||||
|
|
||||||
|
void fill_thread_context (windows_nat::windows_thread_info *th) override;
|
||||||
|
|
||||||
int attaching = 0;
|
int attaching = 0;
|
||||||
|
|
||||||
/* A status that hasn't been reported to the core yet, and so
|
/* A status that hasn't been reported to the core yet, and so
|
||||||
@@ -189,14 +190,6 @@ struct gdbserver_windows_process : public windows_nat::windows_process_info
|
|||||||
debug event off the win32 API. */
|
debug event off the win32 API. */
|
||||||
struct target_waitstatus cached_status;
|
struct target_waitstatus cached_status;
|
||||||
|
|
||||||
/* Non zero if an interrupt request is to be satisfied by suspending
|
|
||||||
all threads. */
|
|
||||||
int soft_interrupt_requested = 0;
|
|
||||||
|
|
||||||
/* Non zero if the inferior is stopped in a simulated breakpoint done
|
|
||||||
by suspending all the threads. */
|
|
||||||
int faked_breakpoint = 0;
|
|
||||||
|
|
||||||
/* True if current_process_handle needs to be closed. */
|
/* True if current_process_handle needs to be closed. */
|
||||||
bool open_process_used = false;
|
bool open_process_used = false;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user