diff options
Diffstat (limited to 'gdb/windows-nat.c')
-rw-r--r-- | gdb/windows-nat.c | 231 |
1 files changed, 143 insertions, 88 deletions
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index dcc3d33..2f7e8cc 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* by Steve Chamberlain, sac@cygnus.com */ +/* Originally by Steve Chamberlain, sac@cygnus.com */ /* We assume we're being built with and will be used for cygwin. */ @@ -86,7 +86,7 @@ static int debug_registers_used = 0; #define CYGWIN_SIGNAL_STRING "cygwin: signal" #define CHECK(x) check (x, __FILE__,__LINE__) -#define DEBUG_EXEC(x) if (debug_exec) printf_unfiltered x +#define DEBUG_EXEC(x) if (debug_exec) printf_unfiltered x #define DEBUG_EVENTS(x) if (debug_events) printf_unfiltered x #define DEBUG_MEM(x) if (debug_memory) printf_unfiltered x #define DEBUG_EXCEPT(x) if (debug_exceptions) printf_unfiltered x @@ -128,14 +128,19 @@ static DWORD main_thread_id; /* Thread ID of the main thread */ /* Counts of things. */ static int exception_count = 0; static int event_count = 0; +static int saw_create; /* User options. */ static int new_console = 0; static int new_group = 1; -static int debug_exec = 0; /* show execution */ -static int debug_events = 0; /* show events from kernel */ -static int debug_memory = 0; /* show target memory accesses */ +static int debug_exec = 0; /* show execution */ +static int debug_events = 0; /* show events from kernel */ +static int debug_memory = 0; /* show target memory accesses */ static int debug_exceptions = 0; /* show target exceptions */ +static int useshell = 0; /* use shell for subprocesses */ + +/* Path to shell */ +static char shell[MAX_PATH + 1]; /* This vector maps GDB's idea of a register's number into an address in the win32 exception context vector. @@ -226,7 +231,7 @@ static void check (BOOL ok, const char *file, int line) { if (!ok) - printf_filtered ("error return %s:%d was %lu\n", file, line, + printf_filtered ("error return %s:%d was %lu\n", file, line, GetLastError ()); } @@ -284,7 +289,7 @@ child_add_thread (DWORD id, HANDLE h) th->next = thread_head.next; thread_head.next = th; add_thread (pid_to_ptid (id)); - /* Set the debug registers for the new thread in they are used. */ + /* Set the debug registers for the new thread in they are used. */ if (debug_registers_used) { /* Only change the value of the debug registers. */ @@ -604,14 +609,58 @@ register_loaded_dll (const char *name, DWORD load_addr) max_dll_name_len = len; } +char * +get_image_name (HANDLE h, void *address, int unicode) +{ + static char buf[(2 * MAX_PATH) + 1]; + DWORD size = unicode ? sizeof (WCHAR) : sizeof (char); + char *address_ptr; + int len = 0; + char b[2]; + DWORD done; + + /* Attempt to read the name of the dll that was detected. + This is documented to work only when actively debugging + a program. It will not work for attached processes. */ + if (address == NULL) + return NULL; + + ReadProcessMemory (h, address, &address_ptr, sizeof (address_ptr), &done); + + /* See if we could read the address of a string, and that the + address isn't null. */ + + if (done != sizeof (address_ptr) || !address_ptr) + return NULL; + + /* Find the length of the string */ + do + { + ReadProcessMemory (h, address_ptr + len * size, &b, size, &done); + len++; + } + while ((b[0] != 0 || b[size - 1] != 0) && done == size); + + if (!unicode) + ReadProcessMemory (h, address_ptr, buf, len, &done); + else + { + WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR)); + ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR), + &done); + + WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, len, 0, 0); + } + + return buf; +} + /* 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 (void *dummy) { 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; char *p; @@ -623,62 +672,8 @@ handle_load_dll (void *dummy) dll_name = dll_buf; - /* Attempt to read the name of the dll that was detected. - This is documented to work only when actively debugging - a program. It will not work for attached processes. */ - if (dll_name == NULL || *dll_name == '\0') - { - DWORD size = event->fUnicode ? sizeof (WCHAR) : sizeof (char); - int len = 0; - char b[2]; - - ReadProcessMemory (current_process_handle, - (LPCVOID) event->lpImageName, - (char *) &dll_name_ptr, - sizeof (dll_name_ptr), &done); - - /* See if we could read the address of a string, and that the - address isn't null. */ - - if (done != sizeof (dll_name_ptr) || !dll_name_ptr) - return 1; - - do - { - ReadProcessMemory (current_process_handle, - (LPCVOID) (dll_name_ptr + len * size), - &b, - size, - &done); - len++; - } - while ((b[0] != 0 || b[size - 1] != 0) && done == size); - - dll_name = alloca (len); - - if (event->fUnicode) - { - WCHAR *unicode_dll_name = (WCHAR *) alloca (len * sizeof (WCHAR)); - ReadProcessMemory (current_process_handle, - (LPCVOID) dll_name_ptr, - unicode_dll_name, - len * sizeof (WCHAR), - &done); - - WideCharToMultiByte (CP_ACP, 0, - unicode_dll_name, len, - dll_name, len, 0, 0); - } - else - { - ReadProcessMemory (current_process_handle, - (LPCVOID) dll_name_ptr, - dll_name, - len, - &done); - } - } - + if (*dll_name == '\0') + dll_name = get_image_name (current_process_handle, event->lpImageName, event->fUnicode); if (!dll_name) return 1; @@ -785,7 +780,7 @@ info_dll_command (char *ignore, int from_tty) if (!so->next) return; - printf_filtered ("%*s Load Address\n", -max_dll_name_len, "DLL Name"); + printf_filtered ("%*s Load Address\n", -max_dll_name_len, "DLL Name"); while ((so = so->next) != NULL) printf_filtered ("%*s %08lx\n", -max_dll_name_len, so->name, so->load_addr); @@ -943,7 +938,7 @@ child_continue (DWORD continue_status, int id) DEBUG_EVENTS (("ContinueDebugEvent (cpid=%ld, ctid=%ld, %s);\n", current_event.dwProcessId, current_event.dwThreadId, - continue_status == DBG_CONTINUE ? + continue_status == DBG_CONTINUE ? "DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED")); res = ContinueDebugEvent (current_event.dwProcessId, current_event.dwThreadId, @@ -966,7 +961,7 @@ child_continue (DWORD continue_status, int id) th->context.Dr2 = dr[2]; th->context.Dr3 = dr[3]; /* th->context.Dr6 = dr[6]; - FIXME: should we set dr6 also ?? */ + FIXME: should we set dr6 also ?? */ th->context.Dr7 = dr[7]; CHECK (SetThreadContext (th->h, &th->context)); th->context.ContextFlags = 0; @@ -1007,6 +1002,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "CREATE_THREAD_DEBUG_EVENT")); + if (saw_create != 1) + break; /* Record the existence of this thread */ th = child_add_thread (current_event.dwThreadId, current_event.u.CreateThread.hThread); @@ -1022,6 +1019,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXIT_THREAD_DEBUG_EVENT")); + if (saw_create != 1) + break; child_delete_thread (current_event.dwThreadId); th = &dummy_thread_info; break; @@ -1032,8 +1031,13 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) (unsigned) current_event.dwThreadId, "CREATE_PROCESS_DEBUG_EVENT")); CloseHandle (current_event.u.CreateProcessInfo.hFile); - current_process_handle = current_event.u.CreateProcessInfo.hProcess; + if (++saw_create != 1) + { + CloseHandle (current_event.u.CreateProcessInfo.hProcess); + break; + } + current_process_handle = current_event.u.CreateProcessInfo.hProcess; main_thread_id = current_event.dwThreadId; /* Add the main thread */ #if 0 @@ -1050,6 +1054,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXIT_PROCESS_DEBUG_EVENT")); + if (saw_create != 1) + break; ourstatus->kind = TARGET_WAITKIND_EXITED; ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; CloseHandle (current_process_handle); @@ -1062,6 +1068,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) (unsigned) current_event.dwThreadId, "LOAD_DLL_DEBUG_EVENT")); CloseHandle (current_event.u.LoadDll.hFile); + if (saw_create != 1) + break; catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL); registers_changed (); /* mark all regs invalid */ ourstatus->kind = TARGET_WAITKIND_LOADED; @@ -1074,6 +1082,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "UNLOAD_DLL_DEBUG_EVENT")); + if (saw_create != 1) + break; catch_errors (handle_unload_dll, NULL, (char *) "", RETURN_MASK_ALL); registers_changed (); /* mark all regs invalid */ /* ourstatus->kind = TARGET_WAITKIND_UNLOADED; @@ -1085,6 +1095,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXCEPTION_DEBUG_EVENT")); + if (saw_create != 1) + break; if (handle_exception (ourstatus)) retval = current_event.dwThreadId; break; @@ -1094,11 +1106,15 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "OUTPUT_DEBUG_STRING_EVENT")); + if (saw_create != 1) + break; if (handle_output_debug_string (ourstatus)) retval = main_thread_id; break; default: + if (saw_create != 1) + break; printf_unfiltered ("gdb: kernel event for pid=%ld tid=%ld\n", (DWORD) current_event.dwProcessId, (DWORD) current_event.dwThreadId); @@ -1107,7 +1123,7 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus) break; } - if (!retval) + if (!retval || saw_create != 1) CHECK (child_continue (continue_status, -1)); else { @@ -1159,7 +1175,7 @@ do_initial_child_stuff (DWORD pid) event_count = 0; exception_count = 0; debug_registers_changed = 0; - debug_registers_used = 0; + debug_registers_used = 0; for (i = 0; i < sizeof (dr) / sizeof (dr[0]); i++) dr[i] = 0; current_event.dwProcessId = pid; @@ -1309,7 +1325,6 @@ child_open (char *arg, int from_tty) static void child_create_inferior (char *exec_file, char *allargs, char **env) { - char real_path[MAXPATHLEN]; char *winenv; char *temp; int envlen; @@ -1319,6 +1334,8 @@ child_create_inferior (char *exec_file, char *allargs, char **env) BOOL ret; DWORD flags; char *args; + char real_path[MAXPATHLEN]; + char *toexec; if (!exec_file) error ("No executable specified, use `target exec'.\n"); @@ -1326,9 +1343,7 @@ child_create_inferior (char *exec_file, char *allargs, char **env) memset (&si, 0, sizeof (si)); si.cb = sizeof (si); - cygwin_conv_to_win32_path (exec_file, real_path); - - flags = DEBUG_ONLY_THIS_PROCESS; + flags = 0; if (new_group) flags |= CREATE_NEW_PROCESS_GROUP; @@ -1336,10 +1351,23 @@ child_create_inferior (char *exec_file, char *allargs, char **env) if (new_console) flags |= CREATE_NEW_CONSOLE; - args = alloca (strlen (real_path) + strlen (allargs) + 2); - - strcpy (args, real_path); + if (!useshell || !shell[0]) + { + flags = DEBUG_ONLY_THIS_PROCESS; + cygwin_conv_to_win32_path (exec_file, real_path); + toexec = real_path; + } + else + { + char *newallargs = alloca (sizeof (" -c 'exec '") + strlen (exec_file) + strlen (allargs) + 2); + sprintf (newallargs, " -c 'exec %s %s'", exec_file, allargs); + allargs = newallargs; + toexec = shell; + flags = DEBUG_PROCESS; + } + args = alloca (strlen (toexec) + strlen (allargs) + 2); + strcpy (args, toexec); strcat (args, " "); strcat (args, allargs); @@ -1431,6 +1459,12 @@ child_create_inferior (char *exec_file, char *allargs, char **env) CloseHandle (pi.hThread); CloseHandle (pi.hProcess); + + if (useshell && shell[0] != '\0') + saw_create = -1; + else + saw_create = 0; + do_initial_child_stuff (pi.dwProcessId); /* child_continue (DBG_CONTINUE, -1); */ @@ -1523,7 +1557,7 @@ child_resume (ptid_t ptid, int step, enum target_signal sig) #if 0 /* This code does not seem to work, because the kernel does probably not consider changes in the ExceptionRecord - structure when passing the exception to the inferior. + structure when passing the exception to the inferior. Note that this seems possible in the exception handler itself. */ { int i; @@ -1541,7 +1575,7 @@ child_resume (ptid_t ptid, int step, enum target_signal sig) } } #endif - DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n", + DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n", last_sig)); } @@ -1565,13 +1599,13 @@ child_resume (ptid_t ptid, int step, enum target_signal sig) { if (debug_registers_changed) { - th->context.Dr0 = dr[0]; - th->context.Dr1 = dr[1]; - th->context.Dr2 = dr[2]; - th->context.Dr3 = dr[3]; - /* th->context.Dr6 = dr[6]; - FIXME: should we set dr6 also ?? */ - th->context.Dr7 = dr[7]; + th->context.Dr0 = dr[0]; + th->context.Dr1 = dr[1]; + th->context.Dr2 = dr[2]; + th->context.Dr3 = dr[3]; + /* th->context.Dr6 = dr[6]; + FIXME: should we set dr6 also ?? */ + th->context.Dr7 = dr[7]; } CHECK (SetThreadContext (th->h, &th->context)); th->context.ContextFlags = 0; @@ -1655,6 +1689,7 @@ void _initialize_inftarg (void) { struct cmd_list_element *c; + const char *sh; init_child_ops (); @@ -1662,8 +1697,28 @@ _initialize_inftarg (void) "Load dll library symbols from FILE."); c->completer = filename_completer; + sh = getenv ("SHELL"); + if (!sh) + sh = "/bin/sh"; + if (access (sh, X_OK) != 0) + { + shell[0] = '\0'; + useshell = 0; + } + else + { + cygwin_conv_to_win32_path (sh, shell); + useshell = 1; + } + add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1); + add_show_from_set (add_set_cmd ("shell", class_support, var_boolean, + (char *) &useshell, + "Set use of shell to start subprocess.", + &setlist), + &showlist); + add_show_from_set (add_set_cmd ("new-console", class_support, var_boolean, (char *) &new_console, "Set creation of new console when creating child process.", @@ -2009,7 +2064,7 @@ _initialize_check_for_gdb_ini (void) { int len = strlen (oldini); char *newini = alloca (len + 1); - sprintf (newini, "%.*s.gdbinit", + sprintf (newini, "%.*s.gdbinit", (int) (len - (sizeof ("gdb.ini") - 1)), oldini); warning ("obsolete '%s' found. Rename to '%s'.", oldini, newini); } |