From a30bce9162fdd643b4e14a7e032042a7438995a5 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Sun, 4 Jun 2000 00:28:17 +0000 Subject: * win32-nat.c (safe_symbol_file_add_cleanup): Ensure that gdb_stderr is flushed before deleting and restoring it. (safe_symbol_file_add): Ensure that gdb_stderr is flushed before reassigning it. (handle_load_dll): Split into two functions so that WFI can handle shared library events. (child_solib_loaded_library_pathname): New function. (child_clear_solibs): New function. Clears shared library list. (child_solib_add): New function. Adds shared library symbols. (dll_symbol_command): New function. Handles "dll-symbol" command. (info_dll_command): New function. Handles info "sharedlibrary" command. (handle_exceptions): Eliminate 'ignore_trap' argument. (get_child_debug_event): Eliminate two arguments. Return "pid" when appropriate. Break out on most events to allow WFI to handle stuff. (child_wait): Accomodate get_child_debug_event changes. (child_attach): Clear thread list and list of loaded dlls. (child_create_inferior): Clear list of loaded dlls. Use wait_for_inferior in a loop to look for first "trap". (child_resume): Avoid accessing a possibly-freed thread pointer. (_initialize_inftarg): Add "dll-symbols", "sharedlibrary", and "info dll", and "info sharedlibrary" commands. * config/i386/tm-cygwin.h: Add some shared library (aka DLL) hooks. --- gdb/win32-nat.c | 256 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 183 insertions(+), 73 deletions(-) (limited to 'gdb/win32-nat.c') diff --git a/gdb/win32-nat.c b/gdb/win32-nat.c index e1e2898078a..7f0cb78d647 100644 --- a/gdb/win32-nat.c +++ b/gdb/win32-nat.c @@ -58,8 +58,6 @@ extern int (*ui_loop_hook) PARAMS ((int signo)); #define CONTEXT_DEBUGGER (CONTEXT_FULL | CONTEXT_FLOATING_POINT) #endif -#define FIRST_EXCEPTION 0xffffffff - /* The string sent by cygwin when it processes a signal. FIXME: This should be in a cygwin include file. */ #define CYGWIN_SIGNAL_STRING "cygwin: signal" @@ -415,6 +413,8 @@ failed: return 0; } +/* Encapsulate the information required in a call to + symbol_file_add_args */ struct safe_symbol_file_add_args { char *name; @@ -425,6 +425,8 @@ struct safe_symbol_file_add_args struct objfile *ret; }; +/* Call symbol_file_add with stderr redirected. We don't care if there + are errors. */ static int safe_symbol_file_add_stub (void *argv) { @@ -434,13 +436,16 @@ safe_symbol_file_add_stub (void *argv) #undef p } +/* Restore gdb's stderr after calling symbol_file_add */ static void safe_symbol_file_add_cleanup (void *gdb_stderrv) { + gdb_flush (gdb_stderr); ui_file_delete (gdb_stderr); gdb_stderr = (struct ui_file *)gdb_stderrv; } +/* symbol_file_add wrapper that prevents errors from being displayed. */ static struct objfile * safe_symbol_file_add (char *name, int from_tty, struct section_addr_info *addrs, @@ -452,6 +457,7 @@ safe_symbol_file_add (char *name, int from_tty, cleanup = make_cleanup (safe_symbol_file_add_cleanup, gdb_stderr); + gdb_flush (gdb_stderr); gdb_stderr = ui_file_new (); p.name = name; p.from_tty = from_tty; @@ -464,9 +470,19 @@ safe_symbol_file_add (char *name, int 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; + /* 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) { @@ -474,10 +490,12 @@ handle_load_dll (PTR dummy ATTRIBUTE_UNUSED) DWORD dll_name_ptr; DWORD done; char dll_buf[MAX_PATH + 1]; - char *p, *dll_name = NULL; - struct section_addr_info section_addrs; + struct so_stuff *so, *solast; + char *dll_name = NULL; + DWORD dll_base = 0; + int len; + char *p; - memset (§ion_addrs, 0, sizeof (section_addrs)); dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0'; if (!psapi_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf)) @@ -549,16 +567,94 @@ handle_load_dll (PTR dummy ATTRIBUTE_UNUSED) while ((p = strchr (dll_name, '\\'))) *p = '/'; + so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) + strlen (dll_name) + 8 + 2); + so->load_addr = (DWORD) event->lpBaseOfDll + 0x1000; + strcpy (so->name, dll_name); + + solib_end->next = so; + solib_end = so; + so->next = NULL; + + len = strlen (dll_name); + if (len > max_dll_name_len) + max_dll_name_len = len; + + return 1; +} + +/* Return name of last loaded DLL. */ +char * +child_solib_loaded_library_pathname (int pid) +{ + return !solib_end || !solib_end->name[0]? NULL : solib_end->name; +} + +/* Clear list of loaded DLLs. */ +void +child_clear_solibs (void) +{ + struct so_stuff *so, *so1 = solib_start.next; + + while ((so = so1) != NULL) + { + so1 = so->next; + free (so); + } + + solib_start.next = NULL; + solib_end = &solib_start; + max_dll_name_len = sizeof ("DLL Name") - 1; +} + +/* Add DLL symbol information. */ +void +child_solib_add (char *filename, int from_tty, struct target_ops *t) +{ + struct section_addr_info section_addrs; + /* The symbols in a dll are offset by 0x1000, which is the the offset from 0 of the first byte in an image - because of the file header and the section alignment. */ + if (!solib_end || !solib_end->name[0]) + return; + + memset (§ion_addrs, 0, sizeof (section_addrs)); section_addrs.other[0].name = ".text"; - section_addrs.other[0].addr = (int) event->lpBaseOfDll + 0x1000; - safe_symbol_file_add (dll_name, 0, §ion_addrs, 0, OBJF_SHARED); - printf_unfiltered ("%lx:%s\n", (DWORD) event->lpBaseOfDll, dll_name); + section_addrs.other[0].addr = solib_end->load_addr; + safe_symbol_file_add (solib_end->name, 0, §ion_addrs, 0, OBJF_SHARED); - return 1; + return; +} + +/* Load DLL symbol info. */ +void +dll_symbol_command (char *args, int from_tty) +{ + struct section_addr_info section_addrs; + + dont_repeat (); + + if (args == NULL) + error ("dll-symbols requires a file name"); + + safe_symbol_file_add (args, 0, NULL, 0, OBJF_SHARED); +} + +/* List currently loaded DLLs. */ +void +info_dll_command (char *ignore, int from_tty) +{ + struct so_stuff *so = &solib_start; + + if (!so->next) + return; + + printf ("%*s Load Address\n", -max_dll_name_len, "DLL Name"); + while ((so = so->next) != NULL) + printf_unfiltered ("%*s %08lx\n", -max_dll_name_len, so->name, so->load_addr); + + return; } /* Handle DEBUG_STRING output from child process. @@ -595,14 +691,11 @@ handle_output_debug_string (struct target_waitstatus *ourstatus) } static int -handle_exception (struct target_waitstatus *ourstatus, int ignore_trap) +handle_exception (struct target_waitstatus *ourstatus) { thread_info *th; DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode; - if (ignore_trap && code == EXCEPTION_BREAKPOINT) - return 0; - ourstatus->kind = TARGET_WAITKIND_STOPPED; /* Record the context of the current thread */ @@ -696,16 +789,15 @@ child_continue (DWORD continue_status, int id) handling by WFI (or whatever). */ static int -get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus, - DWORD target_event_code, int *retval) +get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourstatus) { int breakout = 0; BOOL debug_event; DWORD continue_status, event_code; thread_info *th = NULL; static thread_info dummy_thread_info; + int retval = 0; - *retval = 0; if (!(debug_event = WaitForDebugEvent (¤t_event, 1000))) goto out; @@ -713,7 +805,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst continue_status = DBG_CONTINUE; event_code = current_event.dwDebugEventCode; - breakout = event_code == target_event_code; + ourstatus->kind = TARGET_WAITKIND_SPURIOUS; switch (event_code) { @@ -728,6 +820,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst if (info_verbose) printf_unfiltered ("[New %s]\n", target_pid_to_str (current_event.dwThreadId)); + retval = current_event.dwThreadId; break; case EXIT_THREAD_DEBUG_EVENT: @@ -748,8 +841,11 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst main_thread_id = inferior_pid = current_event.dwThreadId; /* Add the main thread */ + th = child_add_thread (current_event.dwProcessId, + current_event.u.CreateProcessInfo.hProcess); th = child_add_thread (inferior_pid, current_event.u.CreateProcessInfo.hThread); + retval = ourstatus->value.related_pid = current_event.dwProcessId; break; case EXIT_PROCESS_DEBUG_EVENT: @@ -760,8 +856,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst ourstatus->kind = TARGET_WAITKIND_EXITED; ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; CloseHandle (current_process_handle); - *retval = current_event.dwProcessId; - breakout = 1; + retval = current_event.dwProcessId; break; case LOAD_DLL_DEBUG_EVENT: @@ -771,6 +866,9 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst "LOAD_DLL_DEBUG_EVENT")); catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL); registers_changed (); /* mark all regs invalid */ + ourstatus->kind = TARGET_WAITKIND_LOADED; + ourstatus->value.integer = 0; + retval = current_event.dwProcessId; break; case UNLOAD_DLL_DEBUG_EVENT: @@ -785,10 +883,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXCEPTION_DEBUG_EVENT")); - if (handle_exception (ourstatus, target_event_code == FIRST_EXCEPTION)) - *retval = current_event.dwThreadId; - else - breakout = -1; + handle_exception (ourstatus); + retval = current_event.dwThreadId; break; case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */ @@ -796,7 +892,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "OUTPUT_DEBUG_STRING_EVENT")); - handle_output_debug_string ( ourstatus); + if (handle_output_debug_string ( ourstatus)) + retval = current_event.dwProcessId; break; default: printf_unfiltered ("gdb: kernel event for pid=%ld tid=%ld\n", @@ -807,21 +904,19 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst break; } - if (breakout > 0) - current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE); - else if (!breakout) + if (!retval) CHECK (child_continue (continue_status, -1)); + else + current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE); out: - return breakout; + return retval; } /* Wait for interesting events to occur in the target process. */ static int child_wait (int pid, struct target_waitstatus *ourstatus) { - int retval; - /* 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 @@ -829,18 +924,21 @@ child_wait (int pid, struct target_waitstatus *ourstatus) isn't necessarily what you think it is. */ while (1) - if (get_child_debug_event (pid, ourstatus, EXCEPTION_DEBUG_EVENT, &retval)) - return retval; - else - { - int detach = 0; + { + int retval = get_child_debug_event (pid, ourstatus); + if (retval) + return retval; + else + { + int detach = 0; - if (ui_loop_hook != NULL) - detach = ui_loop_hook (0); + if (ui_loop_hook != NULL) + detach = ui_loop_hook (0); - if (detach) - child_kill_inferior (); - } + if (detach) + child_kill_inferior (); + } + } } /* Attach to process PID, then initialize for debugging it. */ @@ -865,6 +963,9 @@ child_attach (args, from_tty) exception_count = 0; event_count = 0; + child_init_thread_list (); + child_clear_solibs (); + if (from_tty) { char *exec_file = (char *) get_exec_file (0); @@ -936,11 +1037,10 @@ child_create_inferior (exec_file, allargs, env) BOOL ret; DWORD flags; char *args; + extern int stop_after_trap; if (!exec_file) - { - error ("No executable specified, use `target exec'.\n"); - } + error ("No executable specified, use `target exec'.\n"); memset (&si, 0, sizeof (si)); si.cb = sizeof (si); @@ -1057,16 +1157,23 @@ child_create_inferior (exec_file, allargs, env) inferior_pid = current_event.dwThreadId = pi.dwThreadId; push_target (&child_ops); child_init_thread_list (); - init_wait_for_inferior (); + child_clear_solibs (); clear_proceed_status (); + init_wait_for_inferior (); target_terminal_init (); target_terminal_inferior (); last_sig = 0; - /* Run until process and threads are loaded */ - while (!get_child_debug_event (inferior_pid, &dummy, - FIRST_EXCEPTION, &ret)) - continue; + while (1) + { + stop_after_trap = 1; + wait_for_inferior (); + if (stop_signal != TARGET_SIGNAL_TRAP) + resume (0, stop_signal); + else + break; + } + stop_after_trap = 0; /* child_continue (DBG_CONTINUE, -1);*/ proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0); @@ -1150,19 +1257,20 @@ child_resume (int pid, int step, enum target_signal sig) /* Get context for currently selected thread */ th = thread_rec (current_event.dwThreadId, FALSE); - if (step) + if (th) { -#ifdef i386 - /* Single step by setting t bit */ - child_fetch_inferior_registers (PS_REGNUM); - th->context.EFlags |= FLAG_TRACE_BIT; -#endif - } + if (step) + { + /* Single step by setting t bit */ + child_fetch_inferior_registers (PS_REGNUM); + th->context.EFlags |= FLAG_TRACE_BIT; + } - if (th->context.ContextFlags) - { - CHECK (SetThreadContext (th->h, &th->context)); - th->context.ContextFlags = 0; + if (th->context.ContextFlags) + { + CHECK (SetThreadContext (th->h, &th->context)); + th->context.ContextFlags = 0; + } } /* Allow continuing with the same signal that interrupted us. @@ -1242,48 +1350,50 @@ _initialize_inftarg () { init_child_ops (); - add_show_from_set - (add_set_cmd ("new-console", class_support, var_boolean, + add_com ("dll-symbols", class_files, dll_symbol_command, + "Load dll library symbols from FILE."); + + add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1); + + 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.", &setlist), &showlist); - add_show_from_set - (add_set_cmd ("new-group", class_support, var_boolean, + add_show_from_set (add_set_cmd ("new-group", class_support, var_boolean, (char *) &new_group, "Set creation of new group when creating child process.", &setlist), &showlist); - add_show_from_set - (add_set_cmd ("debugexec", class_support, var_boolean, + add_show_from_set (add_set_cmd ("debugexec", class_support, var_boolean, (char *) &debug_exec, "Set whether to display execution in child process.", &setlist), &showlist); - add_show_from_set - (add_set_cmd ("debugevents", class_support, var_boolean, + add_show_from_set (add_set_cmd ("debugevents", class_support, var_boolean, (char *) &debug_events, "Set whether to display kernel events in child process.", &setlist), &showlist); - add_show_from_set - (add_set_cmd ("debugmemory", class_support, var_boolean, + add_show_from_set (add_set_cmd ("debugmemory", class_support, var_boolean, (char *) &debug_memory, "Set whether to display memory accesses in child process.", &setlist), &showlist); - add_show_from_set - (add_set_cmd ("debugexceptions", class_support, var_boolean, + add_show_from_set (add_set_cmd ("debugexceptions", class_support, var_boolean, (char *) &debug_exceptions, - "Set whether to display kernel exceptions in child process.", + "Set whether to display kernel exceptions in child process.", &setlist), &showlist); + add_info ("dll", info_dll_command, "Status of loaded DLLs."); + add_info_alias ("sharedlibrary", "dll", 1); + add_target (&child_ops); } -- cgit v1.2.1