/* Target-vector operations for controlling win32 child processes, for GDB.
- Copyright 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
Contributed by Cygnus Solutions, A Red Hat Company.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
- */
+ Boston, MA 02111-1307, USA. */
/* by Steve Chamberlain, sac@cygnus.com */
#include "target.h"
#include "gdbcore.h"
#include "command.h"
+#include "completer.h"
+#include "regcache.h"
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
extern struct target_ops child_ops;
static void child_stop (void);
-static int win32_child_thread_alive (int);
+static int win32_child_thread_alive (ptid_t);
void child_kill_inferior (void);
static int last_sig = 0; /* Set if a signal was received from the
th->h = h;
th->next = thread_head.next;
thread_head.next = th;
- add_thread (id);
+ add_thread (pid_to_ptid (id));
return th;
}
thread_info *here = th->next;
th->next = here->next;
(void) CloseHandle (here->h);
- free (here);
+ xfree (here);
}
}
thread_info *th;
if (info_verbose)
- printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (id));
- delete_thread (id);
+ printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (pid_to_ptid (id)));
+ delete_thread (pid_to_ptid (id));
for (th = &thread_head;
th->next != NULL && th->next->id != id;
thread_info *here = th->next;
th->next = here->next;
CloseHandle (here->h);
- free (here);
+ xfree (here);
}
}
static void
child_fetch_inferior_registers (int r)
{
- current_thread = thread_rec (inferior_pid, TRUE);
+ current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
do_child_fetch_inferior_registers (r);
}
static void
child_store_inferior_registers (int r)
{
- current_thread = thread_rec (inferior_pid, TRUE);
+ current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
do_child_store_inferior_registers (r);
}
struct objfile *ret;
};
+/* Maintain a linked list of "so" information. */
+struct so_stuff
+{
+ struct so_stuff *next, **last;
+ DWORD load_addr;
+ int loaded;
+ char name[1];
+} solib_start, *solib_end;
+
/* Call symbol_file_add with stderr redirected. We don't care if there
are errors. */
static int
safe_symbol_file_add_stub (void *argv)
{
#define p ((struct safe_symbol_file_add_args *)argv)
+ struct so_stuff *so = &solib_start;
+
+ while ((so = so->next))
+ if (so->loaded && strcasecmp (so->name, p->name) == 0)
+ return 0;
p->ret = symbol_file_add (p->name, p->from_tty, p->addrs, p->mainline, p->flags);
return !!p->ret;
#undef p
#define sp ((struct safe_symbol_file_add_args *)p)
gdb_flush (gdb_stderr);
gdb_flush (gdb_stdout);
- ui_file_delete (gdb_stderr);
+ /* ui_file_delete (gdb_stderr); */
ui_file_delete (gdb_stdout);
- gdb_stderr = sp->err;
+ /* gdb_stderr = sp->err; */
gdb_stdout = sp->out;
#undef sp
}
p.out = gdb_stdout;
gdb_flush (gdb_stderr);
gdb_flush (gdb_stdout);
- gdb_stderr = ui_file_new ();
+ /* gdb_stderr = ui_file_new (); */
gdb_stdout = ui_file_new ();
p.name = name;
p.from_tty = from_tty;
return p.ret;
}
-/* Maintain a linked list of "so" information. */
-struct so_stuff
-{
- struct so_stuff *next, **last;
- DWORD load_addr;
- char name[0];
-}
-solib_start, *solib_end;
-
/* Remember the maximum DLL length for printing in info dll command. */
int max_dll_name_len;
register_loaded_dll (const char *name, DWORD load_addr)
{
struct so_stuff *so;
- so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) + strlen (name) + 8 + 2);
+ char ppath[MAX_PATH + 1];
+ char buf[MAX_PATH + 1];
+ char cwd[MAX_PATH + 1];
+ char *p;
+ WIN32_FIND_DATA w32_fd;
+ HANDLE h = FindFirstFile(name, &w32_fd);
+ size_t len;
+
+ FindClose (h);
+ strcpy (buf, name);
+ if (GetCurrentDirectory (MAX_PATH + 1, cwd))
+ {
+ p = strrchr (buf, '\\');
+ if (p)
+ p[1] = '\0';
+ SetCurrentDirectory (buf);
+ GetFullPathName (w32_fd.cFileName, MAX_PATH, buf, &p);
+ SetCurrentDirectory (cwd);
+ }
+
+ cygwin_conv_to_posix_path (buf, ppath);
+ so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) + strlen (ppath) + 8 + 1);
+ so->loaded = 0;
so->load_addr = load_addr;
- strcpy (so->name, name);
+ strcpy (so->name, ppath);
solib_end->next = so;
solib_end = so;
so->next = NULL;
+ len = strlen (ppath);
+ if (len > max_dll_name_len)
+ max_dll_name_len = len;
}
/* Wait for child to do something. Return pid of child, or -1 in case
of error; store status through argument pointer OURSTATUS. */
static int
-handle_load_dll (PTR dummy ATTRIBUTE_UNUSED)
+handle_load_dll (void *dummy ATTRIBUTE_UNUSED)
{
LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
DWORD dll_name_ptr;
DWORD done;
char dll_buf[MAX_PATH + 1];
char *dll_name = NULL;
- int len;
char *p;
dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
if (!dll_name)
return 1;
- (void) strlwr (dll_name);
-
- while ((p = strchr (dll_name, '\\')))
- *p = '/';
-
register_loaded_dll (dll_name, (DWORD) event->lpBaseOfDll + 0x1000);
- len = strlen (dll_name);
- if (len > max_dll_name_len)
- max_dll_name_len = len;
return 1;
}
while ((so = so1) != NULL)
{
so1 = so->next;
- free (so);
+ xfree (so);
}
solib_start.next = NULL;
}
/* Add DLL symbol information. */
-void
-solib_symbols_add (char *name, CORE_ADDR load_addr)
+static void
+solib_symbols_add (char *name, int from_tty, CORE_ADDR load_addr)
{
struct section_addr_info section_addrs;
memset (§ion_addrs, 0, sizeof (section_addrs));
section_addrs.other[0].name = ".text";
section_addrs.other[0].addr = load_addr;
- safe_symbol_file_add (name, 0, §ion_addrs, 0, OBJF_SHARED);
+ safe_symbol_file_add (name, from_tty, NULL, 0, OBJF_SHARED);
return;
}
/* Load DLL symbol info. */
void
-dll_symbol_command (char *args, int from_tty ATTRIBUTE_UNUSED)
+dll_symbol_command (char *args, int from_tty)
{
int n;
dont_repeat ();
args = newargs;
}
- safe_symbol_file_add (args, 0, NULL, 0, OBJF_SHARED | OBJF_USERLOADED);
+ safe_symbol_file_add (args, from_tty, NULL, 0, OBJF_SHARED | OBJF_USERLOADED);
}
/* List currently loaded DLLs. */
ourstatus->kind = TARGET_WAITKIND_STOPPED;
}
- free (s);
+ xfree (s);
return gotasig;
}
last_sig = SIGILL;
break;
default:
+ if (current_event.u.Exception.dwFirstChance)
+ return 0;
printf_unfiltered ("gdb: unknown target exception 0x%08lx at 0x%08lx\n",
current_event.u.Exception.ExceptionRecord.ExceptionCode,
(DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress);
current_event.u.CreateThread.hThread);
if (info_verbose)
printf_unfiltered ("[New %s]\n",
- target_pid_to_str (current_event.dwThreadId));
+ target_pid_to_str (
+ pid_to_ptid (current_event.dwThreadId)));
retval = current_event.dwThreadId;
break;
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
"CREATE_PROCESS_DEBUG_EVENT"));
+ CloseHandle (current_event.u.CreateProcessInfo.hFile);
current_process_handle = current_event.u.CreateProcessInfo.hProcess;
main_thread_id = current_event.dwThreadId;
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
"LOAD_DLL_DEBUG_EVENT"));
+ CloseHandle (current_event.u.LoadDll.hFile);
catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
registers_changed (); /* mark all regs invalid */
ourstatus->kind = TARGET_WAITKIND_LOADED;
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
"EXCEPTION_DEBUG_EVENT"));
- handle_exception (ourstatus);
- retval = current_event.dwThreadId;
+ if (handle_exception (ourstatus))
+ retval = current_event.dwThreadId;
break;
case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */
else
{
current_thread = th ? : thread_rec (current_event.dwThreadId, TRUE);
- inferior_pid = retval;
+ inferior_ptid = pid_to_ptid (retval);
}
out:
}
/* Wait for interesting events to occur in the target process. */
-static int
-child_wait (int pid, struct target_waitstatus *ourstatus)
+static ptid_t
+child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
{
+ int pid = PIDGET (ptid);
+
/* We loop when we get a non-standard exception rather than return
with a SPURIOUS because resume can try and step or modify things,
which needs a current_thread->h. But some of these exceptions mark
{
int retval = get_child_debug_event (pid, ourstatus);
if (retval)
- return retval;
+ return pid_to_ptid (retval);
else
{
int detach = 0;
return;
}
-/* Attach to process PID, then initialize for debugging it. */
+/* Since Windows XP, detaching from a process is supported by Windows.
+ The following code tries loading the appropriate functions dynamically.
+ If loading these functions succeeds use them to actually detach from
+ the inferior process, otherwise behave as usual, pretending that
+ detach has worked. */
+static BOOL WINAPI (*DebugSetProcessKillOnExit)(BOOL);
+static BOOL WINAPI (*DebugActiveProcessStop)(DWORD);
+
+static int
+has_detach_ability ()
+{
+ static HMODULE kernel32 = NULL;
+
+ if (!kernel32)
+ kernel32 = LoadLibrary ("kernel32.dll");
+ if (kernel32)
+ {
+ if (!DebugSetProcessKillOnExit)
+ DebugSetProcessKillOnExit = GetProcAddress (kernel32,
+ "DebugSetProcessKillOnExit");
+ if (!DebugActiveProcessStop)
+ DebugActiveProcessStop = GetProcAddress (kernel32,
+ "DebugActiveProcessStop");
+ if (DebugSetProcessKillOnExit && DebugActiveProcessStop)
+ return 1;
+ }
+ return 0;
+}
+/* Attach to process PID, then initialize for debugging it. */
static void
child_attach (char *args, int from_tty)
{
BOOL ok;
- DWORD pid = strtoul (args, 0, 0);
+ DWORD pid;
if (!args)
error_no_arg ("process-id to attach");
+ pid = strtoul (args, 0, 0);
ok = DebugActiveProcess (pid);
if (!ok)
error ("Can't attach to process.");
+ if (has_detach_ability ())
+ {
+ attach_flag = 1;
+ DebugSetProcessKillOnExit (FALSE);
+ }
+
if (from_tty)
{
char *exec_file = (char *) get_exec_file (0);
if (exec_file)
printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
- target_pid_to_str (pid));
+ target_pid_to_str (pid_to_ptid (pid)));
else
printf_unfiltered ("Attaching to %s\n",
- target_pid_to_str (pid));
+ target_pid_to_str (pid_to_ptid (pid)));
gdb_flush (gdb_stdout);
}
static void
child_detach (char *args ATTRIBUTE_UNUSED, int from_tty)
{
- if (from_tty)
+ int detached = 1;
+
+ if (has_detach_ability ())
+ {
+ delete_command (NULL, 0);
+ child_continue (DBG_CONTINUE, -1);
+ if (!DebugActiveProcessStop (current_event.dwProcessId))
+ {
+ error ("Can't detach process %lu (error %lu)",
+ current_event.dwProcessId, GetLastError ());
+ detached = 0;
+ }
+ DebugSetProcessKillOnExit (FALSE);
+ }
+ if (detached && from_tty)
{
char *exec_file = get_exec_file (0);
if (exec_file == 0)
exec_file = "";
- printf_unfiltered ("Detaching from program: %s %s\n", exec_file,
- target_pid_to_str (inferior_pid));
+ printf_unfiltered ("Detaching from program: %s, Pid %lu\n", exec_file,
+ current_event.dwProcessId);
gdb_flush (gdb_stdout);
}
- inferior_pid = 0;
+ inferior_ptid = null_ptid;
unpush_target (&child_ops);
}
child_files_info (struct target_ops *ignore ATTRIBUTE_UNUSED)
{
printf_unfiltered ("\tUsing the running image of %s %s.\n",
- attach_flag ? "attached" : "child", target_pid_to_str (inferior_pid));
+ attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid));
}
/* ARGSUSED */
error ("Use the \"run\" command to start a Unix child process.");
}
-/* Start an inferior win32 child process and sets inferior_pid to its pid.
+/* Start an inferior win32 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(). */
if (!ret)
error ("Error creating process %s, (error %d)\n", exec_file, GetLastError ());
+ CloseHandle (pi.hThread);
+ CloseHandle (pi.hProcess);
do_initial_child_stuff (pi.dwProcessId);
/* child_continue (DBG_CONTINUE, -1); */
int
child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
- int write, struct target_ops *target ATTRIBUTE_UNUSED)
+ int write, struct mem_attrib *mem ATTRIBUTE_UNUSED,
+ struct target_ops *target ATTRIBUTE_UNUSED)
{
DWORD done;
if (write)
}
void
-child_resume (int pid, int step, enum target_signal sig)
+child_resume (ptid_t ptid, int step, enum target_signal sig)
{
thread_info *th;
DWORD continue_status = last_sig > 0 && last_sig < NSIG ?
DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE;
+ int pid = PIDGET (ptid);
last_sig = 0;
static void
child_close (int x ATTRIBUTE_UNUSED)
{
- DEBUG_EVENTS (("gdb: child_close, inferior_pid=%d\n", inferior_pid));
+ DEBUG_EVENTS (("gdb: child_close, inferior_ptid=%d\n",
+ PIDGET (inferior_ptid)));
}
struct target_ops child_ops;
void
_initialize_inftarg (void)
{
+ struct cmd_list_element *c;
+
init_child_ops ();
- add_com ("dll-symbols", class_files, dll_symbol_command,
- "Load dll library symbols from FILE.");
+ c = add_com ("dll-symbols", class_files, dll_symbol_command,
+ "Load dll library symbols from FILE.");
+ c->completer = filename_completer;
- auto_solib_add = 1;
add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
add_show_from_set (add_set_cmd ("new-console", class_support, var_boolean,
by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0
it means that the pid has died. Otherwise it is assumed to be alive. */
static int
-win32_child_thread_alive (int pid)
+win32_child_thread_alive (ptid_t ptid)
{
+ int pid = PIDGET (ptid);
+
return WaitForSingleObject (thread_rec (pid, FALSE)->h, 0) == WAIT_OBJECT_0 ?
FALSE : TRUE;
}
/* Convert pid to printable format. */
char *
-cygwin_pid_to_str (int pid)
+cygwin_pid_to_str (ptid_t ptid)
{
static char buf[80];
+ int pid = PIDGET (ptid);
+
if ((DWORD) pid == current_event.dwProcessId)
sprintf (buf, "process %d", pid);
else
}
register_loaded_dll (dll_name, base_addr + 0x1000);
- solib_symbols_add (dll_name, (CORE_ADDR) base_addr + 0x1000);
+ solib_symbols_add (dll_name, 0, (CORE_ADDR) base_addr + 0x1000);
out:
return 1;
map_code_section_args;
static void
-map_single_dll_code_section (bfd * abfd, asection * sect, PTR obj)
+map_single_dll_code_section (bfd * abfd, asection * sect, void *obj)
{
int old;
int update_coreops;
char *name;
if (dll_name == NULL || target == NULL)
return 0;
- name = strdup (dll_name);
+ name = xstrdup (dll_name);
dll_bfd = bfd_openr (name, "pei-i386");
if (dll_bfd == NULL)
return 0;
map_args.target = target;
map_args.addr = base_addr - bfd_section_vma (dll_bfd, lowest_sect);
- bfd_map_over_sections (dll_bfd, &map_single_dll_code_section, (PTR) (&map_args));
+ bfd_map_over_sections (dll_bfd, &map_single_dll_code_section, (void *) (&map_args));
}
return 1;
}
static void
-core_section_load_dll_symbols (bfd * abfd, asection * sect, PTR obj)
+core_section_load_dll_symbols (bfd * abfd, asection * sect, void *obj)
{
struct target_ops *target = (struct target_ops *) obj;
out:
if (buf)
- free (buf);
+ xfree (buf);
if (dll_name)
- free (dll_name);
+ xfree (dll_name);
return;
}
void
-child_solib_add (char *filename ATTRIBUTE_UNUSED, int from_tty ATTRIBUTE_UNUSED, struct target_ops *target)
+child_solib_add (char *filename ATTRIBUTE_UNUSED, int from_tty, struct target_ops *target, int readsyms)
{
+ if (!readsyms)
+ return;
if (core_bfd)
{
child_clear_solibs ();
else
{
if (solib_end && solib_end->name)
- solib_symbols_add (solib_end->name, solib_end->load_addr);
+ solib_symbols_add (solib_end->name, from_tty, solib_end->load_addr);
}
}
};
void
-_initialize_core_win32 ()
+_initialize_core_win32 (void)
{
add_core_fns (&win32_elf_core_fns);
}