X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fwindows-nat.c;h=1ef38fb32b4bd8cb9d9907ba1c7d728658a9f446;hb=d092c5a2465ece3435131ae6fef1ccb6e70986cb;hp=3f67486975cf8f28c52ae44ecd17113c878cf8fe;hpb=463888ab6be549e8dcc9eac36dc07c1c237e2968;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 3f67486975..1ef38fb32b 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -1,6 +1,6 @@ /* Target-vector operations for controlling windows child processes, for GDB. - Copyright (C) 1995-2016 Free Software Foundation, Inc. + Copyright (C) 1995-2017 Free Software Foundation, Inc. Contributed by Cygnus Solutions, A Red Hat Company. @@ -66,6 +66,7 @@ #include "x86-nat.h" #include "complaints.h" #include "inf-child.h" +#include "gdb_tilde_expand.h" #define AdjustTokenPrivileges dyn_AdjustTokenPrivileges #define DebugActiveProcessStop dyn_DebugActiveProcessStop @@ -174,6 +175,19 @@ static int debug_registers_used; static int windows_initialization_done; #define DR6_CLEAR_VALUE 0xffff0ff0 +/* The exception thrown by a program to tell the debugger the name of + a thread. The exception record contains an ID of a thread and a + name to give it. This exception has no documented name, but MSDN + dubs it "MS_VC_EXCEPTION" in one code example. */ +#define MS_VC_EXCEPTION 0x406d1388 + +typedef enum +{ + HANDLE_EXCEPTION_UNHANDLED = 0, + HANDLE_EXCEPTION_HANDLED, + HANDLE_EXCEPTION_IGNORED +} handle_exception_result; + /* The string sent by cygwin when it processes a signal. FIXME: This should be in a cygwin include file. */ #ifndef _CYGWIN_SIGNAL_STRING @@ -396,7 +410,7 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb) 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) @@ -441,23 +455,21 @@ windows_delete_thread (ptid_t ptid, DWORD exit_code) { windows_thread_info *here = th->next; th->next = here->next; + xfree (here->name); xfree (here); } } 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]; + char *context_offset = ((char *) &th->context) + mappings[r]; struct gdbarch *gdbarch = get_regcache_arch (regcache); 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) @@ -466,14 +478,13 @@ do_windows_fetch_inferior_registers (struct regcache *regcache, int r) 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. @@ -489,7 +500,7 @@ do_windows_fetch_inferior_registers (struct regcache *regcache, int r) dr[7] = th->context.Dr7; } } - current_thread->reload_context = 0; + th->reload_context = 0; } if (r == I387_FISEG_REGNUM (tdep)) @@ -515,7 +526,7 @@ do_windows_fetch_inferior_registers (struct regcache *regcache, int r) 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); } } @@ -523,38 +534,42 @@ static void 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); + 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 @@ -571,9 +586,9 @@ struct safe_symbol_file_add_args }; /* 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; @@ -631,8 +646,9 @@ windows_make_so (const char *name, LPVOID load_addr) } #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); @@ -655,32 +671,27 @@ windows_make_so (const char *name, LPVOID load_addr) 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 @@ -763,8 +774,10 @@ handle_load_dll (void *dummy) solib_end->next = windows_make_so (dll_name, event->lpBaseOfDll); solib_end = solib_end->next; + lm_info_windows *li = (lm_info_windows *) solib_end->lm_info; + DEBUG_EVENTS (("gdb: Loading dll \"%s\" at %s.\n", solib_end->so_name, - host_address_to_string (solib_end->lm_info->load_addr))); + host_address_to_string (li->load_addr))); return 1; } @@ -772,8 +785,9 @@ handle_load_dll (void *dummy) 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); } @@ -792,18 +806,22 @@ handle_unload_dll (void *dummy) 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 1; + } + } /* 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 @@ -1031,10 +1049,12 @@ display_selectors (char * args, int from_tty) host_address_to_string (\ current_event.u.Exception.ExceptionRecord.ExceptionAddress)) -static int +static handle_exception_result handle_exception (struct target_waitstatus *ourstatus) { - DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode; + EXCEPTION_RECORD *rec = ¤t_event.u.Exception.ExceptionRecord; + DWORD code = rec->ExceptionCode; + handle_exception_result result = HANDLE_EXCEPTION_HANDLED; ourstatus->kind = TARGET_WAITKIND_STOPPED; @@ -1057,14 +1077,13 @@ handle_exception (struct target_waitstatus *ourstatus) cygwin-specific-signal. So, ignore SEGVs if they show up within the text segment of the DLL itself. */ const char *fn; - CORE_ADDR addr = (CORE_ADDR) (uintptr_t) - current_event.u.Exception.ExceptionRecord.ExceptionAddress; + CORE_ADDR addr = (CORE_ADDR) (uintptr_t) rec->ExceptionAddress; if ((!cygwin_exceptions && (addr >= cygwin_load_start && addr < cygwin_load_end)) || (find_pc_partial_function (addr, &fn, NULL, NULL) && startswith (fn, "KERNEL32!IsBad"))) - return 0; + return HANDLE_EXCEPTION_UNHANDLED; } #endif break; @@ -1140,10 +1159,48 @@ handle_exception (struct target_waitstatus *ourstatus) DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION"); ourstatus->value.sig = GDB_SIGNAL_ILL; break; + case MS_VC_EXCEPTION: + if (rec->NumberParameters >= 3 + && (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000) + { + DWORD named_thread_id; + windows_thread_info *named_thread; + CORE_ADDR thread_name_target; + + DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION"); + + thread_name_target = rec->ExceptionInformation[1]; + named_thread_id = (DWORD) (0xffffffff & rec->ExceptionInformation[2]); + + if (named_thread_id == (DWORD) -1) + named_thread_id = current_event.dwThreadId; + + named_thread = thread_rec (named_thread_id, 0); + if (named_thread != NULL) + { + int thread_name_len; + 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'; + xfree (named_thread->name); + named_thread->name = thread_name; + } + else + xfree (thread_name); + } + ourstatus->value.sig = GDB_SIGNAL_TRAP; + result = HANDLE_EXCEPTION_IGNORED; + break; + } + /* treat improperly formed exception as unknown, fallthrough */ default: /* Treat unhandled first chance exceptions specially. */ if (current_event.u.Exception.dwFirstChance) - return 0; + return HANDLE_EXCEPTION_UNHANDLED; printf_unfiltered ("gdb: unknown target exception 0x%08x at %s\n", (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, host_address_to_string ( @@ -1153,7 +1210,7 @@ handle_exception (struct target_waitstatus *ourstatus) } exception_count++; last_sig = ourstatus->value.sig; - return 1; + return result; } /* Resume thread specified by ID, or all artificially suspended @@ -1463,8 +1520,8 @@ get_windows_debug_event (struct target_ops *ops, "EXIT_PROCESS_DEBUG_EVENT")); if (!windows_initialization_done) { - target_terminal_ours (); - target_mourn_inferior (); + target_terminal::ours (); + target_mourn_inferior (inferior_ptid); error (_("During startup program exited with code 0x%x."), (unsigned int) current_event.u.ExitProcess.dwExitCode); } @@ -1510,10 +1567,19 @@ get_windows_debug_event (struct target_ops *ops, "EXCEPTION_DEBUG_EVENT")); if (saw_create != 1) break; - if (handle_exception (ourstatus)) - thread_id = current_event.dwThreadId; - else - continue_status = DBG_EXCEPTION_NOT_HANDLED; + switch (handle_exception (ourstatus)) + { + case HANDLE_EXCEPTION_UNHANDLED: + default: + continue_status = DBG_EXCEPTION_NOT_HANDLED; + break; + case HANDLE_EXCEPTION_HANDLED: + thread_id = current_event.dwThreadId; + break; + case HANDLE_EXCEPTION_IGNORED: + continue_status = DBG_CONTINUE; + break; + } break; case OUTPUT_DEBUG_STRING_EVENT: /* Message from the kernel. */ @@ -1561,7 +1627,7 @@ windows_wait (struct target_ops *ops, { 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, @@ -1706,8 +1772,8 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) 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; @@ -1847,7 +1913,7 @@ windows_attach (struct target_ops *ops, const char *args, int from_tty) } do_initial_windows_stuff (ops, pid, 1); - target_terminal_ours (); + target_terminal::ours (); } static void @@ -1855,7 +1921,7 @@ windows_detach (struct target_ops *ops, const char *args, 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)) @@ -1868,7 +1934,7 @@ windows_detach (struct target_ops *ops, const char *args, int from_tty) 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, @@ -2054,19 +2120,316 @@ clear_win32_environment (char **env) } #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; @@ -2076,20 +2439,26 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, 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; @@ -2098,6 +2467,17 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, 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); @@ -2121,7 +2501,7 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, error (_("Error starting executable: %d"), errno); cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t)); mbstowcs (cygallargs, allargs, len); -#else +#else /* !__USEWIDE */ cygallargs = allargs; #endif } @@ -2137,28 +2517,33 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, + 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. */ @@ -2167,7 +2552,7 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, 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); @@ -2207,7 +2592,8 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, TRUE, /* inherit handles */ flags, /* start flags */ w32_env, /* environment */ - NULL, /* current directory */ + inferior_cwd != NULL ? infcwd : NULL, /* current + directory */ &si, &pi); if (w32_env) @@ -2232,21 +2618,26 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, 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); @@ -2257,15 +2648,41 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, 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). */ @@ -2299,12 +2716,18 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, 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)."), @@ -2402,7 +2825,7 @@ windows_kill_inferior (struct target_ops *ops) break; } - target_mourn_inferior (); /* Or just windows_mourn_inferior? */ + target_mourn_inferior (inferior_ptid); /* Or just windows_mourn_inferior? */ } static void @@ -2413,7 +2836,7 @@ windows_close (struct target_ops *self) } /* 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]; @@ -2446,9 +2869,13 @@ windows_xfer_shared_libraries (struct target_ops *ops, obstack_init (&obstack); obstack_grow_str (&obstack, "\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, "\n"); buf = (const char *) obstack_finish (&obstack); @@ -2514,6 +2941,14 @@ windows_get_ada_task_ptid (struct target_ops *self, long lwp, long thread) return ptid_build (ptid_get_pid (inferior_ptid), 0, lwp); } +/* Implementation of the to_thread_name method. */ + +static const char * +windows_thread_name (struct target_ops *self, struct thread_info *thr) +{ + return thread_rec (ptid_get_tid (thr->ptid), 0)->name; +} + static struct target_ops * windows_target (void) { @@ -2538,13 +2973,11 @@ windows_target (void) t->to_pid_to_exec_file = windows_pid_to_exec_file; t->to_get_ada_task_ptid = windows_get_ada_task_ptid; t->to_get_tib_address = windows_get_tib_address; + t->to_thread_name = windows_thread_name; return t; } -/* -Wmissing-prototypes */ -extern initialize_file_ftype _initialize_windows_nat; - void _initialize_windows_nat (void) { @@ -2713,9 +3146,6 @@ windows_thread_alive (struct target_ops *ops, ptid_t ptid) ? FALSE : TRUE; } -/* -Wmissing-prototypes */ -extern initialize_file_ftype _initialize_check_for_gdb_ini; - void _initialize_check_for_gdb_ini (void) { @@ -2810,9 +3240,6 @@ bad_GetConsoleFontSize (HANDLE w, DWORD nFont) return size; } -/* -Wmissing-prototypes */ -extern initialize_file_ftype _initialize_loadable; - /* Load any functions which may not be available in ancient versions of Windows. */