/* Target-vector operations for controlling windows child processes, for GDB.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 Free Software Foundation, Inc.
Contributed by Cygnus Solutions, A Red Hat Company.
#include <sys/cygwin.h>
#include <cygwin/version.h>
#endif
+#include <algorithm>
#include "buildsym.h"
#include "filenames.h"
#include "x86-nat.h"
#include "complaints.h"
#include "inf-child.h"
+#include "gdb_tilde_expand.h"
#define AdjustTokenPrivileges dyn_AdjustTokenPrivileges
#define DebugActiveProcessStop dyn_DebugActiveProcessStop
#define DEBUG_MEM(x) if (debug_memory) printf_unfiltered x
#define DEBUG_EXCEPT(x) if (debug_exceptions) printf_unfiltered x
-static void windows_interrupt (struct target_ops *self, ptid_t);
+static void windows_interrupt (struct target_ops *self);
static int windows_thread_alive (struct target_ops *, ptid_t);
static void windows_kill_inferior (struct target_ops *);
return th;
}
-/* Clear out any old thread list and reintialize it to a
+/* Clear out any old thread list and reinitialize it to a
pristine state. */
static void
windows_init_thread_list (void)
}
static void
-do_windows_fetch_inferior_registers (struct regcache *regcache, int r)
+do_windows_fetch_inferior_registers (struct regcache *regcache,
+ windows_thread_info *th, int r)
{
- char *context_offset = ((char *) ¤t_thread->context) + mappings[r];
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ char *context_offset = ((char *) &th->context) + mappings[r];
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
long l;
- if (!current_thread)
- return; /* Windows sometimes uses a non-existent thread id in its
- events. */
-
- if (current_thread->reload_context)
+ if (th->reload_context)
{
#ifdef __CYGWIN__
if (have_saved_context)
cygwin has informed us that we should consider the signal
to have occurred at another location which is stored in
"saved_context. */
- memcpy (¤t_thread->context, &saved_context,
+ memcpy (&th->context, &saved_context,
__COPY_CONTEXT_SIZE);
have_saved_context = 0;
}
else
#endif
{
- windows_thread_info *th = current_thread;
th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
CHECK (GetThreadContext (th->h, &th->context));
/* Copy dr values from that thread.
dr[7] = th->context.Dr7;
}
}
- current_thread->reload_context = 0;
+ th->reload_context = 0;
}
if (r == I387_FISEG_REGNUM (tdep))
else
{
for (r = 0; r < gdbarch_num_regs (gdbarch); r++)
- do_windows_fetch_inferior_registers (regcache, r);
+ do_windows_fetch_inferior_registers (regcache, th, r);
}
}
windows_fetch_inferior_registers (struct target_ops *ops,
struct regcache *regcache, int r)
{
- current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE);
- /* Check if current_thread exists. Windows sometimes uses a non-existent
+ DWORD pid = ptid_get_tid (regcache_get_ptid (regcache));
+ windows_thread_info *th = thread_rec (pid, TRUE);
+
+ /* Check if TH exists. Windows sometimes uses a non-existent
thread id in its events. */
- if (current_thread)
- do_windows_fetch_inferior_registers (regcache, r);
+ if (th != NULL)
+ do_windows_fetch_inferior_registers (regcache, th, r);
}
static void
-do_windows_store_inferior_registers (const struct regcache *regcache, int r)
+do_windows_store_inferior_registers (const struct regcache *regcache,
+ windows_thread_info *th, int r)
{
- if (!current_thread)
- /* Windows sometimes uses a non-existent thread id in its events. */;
- else if (r >= 0)
+ if (r >= 0)
regcache_raw_collect (regcache, r,
- ((char *) ¤t_thread->context) + mappings[r]);
+ ((char *) &th->context) + mappings[r]);
else
{
- for (r = 0; r < gdbarch_num_regs (get_regcache_arch (regcache)); r++)
- do_windows_store_inferior_registers (regcache, r);
+ for (r = 0; r < gdbarch_num_regs (regcache->arch ()); r++)
+ do_windows_store_inferior_registers (regcache, th, r);
}
}
-/* Store a new register value into the current thread context. */
+/* Store a new register value into the context of the thread tied to
+ REGCACHE. */
static void
windows_store_inferior_registers (struct target_ops *ops,
struct regcache *regcache, int r)
{
- current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE);
- /* Check if current_thread exists. Windows sometimes uses a non-existent
+ DWORD pid = ptid_get_tid (regcache_get_ptid (regcache));
+ windows_thread_info *th = thread_rec (pid, TRUE);
+
+ /* Check if TH exists. Windows sometimes uses a non-existent
thread id in its events. */
- if (current_thread)
- do_windows_store_inferior_registers (regcache, r);
+ if (th != NULL)
+ do_windows_store_inferior_registers (regcache, th, r);
}
/* Encapsulate the information required in a call to
{
char *name;
int from_tty;
- struct section_addr_info *addrs;
+ section_addr_info *addrs;
int mainline;
int flags;
struct ui_file *err, *out;
};
/* Maintain a linked list of "so" information. */
-struct lm_info
+struct lm_info_windows : public lm_info_base
{
- LPVOID load_addr;
+ LPVOID load_addr = 0;
};
static struct so_list solib_start, *solib_end;
}
#endif
so = XCNEW (struct so_list);
- so->lm_info = XNEW (struct lm_info);
- so->lm_info->load_addr = load_addr;
+ lm_info_windows *li = new lm_info_windows;
+ so->lm_info = li;
+ li->load_addr = load_addr;
strcpy (so->so_original_name, name);
#ifndef __CYGWIN__
strcpy (so->so_name, buf);
p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1);
if (p >= so->so_name && strcasecmp (p, "/cygwin1.dll") == 0)
{
- bfd *abfd;
asection *text = NULL;
CORE_ADDR text_vma;
- abfd = gdb_bfd_open (so->so_name, "pei-i386", -1);
+ gdb_bfd_ref_ptr abfd (gdb_bfd_open (so->so_name, "pei-i386", -1));
- if (!abfd)
+ if (abfd == NULL)
return so;
- if (bfd_check_format (abfd, bfd_object))
- text = bfd_get_section_by_name (abfd, ".text");
+ if (bfd_check_format (abfd.get (), bfd_object))
+ text = bfd_get_section_by_name (abfd.get (), ".text");
if (!text)
- {
- gdb_bfd_unref (abfd);
- return so;
- }
+ return so;
/* The symbols in a dll are offset by 0x1000, which is the
offset from 0 of the first byte in an image - because of the
file header and the section alignment. */
cygwin_load_start = (CORE_ADDR) (uintptr_t) ((char *)
load_addr + 0x1000);
- cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text);
-
- gdb_bfd_unref (abfd);
+ cygwin_load_end = cygwin_load_start + bfd_section_size (abfd.get (),
+ text);
}
#endif
do_initial_windows_stuff and windows_add_all_dlls for more info
on how we handle DLL loading during that phase). */
-static int
-handle_load_dll (void *dummy)
+static void
+handle_load_dll ()
{
LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
char *dll_name;
dll_name = get_image_name (current_process_handle,
event->lpImageName, event->fUnicode);
if (!dll_name)
- return 1;
+ return;
solib_end->next = windows_make_so (dll_name, event->lpBaseOfDll);
solib_end = solib_end->next;
- DEBUG_EVENTS (("gdb: Loading dll \"%s\" at %s.\n", solib_end->so_name,
- host_address_to_string (solib_end->lm_info->load_addr)));
+ lm_info_windows *li = (lm_info_windows *) solib_end->lm_info;
- return 1;
+ DEBUG_EVENTS (("gdb: Loading dll \"%s\" at %s.\n", solib_end->so_name,
+ host_address_to_string (li->load_addr)));
}
static void
windows_free_so (struct so_list *so)
{
- if (so->lm_info)
- xfree (so->lm_info);
+ lm_info_windows *li = (lm_info_windows *) so->lm_info;
+
+ delete li;
xfree (so);
}
do_initial_windows_stuff and windows_add_all_dlls for more info
on how we handle DLL loading during that phase). */
-static int
-handle_unload_dll (void *dummy)
+static void
+handle_unload_dll ()
{
LPVOID lpBaseOfDll = current_event.u.UnloadDll.lpBaseOfDll;
struct so_list *so;
for (so = &solib_start; so->next != NULL; so = so->next)
- if (so->next->lm_info->load_addr == lpBaseOfDll)
- {
- struct so_list *sodel = so->next;
+ {
+ lm_info_windows *li_next = (lm_info_windows *) so->next->lm_info;
- so->next = sodel->next;
- if (!so->next)
- solib_end = so;
- DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name));
+ if (li_next->load_addr == lpBaseOfDll)
+ {
+ struct so_list *sodel = so->next;
- windows_free_so (sodel);
- return 1;
- }
+ so->next = sodel->next;
+ if (!so->next)
+ solib_end = so;
+ DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name));
+
+ windows_free_so (sodel);
+ return;
+ }
+ }
/* We did not find any DLL that was previously loaded at this address,
so register a complaint. We do not report an error, because we have
32bit and 64bit worlds). */
complaint (&symfile_complaints, _("dll starting at %s not found."),
host_address_to_string (lpBaseOfDll));
+}
- return 0;
+/* Call FUNC wrapped in a TRY/CATCH that swallows all GDB
+ exceptions. */
+
+static void
+catch_errors (void (*func) ())
+{
+ TRY
+ {
+ func ();
+ }
+ CATCH (ex, RETURN_MASK_ALL)
+ {
+ exception_print (gdb_stderr, ex);
+ }
+ END_CATCH
}
/* Clear list of loaded DLLs. */
}
static void
-signal_event_command (char *args, int from_tty)
+signal_event_command (const char *args, int from_tty)
{
uintptr_t event_id = 0;
char *endargs = NULL;
static int
handle_output_debug_string (struct target_waitstatus *ourstatus)
{
- char *s = NULL;
+ 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)
+ &s, 1024, 0)
+ || !s || !*(s.get ()))
/* nothing to do */;
- else if (!startswith (s, _CYGWIN_SIGNAL_STRING))
+ else if (!startswith (s.get (), _CYGWIN_SIGNAL_STRING))
{
#ifdef __CYGWIN__
- if (!startswith (s, "cYg"))
+ if (!startswith (s.get (), "cYg"))
#endif
{
- char *p = strchr (s, '\0');
+ char *p = strchr (s.get (), '\0');
- if (p > s && *--p == '\n')
+ if (p > s.get () && *--p == '\n')
*p = '\0';
- warning (("%s"), s);
+ warning (("%s"), s.get ());
}
}
#ifdef __CYGWIN__
to be stored at the given address in the inferior. Tell gdb
to treat this like a real signal. */
char *p;
- int sig = strtol (s + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0);
+ int sig = strtol (s.get () + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0);
gdb_signal gotasig = gdb_signal_from_host (sig);
ourstatus->value.sig = gotasig;
}
#endif
- if (s)
- xfree (s);
return retval;
}
}
static void
-display_selectors (char * args, int from_tty)
+display_selectors (const char * args, int from_tty)
{
if (!current_thread)
{
if (named_thread != NULL)
{
int thread_name_len;
- char *thread_name;
+ gdb::unique_xmalloc_ptr<char> thread_name;
thread_name_len = target_read_string (thread_name_target,
&thread_name, 1025, NULL);
if (thread_name_len > 0)
{
- thread_name[thread_name_len - 1] = '\0';
+ thread_name.get ()[thread_name_len - 1] = '\0';
xfree (named_thread->name);
- named_thread->name = thread_name;
+ named_thread->name = thread_name.release ();
}
- else
- xfree (thread_name);
}
ourstatus->value.sig = GDB_SIGNAL_TRAP;
result = HANDLE_EXCEPTION_IGNORED;
{
/* Single step by setting t bit. */
struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
windows_fetch_inferior_registers (ops, regcache,
gdbarch_ps_regnum (gdbarch));
th->context.EFlags |= FLAG_TRACE_BIT;
"EXIT_PROCESS_DEBUG_EVENT"));
if (!windows_initialization_done)
{
- target_terminal_ours ();
+ target_terminal::ours ();
target_mourn_inferior (inferior_ptid);
error (_("During startup program exited with code 0x%x."),
(unsigned int) current_event.u.ExitProcess.dwExitCode);
CloseHandle (current_event.u.LoadDll.hFile);
if (saw_create != 1 || ! windows_initialization_done)
break;
- catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
+ catch_errors (handle_load_dll);
ourstatus->kind = TARGET_WAITKIND_LOADED;
ourstatus->value.integer = 0;
thread_id = main_thread_id;
"UNLOAD_DLL_DEBUG_EVENT"));
if (saw_create != 1 || ! windows_initialization_done)
break;
- catch_errors (handle_unload_dll, NULL, (char *) "", RETURN_MASK_ALL);
+ catch_errors (handle_unload_dll);
ourstatus->kind = TARGET_WAITKIND_LOADED;
ourstatus->value.integer = 0;
thread_id = main_thread_id;
{
int pid = -1;
- target_terminal_ours ();
+ target_terminal::ours ();
/* We loop when we get a non-standard exception rather than return
with a SPURIOUS because resume can try and step or modify things,
current thread until we report an event out of windows_wait. */
inferior_ptid = pid_to_ptid (pid);
- target_terminal_init ();
- target_terminal_inferior ();
+ target_terminal::init ();
+ target_terminal::inferior ();
windows_initialization_done = 0;
}
do_initial_windows_stuff (ops, pid, 1);
- target_terminal_ours ();
+ target_terminal::ours ();
}
static void
-windows_detach (struct target_ops *ops, const char *args, int from_tty)
+windows_detach (struct target_ops *ops, inferior *inf, int from_tty)
{
int detached = 1;
- ptid_t ptid = {-1};
+ ptid_t ptid = minus_one_ptid;
windows_resume (ops, ptid, 0, GDB_SIGNAL_0);
if (!DebugActiveProcessStop (current_event.dwProcessId))
if (detached && from_tty)
{
- char *exec_file = get_exec_file (0);
+ const char *exec_file = get_exec_file (0);
if (exec_file == 0)
exec_file = "";
printf_unfiltered ("Detaching from program: %s, Pid %u\n", exec_file,
}
#endif
+#ifndef __CYGWIN__
+
+/* Redirection of inferior I/O streams for native MS-Windows programs.
+ Unlike on Unix, where this is handled by invoking the inferior via
+ the shell, on MS-Windows we need to emulate the cmd.exe shell.
+
+ The official documentation of the cmd.exe redirection features is here:
+
+ http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx
+
+ (That page talks about Windows XP, but there's no newer
+ documentation, so we assume later versions of cmd.exe didn't change
+ anything.)
+
+ Caveat: the documentation on that page seems to include a few lies.
+ For example, it describes strange constructs 1<&2 and 2<&1, which
+ seem to work only when 1>&2 resp. 2>&1 would make sense, and so I
+ think the cmd.exe parser of the redirection symbols simply doesn't
+ care about the < vs > distinction in these cases. Therefore, the
+ supported features are explicitly documented below.
+
+ The emulation below aims at supporting all the valid use cases
+ supported by cmd.exe, which include:
+
+ < FILE redirect standard input from FILE
+ 0< FILE redirect standard input from FILE
+ <&N redirect standard input from file descriptor N
+ 0<&N redirect standard input from file descriptor N
+ > FILE redirect standard output to FILE
+ >> FILE append standard output to FILE
+ 1>> FILE append standard output to FILE
+ >&N redirect standard output to file descriptor N
+ 1>&N redirect standard output to file descriptor N
+ >>&N append standard output to file descriptor N
+ 1>>&N append standard output to file descriptor N
+ 2> FILE redirect standard error to FILE
+ 2>> FILE append standard error to FILE
+ 2>&N redirect standard error to file descriptor N
+ 2>>&N append standard error to file descriptor N
+
+ Note that using N > 2 in the above construct is supported, but
+ requires that the corresponding file descriptor be open by some
+ means elsewhere or outside GDB. Also note that using ">&0" or
+ "<&2" will generally fail, because the file descriptor redirected
+ from is normally open in an incompatible mode (e.g., FD 0 is open
+ for reading only). IOW, use of such tricks is not recommended;
+ you are on your own.
+
+ We do NOT support redirection of file descriptors above 2, as in
+ "3>SOME-FILE", because MinGW compiled programs don't (supporting
+ that needs special handling in the startup code that MinGW
+ doesn't have). Pipes are also not supported.
+
+ As for invalid use cases, where the redirection contains some
+ error, the emulation below will detect that and produce some
+ error and/or failure. But the behavior in those cases is not
+ bug-for-bug compatible with what cmd.exe does in those cases.
+ That's because what cmd.exe does then is not well defined, and
+ seems to be a side effect of the cmd.exe parsing of the command
+ line more than anything else. For example, try redirecting to an
+ invalid file name, as in "> foo:bar".
+
+ There are also minor syntactic deviations from what cmd.exe does
+ in some corner cases. For example, it doesn't support the likes
+ of "> &foo" to mean redirect to file named literally "&foo"; we
+ do support that here, because that, too, sounds like some issue
+ with the cmd.exe parser. Another nicety is that we support
+ redirection targets that use file names with forward slashes,
+ something cmd.exe doesn't -- this comes in handy since GDB
+ file-name completion can be used when typing the command line for
+ the inferior. */
+
+/* Support routines for redirecting standard handles of the inferior. */
+
+/* Parse a single redirection spec, open/duplicate the specified
+ file/fd, and assign the appropriate value to one of the 3 standard
+ file descriptors. */
+static int
+redir_open (const char *redir_string, int *inp, int *out, int *err)
+{
+ int *fd, ref_fd = -2;
+ int mode;
+ const char *fname = redir_string + 1;
+ int rc = *redir_string;
+
+ switch (rc)
+ {
+ case '0':
+ fname++;
+ /* FALLTHROUGH */
+ case '<':
+ fd = inp;
+ mode = O_RDONLY;
+ break;
+ case '1': case '2':
+ fname++;
+ /* FALLTHROUGH */
+ case '>':
+ fd = (rc == '2') ? err : out;
+ mode = O_WRONLY | O_CREAT;
+ if (*fname == '>')
+ {
+ fname++;
+ mode |= O_APPEND;
+ }
+ else
+ mode |= O_TRUNC;
+ break;
+ default:
+ return -1;
+ }
+
+ if (*fname == '&' && '0' <= fname[1] && fname[1] <= '9')
+ {
+ /* A reference to a file descriptor. */
+ char *fdtail;
+ ref_fd = (int) strtol (fname + 1, &fdtail, 10);
+ if (fdtail > fname + 1 && *fdtail == '\0')
+ {
+ /* Don't allow redirection when open modes are incompatible. */
+ if ((ref_fd == 0 && (fd == out || fd == err))
+ || ((ref_fd == 1 || ref_fd == 2) && fd == inp))
+ {
+ errno = EPERM;
+ return -1;
+ }
+ if (ref_fd == 0)
+ ref_fd = *inp;
+ else if (ref_fd == 1)
+ ref_fd = *out;
+ else if (ref_fd == 2)
+ ref_fd = *err;
+ }
+ else
+ {
+ errno = EBADF;
+ return -1;
+ }
+ }
+ else
+ fname++; /* skip the separator space */
+ /* If the descriptor is already open, close it. This allows
+ multiple specs of redirections for the same stream, which is
+ somewhat nonsensical, but still valid and supported by cmd.exe.
+ (But cmd.exe only opens a single file in this case, the one
+ specified by the last redirection spec on the command line.) */
+ if (*fd >= 0)
+ _close (*fd);
+ if (ref_fd == -2)
+ {
+ *fd = _open (fname, mode, _S_IREAD | _S_IWRITE);
+ if (*fd < 0)
+ return -1;
+ }
+ else if (ref_fd == -1)
+ *fd = -1; /* reset to default destination */
+ else
+ {
+ *fd = _dup (ref_fd);
+ if (*fd < 0)
+ return -1;
+ }
+ /* _open just sets a flag for O_APPEND, which won't be passed to the
+ inferior, so we need to actually move the file pointer. */
+ if ((mode & O_APPEND) != 0)
+ _lseek (*fd, 0L, SEEK_END);
+ return 0;
+}
+
+/* Canonicalize a single redirection spec and set up the corresponding
+ file descriptor as specified. */
+static int
+redir_set_redirection (const char *s, int *inp, int *out, int *err)
+{
+ char buf[__PMAX + 2 + 5]; /* extra space for quotes & redirection string */
+ char *d = buf;
+ const char *start = s;
+ int quote = 0;
+
+ *d++ = *s++; /* copy the 1st character, < or > or a digit */
+ if ((*start == '>' || *start == '1' || *start == '2')
+ && *s == '>')
+ {
+ *d++ = *s++;
+ if (*s == '>' && *start != '>')
+ *d++ = *s++;
+ }
+ else if (*start == '0' && *s == '<')
+ *d++ = *s++;
+ /* cmd.exe recognizes "&N" only immediately after the redirection symbol. */
+ if (*s != '&')
+ {
+ while (isspace (*s)) /* skip whitespace before file name */
+ s++;
+ *d++ = ' '; /* separate file name with a single space */
+ }
+
+ /* Copy the file name. */
+ while (*s)
+ {
+ /* Remove quoting characters from the file name in buf[]. */
+ if (*s == '"') /* could support '..' quoting here */
+ {
+ if (!quote)
+ quote = *s++;
+ else if (*s == quote)
+ {
+ quote = 0;
+ s++;
+ }
+ else
+ *d++ = *s++;
+ }
+ else if (*s == '\\')
+ {
+ if (s[1] == '"') /* could support '..' here */
+ s++;
+ *d++ = *s++;
+ }
+ else if (isspace (*s) && !quote)
+ break;
+ else
+ *d++ = *s++;
+ if (d - buf >= sizeof (buf) - 1)
+ {
+ errno = ENAMETOOLONG;
+ return 0;
+ }
+ }
+ *d = '\0';
+
+ /* Windows doesn't allow redirection characters in file names, so we
+ can bail out early if they use them, or if there's no target file
+ name after the redirection symbol. */
+ if (d[-1] == '>' || d[-1] == '<')
+ {
+ errno = ENOENT;
+ return 0;
+ }
+ if (redir_open (buf, inp, out, err) == 0)
+ return s - start;
+ return 0;
+}
+
+/* Parse the command line for redirection specs and prepare the file
+ descriptors for the 3 standard streams accordingly. */
+static bool
+redirect_inferior_handles (const char *cmd_orig, char *cmd,
+ int *inp, int *out, int *err)
+{
+ const char *s = cmd_orig;
+ char *d = cmd;
+ int quote = 0;
+ bool retval = false;
+
+ while (isspace (*s))
+ *d++ = *s++;
+
+ while (*s)
+ {
+ if (*s == '"') /* could also support '..' quoting here */
+ {
+ if (!quote)
+ quote = *s;
+ else if (*s == quote)
+ quote = 0;
+ }
+ else if (*s == '\\')
+ {
+ if (s[1] == '"') /* escaped quote char */
+ s++;
+ }
+ else if (!quote)
+ {
+ /* Process a single redirection candidate. */
+ if (*s == '<' || *s == '>'
+ || ((*s == '1' || *s == '2') && s[1] == '>')
+ || (*s == '0' && s[1] == '<'))
+ {
+ int skip = redir_set_redirection (s, inp, out, err);
+
+ if (skip <= 0)
+ return false;
+ retval = true;
+ s += skip;
+ }
+ }
+ if (*s)
+ *d++ = *s++;
+ }
+ *d = '\0';
+ return retval;
+}
+#endif /* !__CYGWIN__ */
+
/* Start an inferior windows child process and sets inferior_ptid to its pid.
EXEC_FILE is the file to run.
ALLARGS is a string containing the arguments to the program.
ENV is the environment vector to pass. Errors reported with error(). */
static void
-windows_create_inferior (struct target_ops *ops, char *exec_file,
- char *allargs, char **in_env, int from_tty)
+windows_create_inferior (struct target_ops *ops, const char *exec_file,
+ const std::string &origallargs, char **in_env,
+ int from_tty)
{
STARTUPINFO si;
#ifdef __CYGWIN__
cygwin_buf_t real_path[__PMAX];
cygwin_buf_t shell[__PMAX]; /* Path to shell */
+ cygwin_buf_t infcwd[__PMAX];
const char *sh;
cygwin_buf_t *toexec;
cygwin_buf_t *cygallargs;
size_t len;
int tty;
int ostdin, ostdout, ostderr;
-#else
+#else /* !__CYGWIN__ */
char real_path[__PMAX];
char shell[__PMAX]; /* Path to shell */
- char *toexec;
- char *args;
- size_t args_len;
- HANDLE tty;
+ const char *toexec;
+ char *args, *allargs_copy;
+ size_t args_len, allargs_len;
+ int fd_inp = -1, fd_out = -1, fd_err = -1;
+ HANDLE tty = INVALID_HANDLE_VALUE;
+ HANDLE inf_stdin = INVALID_HANDLE_VALUE;
+ HANDLE inf_stdout = INVALID_HANDLE_VALUE;
+ HANDLE inf_stderr = INVALID_HANDLE_VALUE;
+ bool redirected = false;
char *w32env;
char *temp;
size_t envlen;
int i;
size_t envsize;
char **env;
-#endif
+#endif /* !__CYGWIN__ */
+ const char *allargs = origallargs.c_str ();
PROCESS_INFORMATION pi;
BOOL ret;
DWORD flags = 0;
if (!exec_file)
error (_("No executable specified, use `target exec'."));
+ const char *inferior_cwd = get_inferior_cwd ();
+ std::string expanded_infcwd;
+ if (inferior_cwd != NULL)
+ {
+ expanded_infcwd = gdb_tilde_expand (inferior_cwd);
+ /* Mirror slashes on inferior's cwd. */
+ std::replace (expanded_infcwd.begin (), expanded_infcwd.end (),
+ '/', '\\');
+ inferior_cwd = expanded_infcwd.c_str ();
+ }
+
memset (&si, 0, sizeof (si));
si.cb = sizeof (si);
error (_("Error starting executable: %d"), errno);
cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t));
mbstowcs (cygallargs, allargs, len);
-#else
+#else /* !__USEWIDE */
cygallargs = allargs;
#endif
}
+ mbstowcs (NULL, allargs, 0) + 2;
cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t));
swprintf (cygallargs, len, L" -c 'exec %s %s'", exec_file, allargs);
-#else
+#else /* !__USEWIDE */
len = (sizeof (" -c 'exec '") + strlen (exec_file)
+ strlen (allargs) + 2);
cygallargs = (char *) alloca (len);
xsnprintf (cygallargs, len, " -c 'exec %s %s'", exec_file, allargs);
-#endif
+#endif /* __USEWIDE */
toexec = shell;
flags |= DEBUG_PROCESS;
}
+ if (inferior_cwd != NULL
+ && cygwin_conv_path (CCP_POSIX_TO_WIN_W, inferior_cwd,
+ infcwd, strlen (inferior_cwd)) < 0)
+ error (_("Error converting inferior cwd: %d"), errno);
+
#ifdef __USEWIDE
args = (cygwin_buf_t *) alloca ((wcslen (toexec) + wcslen (cygallargs) + 2)
* sizeof (wchar_t));
wcscpy (args, toexec);
wcscat (args, L" ");
wcscat (args, cygallargs);
-#else
+#else /* !__USEWIDE */
args = (cygwin_buf_t *) alloca (strlen (toexec) + strlen (cygallargs) + 2);
strcpy (args, toexec);
strcat (args, " ");
strcat (args, cygallargs);
-#endif
+#endif /* !__USEWIDE */
#ifdef CW_CVT_ENV_TO_WINENV
/* First try to create a direct Win32 copy of the POSIX environment. */
flags |= CREATE_UNICODE_ENVIRONMENT;
else
/* If that fails, fall back to old method tweaking GDB's environment. */
-#endif
+#endif /* CW_CVT_ENV_TO_WINENV */
{
/* Reset all Win32 environment variables to avoid leftover on next run. */
clear_win32_environment (environ);
TRUE, /* inherit handles */
flags, /* start flags */
w32_env, /* environment */
- NULL, /* current directory */
+ inferior_cwd != NULL ? infcwd : NULL, /* current
+ directory */
&si,
&pi);
if (w32_env)
close (ostdout);
close (ostderr);
}
-#else
- toexec = exec_file;
- /* Build the command line, a space-separated list of tokens where
- the first token is the name of the module to be executed.
- To avoid ambiguities introduced by spaces in the module name,
- we quote it. */
- args_len = strlen (toexec) + 2 /* quotes */ + strlen (allargs) + 2;
- args = (char *) alloca (args_len);
- xsnprintf (args, args_len, "\"%s\" %s", toexec, allargs);
-
- flags |= DEBUG_ONLY_THIS_PROCESS;
-
- if (!inferior_io_terminal)
- tty = INVALID_HANDLE_VALUE;
- else
+#else /* !__CYGWIN__ */
+ allargs_len = strlen (allargs);
+ allargs_copy = strcpy ((char *) alloca (allargs_len + 1), allargs);
+ if (strpbrk (allargs_copy, "<>") != NULL)
+ {
+ int e = errno;
+ errno = 0;
+ redirected =
+ redirect_inferior_handles (allargs, allargs_copy,
+ &fd_inp, &fd_out, &fd_err);
+ if (errno)
+ warning (_("Error in redirection: %s."), strerror (errno));
+ else
+ errno = e;
+ 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
+ && !(fd_inp >= 0 && fd_out >= 0 && fd_err >= 0))
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
if (tty == INVALID_HANDLE_VALUE)
warning (_("Warning: Failed to open TTY %s, error %#x."),
inferior_io_terminal, (unsigned) GetLastError ());
+ }
+ if (redirected || tty != INVALID_HANDLE_VALUE)
+ {
+ if (fd_inp >= 0)
+ si.hStdInput = (HANDLE) _get_osfhandle (fd_inp);
+ else if (tty != INVALID_HANDLE_VALUE)
+ si.hStdInput = tty;
else
- {
- si.hStdInput = tty;
- si.hStdOutput = tty;
- si.hStdError = tty;
- si.dwFlags |= STARTF_USESTDHANDLES;
- }
+ si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
+ if (fd_out >= 0)
+ si.hStdOutput = (HANDLE) _get_osfhandle (fd_out);
+ else if (tty != INVALID_HANDLE_VALUE)
+ si.hStdOutput = tty;
+ else
+ si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
+ if (fd_err >= 0)
+ si.hStdError = (HANDLE) _get_osfhandle (fd_err);
+ else if (tty != INVALID_HANDLE_VALUE)
+ si.hStdError = tty;
+ else
+ si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
+ si.dwFlags |= STARTF_USESTDHANDLES;
}
+ toexec = exec_file;
+ /* Build the command line, a space-separated list of tokens where
+ the first token is the name of the module to be executed.
+ To avoid ambiguities introduced by spaces in the module name,
+ we quote it. */
+ args_len = strlen (toexec) + 2 /* quotes */ + allargs_len + 2;
+ args = (char *) alloca (args_len);
+ xsnprintf (args, args_len, "\"%s\" %s", toexec, allargs_copy);
+
+ flags |= DEBUG_ONLY_THIS_PROCESS;
+
/* CreateProcess takes the environment list as a null terminated set of
strings (i.e. two nulls terminate the list). */
TRUE, /* inherit handles */
flags, /* start flags */
w32env, /* environment */
- NULL, /* current directory */
+ inferior_cwd, /* current directory */
&si,
&pi);
if (tty != INVALID_HANDLE_VALUE)
CloseHandle (tty);
-#endif
+ if (fd_inp >= 0)
+ _close (fd_inp);
+ if (fd_out >= 0)
+ _close (fd_out);
+ if (fd_err >= 0)
+ _close (fd_err);
+#endif /* !__CYGWIN__ */
if (!ret)
error (_("Error creating process %s, (error %u)."),
^C on the controlling terminal. */
static void
-windows_interrupt (struct target_ops *self, ptid_t ptid)
+windows_interrupt (struct target_ops *self)
{
DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n"));
CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId));
}
/* Convert pid to printable format. */
-static char *
+static const char *
windows_pid_to_str (struct target_ops *ops, ptid_t ptid)
{
static char buf[80];
obstack_init (&obstack);
obstack_grow_str (&obstack, "<library-list>\n");
for (so = solib_start.next; so; so = so->next)
- windows_xfer_shared_library (so->so_name, (CORE_ADDR)
- (uintptr_t) so->lm_info->load_addr,
- target_gdbarch (), &obstack);
+ {
+ lm_info_windows *li = (lm_info_windows *) so->lm_info;
+
+ windows_xfer_shared_library (so->so_name, (CORE_ADDR)
+ (uintptr_t) li->load_addr,
+ target_gdbarch (), &obstack);
+ }
obstack_grow_str0 (&obstack, "</library-list>\n");
buf = (const char *) obstack_finish (&obstack);
return t;
}
-/* -Wmissing-prototypes */
-extern initialize_file_ftype _initialize_windows_nat;
-
void
_initialize_windows_nat (void)
{
? FALSE : TRUE;
}
-/* -Wmissing-prototypes */
-extern initialize_file_ftype _initialize_check_for_gdb_ini;
-
void
_initialize_check_for_gdb_ini (void)
{
return size;
}
-/* -Wmissing-prototypes */
-extern initialize_file_ftype _initialize_loadable;
-
/* Load any functions which may not be available in ancient versions
of Windows. */