/* Low level interface to Windows debugging, for gdbserver.
- Copyright (C) 2006-2015 Free Software Foundation, Inc.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
Contributed by Leo Zayas. Based on "win32-nat.c" from GDB.
#include "gdbthread.h"
#include "dll.h"
#include "hostio.h"
-
-#include <stdint.h>
#include <windows.h>
#include <winnt.h>
#include <imagehlp.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <process.h>
+#include "gdb_tilde_expand.h"
+#include "common-inferior.h"
#ifndef USE_WIN32API
#include <sys/cygwin.h>
static ptid_t
debug_event_ptid (DEBUG_EVENT *event)
{
- return ptid_build (event->dwProcessId, event->dwThreadId, 0);
+ return ptid_t (event->dwProcessId, event->dwThreadId, 0);
}
/* Get the thread context of the thread associated with TH. */
static win32_thread_info *
thread_rec (ptid_t ptid, int get_context)
{
- struct thread_info *thread;
- win32_thread_info *th;
-
- thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
+ thread_info *thread = find_thread_ptid (ptid);
if (thread == NULL)
return NULL;
- th = inferior_target_data (thread);
+ win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
if (get_context)
win32_require_context (th);
return th;
child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
{
win32_thread_info *th;
- ptid_t ptid = ptid_build (pid, tid, 0);
+ ptid_t ptid = ptid_t (pid, tid, 0);
if ((th = thread_rec (ptid, FALSE)))
return th;
- th = xcalloc (1, sizeof (*th));
+ th = XCNEW (win32_thread_info);
th->tid = tid;
th->h = h;
th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb;
/* Delete a thread from the list of threads. */
static void
-delete_thread_info (struct inferior_list_entry *thread)
+delete_thread_info (thread_info *thread)
{
- win32_thread_info *th = inferior_target_data ((struct thread_info *) thread);
+ win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
- remove_thread ((struct thread_info *) thread);
+ remove_thread (thread);
CloseHandle (th->h);
free (th);
}
static void
child_delete_thread (DWORD pid, DWORD tid)
{
- struct inferior_list_entry *thread;
- ptid_t ptid;
-
/* If the last thread is exiting, just return. */
- if (one_inferior_p (&all_threads))
+ if (all_threads.size () == 1)
return;
- ptid = ptid_build (pid, tid, 0);
- thread = find_inferior_id (&all_threads, ptid);
+ thread_info *thread = find_thread_ptid (ptid_t (pid, tid));
if (thread == NULL)
return;
static void
child_init_thread_list (void)
{
- for_each_inferior (&all_threads, delete_thread_info);
+ for_each_thread (delete_thread_info);
}
/* Zero during the child initialization phase, and nonzero otherwise. */
/* Resume all artificially suspended threads if we are continuing
execution. */
-static int
-continue_one_thread (struct inferior_list_entry *this_thread, void *id_ptr)
+static void
+continue_one_thread (thread_info *thread, int thread_id)
{
- struct thread_info *thread = (struct thread_info *) this_thread;
- int thread_id = * (int *) id_ptr;
- win32_thread_info *th = inferior_target_data (thread);
+ win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
if (thread_id == -1 || thread_id == th->tid)
{
th->suspended = 0;
}
}
-
- return 0;
}
static BOOL
{
/* The inferior will only continue after the ContinueDebugEvent
call. */
- find_inferior (&all_threads, continue_one_thread, &thread_id);
+ for_each_thread ([&] (thread_info *thread)
+ {
+ continue_one_thread (thread, thread_id);
+ });
faked_breakpoint = 0;
if (!ContinueDebugEvent (current_event.dwProcessId,
NULL,
error,
0, /* Default language */
- (LPVOID)&msgbuf,
+ (LPTSTR) &msgbuf,
0,
NULL);
if (chars != 0)
create_process (const char *program, char *args,
DWORD flags, PROCESS_INFORMATION *pi)
{
+ const char *inferior_cwd = get_inferior_cwd ();
BOOL ret;
#ifdef _WIN32_WCE
- wchar_t *p, *wprogram, *wargs;
+ wchar_t *p, *wprogram, *wargs, *wcwd = NULL;
size_t argslen;
wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t));
wargs = alloca ((argslen + 1) * sizeof (wchar_t));
mbstowcs (wargs, args, argslen + 1);
+ if (inferior_cwd != NULL)
+ {
+ std::string expanded_infcwd = gdb_tilde_expand (inferior_cwd);
+ std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
+ '/', '\\');
+ wcwd = alloca ((expanded_infcwd.size () + 1) * sizeof (wchar_t));
+ if (mbstowcs (wcwd, expanded_infcwd.c_str (),
+ expanded_infcwd.size () + 1) == NULL)
+ {
+ error (_("\
+Could not convert the expanded inferior cwd to wide-char."));
+ }
+ }
+
ret = CreateProcessW (wprogram, /* image name */
wargs, /* command line */
NULL, /* security, not supported */
FALSE, /* inherit handles, not supported */
flags, /* start flags */
NULL, /* environment, not supported */
- NULL, /* current directory, not supported */
+ wcwd, /* current directory */
NULL, /* start info, not supported */
pi); /* proc info */
#else
TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
- NULL, /* current directory */
+ /* current directory */
+ (inferior_cwd == NULL
+ ? NULL
+ : gdb_tilde_expand (inferior_cwd).c_str()),
&si, /* start info */
pi); /* proc info */
#endif
}
/* Start a new process.
- PROGRAM is a path to the program to execute.
- ARGS is a standard NULL-terminated array of arguments,
- to be passed to the inferior as ``argv''.
+ PROGRAM is the program name.
+ PROGRAM_ARGS is the vector containing the inferior's args.
Returns the new PID on success, -1 on failure. Registers the new
process with the process list. */
static int
-win32_create_inferior (char *program, char **program_args)
+win32_create_inferior (const char *program,
+ const std::vector<char *> &program_args)
{
+ client_state &cs = get_client_state ();
#ifndef USE_WIN32API
char real_path[PATH_MAX];
char *orig_path, *new_path, *path_ptr;
#endif
BOOL ret;
DWORD flags;
- char *args;
- int argslen;
- int argc;
PROCESS_INFORMATION pi;
DWORD err;
+ std::string str_program_args = stringify_argv (program_args);
+ char *args = (char *) str_program_args.c_str ();
/* win32_wait needs to know we're not attaching. */
attaching = 0;
if (path_ptr)
{
int size = cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, NULL, 0);
- orig_path = alloca (strlen (path_ptr) + 1);
- new_path = alloca (size);
+ orig_path = (char *) alloca (strlen (path_ptr) + 1);
+ new_path = (char *) alloca (size);
strcpy (orig_path, path_ptr);
cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, new_path, size);
setenv ("PATH", new_path, 1);
program = real_path;
#endif
- argslen = 1;
- for (argc = 1; program_args[argc]; argc++)
- argslen += strlen (program_args[argc]) + 1;
- args = alloca (argslen);
- args[0] = '\0';
- for (argc = 1; program_args[argc]; argc++)
- {
- /* FIXME: Can we do better about quoting? How does Cygwin
- handle this? */
- strcat (args, " ");
- strcat (args, program_args[argc]);
- }
OUTMSG2 (("Command line is \"%s\"\n", args));
#ifdef CREATE_NEW_PROCESS_GROUP
err = GetLastError ();
if (!ret && err == ERROR_FILE_NOT_FOUND)
{
- char *exename = alloca (strlen (program) + 5);
+ char *exename = (char *) alloca (strlen (program) + 5);
strcat (strcpy (exename, program), ".exe");
ret = create_process (exename, args, flags, &pi);
err = GetLastError ();
do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
+ /* Wait till we are at 1st instruction in program, return new pid
+ (assuming success). */
+ cs.last_ptid = win32_wait (ptid_t (current_process_id), &cs.last_status, 0);
+
return current_process_id;
}
/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. */
static void
-handle_output_debug_string (struct target_waitstatus *ourstatus)
+handle_output_debug_string (void)
{
#define READ_BUFFER_LEN 1024
CORE_ADDR addr;
if (current_process_handle != NULL)
CloseHandle (current_process_handle);
- for_each_inferior (&all_threads, delete_thread_info);
+ for_each_thread (delete_thread_info);
clear_inferiors ();
}
-/* Kill all inferiors. */
+/* Implementation of target_ops::kill. */
+
static int
-win32_kill (int pid)
+win32_kill (process_info *process)
{
- struct process_info *process;
-
- if (current_process_handle == NULL)
- return -1;
-
TerminateProcess (current_process_handle, 0);
for (;;)
{
if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
break;
else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
- {
- struct target_waitstatus our_status = { 0 };
- handle_output_debug_string (&our_status);
- }
+ handle_output_debug_string ();
}
win32_clear_inferiors ();
- process = find_process_pid (pid);
remove_process (process);
return 0;
}
-/* Detach from inferior PID. */
+/* Implementation of target_ops::detach. */
+
static int
-win32_detach (int pid)
+win32_detach (process_info *process)
{
- struct process_info *process;
winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL;
winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
#ifdef _WIN32_WCE
return -1;
DebugSetProcessKillOnExit (FALSE);
- process = find_process_pid (pid);
remove_process (process);
win32_clear_inferiors ();
remove_process (process);
}
-/* Wait for inferiors to end. */
+/* Implementation of target_ops::join. */
+
static void
-win32_join (int pid)
+win32_join (process_info *proc)
{
- HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
+ HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, proc->pid);
if (h != NULL)
{
WaitForSingleObject (h, INFINITE);
static int
win32_thread_alive (ptid_t ptid)
{
- int res;
-
/* Our thread list is reliable; don't bother to poll target
threads. */
- if (find_inferior_id (&all_threads, ptid) != NULL)
- res = 1;
- else
- res = 0;
- return res;
+ return find_thread_ptid (ptid) != NULL;
}
/* Resume the inferior process. RESUME_INFO describes how we want
/* This handles the very limited set of resume packets that GDB can
currently produce. */
- if (n == 1 && ptid_equal (resume_info[0].thread, minus_one_ptid))
+ if (n == 1 && resume_info[0].thread == minus_one_ptid)
tid = -1;
else if (n > 1)
tid = -1;
the Windows resume code do the right thing for thread switching. */
tid = current_event.dwThreadId;
- if (!ptid_equal (resume_info[0].thread, minus_one_ptid))
+ if (resume_info[0].thread != minus_one_ptid)
{
- sig = resume_info[0].sig;
+ sig = gdb_signal_from_host (resume_info[0].sig);
step = resume_info[0].kind == resume_step;
}
else
{
- sig = 0;
+ sig = GDB_SIGNAL_0;
step = 0;
}
{
if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
{
- OUTMSG (("Cannot continue with signal %d here.\n", sig));
+ OUTMSG (("Cannot continue with signal %s here.\n",
+ gdb_signal_to_string (sig)));
}
else if (sig == last_sig)
continue_status = DBG_EXCEPTION_NOT_HANDLED;
else
- OUTMSG (("Can only continue with recieved signal %d.\n", last_sig));
+ OUTMSG (("Can only continue with received signal %s.\n",
+ gdb_signal_to_string (last_sig)));
}
last_sig = GDB_SIGNAL_0;
ReadProcessMemory (h, address_ptr, buf, len, &done);
else
{
- WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR));
+ WCHAR *unicode_address = XALLOCAVEC (WCHAR, len);
ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR),
&done);
static void
-suspend_one_thread (struct inferior_list_entry *entry)
+suspend_one_thread (thread_info *thread)
{
- struct thread_info *thread = (struct thread_info *) entry;
- win32_thread_info *th = inferior_target_data (thread);
+ win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
if (!th->suspended)
{
current_event.u.Exception.ExceptionRecord.ExceptionCode
= EXCEPTION_BREAKPOINT;
- for_each_inferior (&all_threads, suspend_one_thread);
+ for_each_thread (suspend_one_thread);
}
#ifdef _WIN32_WCE
child_delete_thread (current_event.dwProcessId,
current_event.dwThreadId);
- current_thread = (struct thread_info *) all_threads.head;
+ current_thread = get_first_thread ();
return 1;
case CREATE_PROCESS_DEBUG_EVENT:
current_process_handle = current_event.u.CreateProcessInfo.hProcess;
main_thread_id = current_event.dwThreadId;
- ourstatus->kind = TARGET_WAITKIND_EXECD;
- ourstatus->value.execd_pathname = "Main executable";
-
/* Add the main thread. */
child_add_thread (current_event.dwProcessId,
main_thread_id,
current_event.u.CreateProcessInfo.hThread,
current_event.u.CreateProcessInfo.lpThreadLocalBase);
- ourstatus->value.related_pid = debug_event_ptid (¤t_event);
#ifdef _WIN32_WCE
if (!attaching)
{
"for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
- handle_output_debug_string (ourstatus);
+ handle_output_debug_string ();
break;
default:
}
ptid = debug_event_ptid (¤t_event);
- current_thread =
- (struct thread_info *) find_inferior_id (&all_threads, ptid);
+ current_thread = find_thread_ptid (ptid);
return 1;
}
OUTMSG2 (("Child exited with retcode = %x\n",
ourstatus->value.integer));
win32_clear_inferiors ();
- return pid_to_ptid (current_event.dwProcessId);
+ return ptid_t (current_event.dwProcessId);
case TARGET_WAITKIND_STOPPED:
case TARGET_WAITKIND_LOADED:
OUTMSG2 (("Child Stopped with signal = %d \n",
OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
/* fall-through */
case TARGET_WAITKIND_SPURIOUS:
- case TARGET_WAITKIND_EXECD:
/* do nothing, just continue */
child_continue (DBG_CONTINUE, -1);
break;
return 1;
}
+/* Implementation of the target_ops method "sw_breakpoint_from_kind". */
+
+static const gdb_byte *
+win32_sw_breakpoint_from_kind (int kind, int *size)
+{
+ *size = the_low_target.breakpoint_len;
+ return the_low_target.breakpoint;
+}
+
static struct target_ops win32_target_ops = {
win32_create_inferior,
+ NULL, /* post_create_inferior */
win32_attach,
win32_kill,
win32_detach,
NULL, /* supports_stopped_by_sw_breakpoint */
NULL, /* stopped_by_hw_breakpoint */
NULL, /* supports_stopped_by_hw_breakpoint */
- /* Although win32-i386 has hardware single step, still disable this
- feature for win32, because it is implemented in linux-low.c instead
- of in generic code. */
- NULL, /* supports_conditional_breakpoints */
+ target_can_do_hardware_single_step,
win32_stopped_by_watchpoint,
win32_stopped_data_address,
NULL, /* read_offsets */
NULL, /* supports_multi_process */
NULL, /* supports_fork_events */
NULL, /* supports_vfork_events */
+ NULL, /* supports_exec_events */
NULL, /* handle_new_gdb_connection */
NULL, /* handle_monitor_command */
NULL, /* core_of_thread */
NULL, /* read_pc */
NULL, /* write_pc */
NULL, /* thread_stopped */
- win32_get_tib_address
+ win32_get_tib_address,
+ NULL, /* pause_all */
+ NULL, /* unpause_all */
+ NULL, /* stabilize_threads */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* supports_disable_randomization */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* qxfer_libraries_svr4 */
+ NULL, /* support_agent */
+ NULL, /* enable_btrace */
+ NULL, /* disable_btrace */
+ NULL, /* read_btrace */
+ NULL, /* read_btrace_conf */
+ NULL, /* supports_range_stepping */
+ NULL, /* pid_to_exec_file */
+ NULL, /* multifs_open */
+ NULL, /* multifs_unlink */
+ NULL, /* multifs_readlink */
+ NULL, /* breakpoint_kind_from_pc */
+ win32_sw_breakpoint_from_kind,
};
/* Initialize the Win32 backend. */
initialize_low (void)
{
set_target_ops (&win32_target_ops);
- if (the_low_target.breakpoint != NULL)
- set_breakpoint_data (the_low_target.breakpoint,
- the_low_target.breakpoint_len);
the_low_target.arch_setup ();
}