Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* We assume we're being built with and will be used for cygwin. */
#define CYGWIN_SIGNAL_STRING "cygwin: signal"
#define CHECK(x) check (x, __FILE__,__LINE__)
-#define DEBUG_EXEC(x) if (debug_exec) printf x
-#define DEBUG_EVENTS(x) if (debug_events) printf x
-#define DEBUG_MEM(x) if (debug_memory) printf x
-#define DEBUG_EXCEPT(x) if (debug_exceptions) printf 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
/* Forward declaration */
extern struct target_ops child_ops;
WaitForDebugEvent */
static HANDLE current_process_handle; /* Currently executing process */
static thread_info *current_thread; /* Info on currently selected thread */
-static DWORD main_thread_id; /* Thread ID of the main thread */
+static DWORD main_thread_id; /* Thread ID of the main thread */
+static pid_t cygwin_pid; /* pid of cygwin process */
/* 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 */
/* This vector maps GDB's idea of a register's number into an address
in the win32 exception context vector.
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 ());
}
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. */
HANDLE h = FindFirstFile(name, &w32_fd);
size_t len;
- FindClose (h);
- strcpy (buf, name);
- if (GetCurrentDirectory (MAX_PATH + 1, cwd))
+ if (h == INVALID_HANDLE_VALUE)
+ strcpy (buf, name);
+ else
{
- p = strrchr (buf, '\\');
- if (p)
- p[1] = '\0';
- SetCurrentDirectory (buf);
- GetFullPathName (w32_fd.cFileName, MAX_PATH, buf, &p);
- SetCurrentDirectory (cwd);
+ 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);
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;
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;
if (!so->next)
return;
- printf ("%*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);
return gotasig;
}
+static int
+display_selector (HANDLE thread, DWORD sel)
+{
+ LDT_ENTRY info;
+ if (GetThreadSelectorEntry (thread, sel, &info))
+ {
+ int base, limit;
+ printf_filtered ("0x%03lx: ", sel);
+ if (!info.HighWord.Bits.Pres)
+ {
+ puts_filtered ("Segment not present\n");
+ return 0;
+ }
+ base = (info.HighWord.Bits.BaseHi << 24) +
+ (info.HighWord.Bits.BaseMid << 16)
+ + info.BaseLow;
+ limit = (info.HighWord.Bits.LimitHi << 16) + info.LimitLow;
+ if (info.HighWord.Bits.Granularity)
+ limit = (limit << 12) | 0xfff;
+ printf_filtered ("base=0x%08x limit=0x%08x", base, limit);
+ if (info.HighWord.Bits.Default_Big)
+ puts_filtered(" 32-bit ");
+ else
+ puts_filtered(" 16-bit ");
+ switch ((info.HighWord.Bits.Type & 0xf) >> 1)
+ {
+ case 0:
+ puts_filtered ("Data (Read-Only, Exp-up");
+ break;
+ case 1:
+ puts_filtered ("Data (Read/Write, Exp-up");
+ break;
+ case 2:
+ puts_filtered ("Unused segment (");
+ break;
+ case 3:
+ puts_filtered ("Data (Read/Write, Exp-down");
+ break;
+ case 4:
+ puts_filtered ("Code (Exec-Only, N.Conf");
+ break;
+ case 5:
+ puts_filtered ("Code (Exec/Read, N.Conf");
+ break;
+ case 6:
+ puts_filtered ("Code (Exec-Only, Conf");
+ break;
+ case 7:
+ puts_filtered ("Code (Exec/Read, Conf");
+ break;
+ default:
+ printf_filtered ("Unknown type 0x%x",info.HighWord.Bits.Type);
+ }
+ if ((info.HighWord.Bits.Type & 0x1) == 0)
+ puts_filtered(", N.Acc");
+ puts_filtered (")\n");
+ if ((info.HighWord.Bits.Type & 0x10) == 0)
+ puts_filtered("System selector ");
+ printf_filtered ("Priviledge level = %d. ", info.HighWord.Bits.Dpl);
+ if (info.HighWord.Bits.Granularity)
+ puts_filtered ("Page granular.\n");
+ else
+ puts_filtered ("Byte granular.\n");
+ return 1;
+ }
+ else
+ {
+ printf_filtered ("Invalid selector 0x%lx.\n",sel);
+ return 0;
+ }
+}
+
+static void
+display_selectors (char * args, int from_tty)
+{
+ if (!current_thread)
+ {
+ puts_filtered ("Impossible to display selectors now.\n");
+ return;
+ }
+ if (!args)
+ {
+
+ puts_filtered ("Selector $cs\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegCs);
+ puts_filtered ("Selector $ds\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegDs);
+ puts_filtered ("Selector $es\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegEs);
+ puts_filtered ("Selector $ss\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegSs);
+ puts_filtered ("Selector $fs\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegFs);
+ puts_filtered ("Selector $gs\n");
+ display_selector (current_thread->h,
+ current_thread->context.SegGs);
+ }
+ else
+ {
+ int sel;
+ sel = parse_and_eval_long (args);
+ printf_filtered ("Selector \"%s\"\n",args);
+ display_selector (current_thread->h, sel);
+ }
+}
+
+static struct cmd_list_element *info_w32_cmdlist = NULL;
+
+static void
+info_w32_command (char *args, int from_tty)
+{
+ help_list (info_w32_cmdlist, "info w32 ", class_info, gdb_stdout);
+}
+
+
#define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \
- printf ("gdb: Target exception %s at 0x%08lx\n", x, \
+ printf_unfiltered ("gdb: Target exception %s at 0x%08lx\n", x, \
(DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress)
static int
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,
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;
(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);
(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;
(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
(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);
(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;
(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;
(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;
(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);
break;
}
- if (!retval)
+ if (!retval || saw_create != 1)
CHECK (child_continue (continue_status, -1));
else
{
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;
static BOOL WINAPI (*DebugActiveProcessStop)(DWORD);
static int
-has_detach_ability ()
+has_detach_ability (void)
{
static HMODULE kernel32 = NULL;
static void
child_create_inferior (char *exec_file, char *allargs, char **env)
{
- char real_path[MAXPATHLEN];
char *winenv;
char *temp;
int envlen;
BOOL ret;
DWORD flags;
char *args;
+ char real_path[MAXPATHLEN];
+ char *toexec;
+ char shell[MAX_PATH + 1]; /* Path to shell */
+ const char *sh;
+ int tty;
+ int ostdin, ostdout, ostderr;
if (!exec_file)
error ("No executable specified, use `target exec'.\n");
memset (&si, 0, sizeof (si));
si.cb = sizeof (si);
- cygwin_conv_to_win32_path (exec_file, real_path);
-
- flags = DEBUG_ONLY_THIS_PROCESS;
+ if (!useshell)
+ {
+ flags = DEBUG_ONLY_THIS_PROCESS;
+ cygwin_conv_to_win32_path (exec_file, real_path);
+ toexec = real_path;
+ }
+ else
+ {
+ char *newallargs;
+ sh = getenv ("SHELL");
+ if (!sh)
+ sh = "/bin/sh";
+ cygwin_conv_to_win32_path (sh, shell);
+ 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;
+ }
if (new_group)
flags |= CREATE_NEW_PROCESS_GROUP;
if (new_console)
flags |= CREATE_NEW_CONSOLE;
- args = alloca (strlen (real_path) + strlen (allargs) + 2);
-
- strcpy (args, real_path);
-
+ args = alloca (strlen (toexec) + strlen (allargs) + 2);
+ strcpy (args, toexec);
strcat (args, " ");
strcat (args, allargs);
/* Prepare the environment vars for CreateProcess. */
{
- /* This code use to assume all env vars were file names and would
+ /* This code used to assume all env vars were file names and would
translate them all to win32 style. That obviously doesn't work in the
general case. The current rule is that we only translate PATH.
We need to handle PATH because we're about to call CreateProcess and
*temp = 0;
}
+ if (!inferior_io_terminal)
+ tty = ostdin = ostdout = ostderr = -1;
+ else
+ {
+ tty = open (inferior_io_terminal, O_RDWR | O_NOCTTY);
+ if (tty < 0)
+ {
+ print_sys_errmsg (inferior_io_terminal, errno);
+ ostdin = ostdout = ostderr = -1;
+ }
+ else
+ {
+ ostdin = dup (0);
+ ostdout = dup (1);
+ ostderr = dup (2);
+ dup2 (tty, 0);
+ dup2 (tty, 1);
+ dup2 (tty, 2);
+ }
+ }
+
ret = CreateProcess (0,
args, /* command line */
NULL, /* Security */
NULL, /* current directory */
&si,
&pi);
+ if (tty >= 0)
+ {
+ close (tty);
+ dup2 (ostdin, 0);
+ dup2 (ostdout, 1);
+ dup2 (ostderr, 2);
+ close (ostdin);
+ close (ostdout);
+ close (ostderr);
+ }
+
if (!ret)
error ("Error creating process %s, (error %d)\n", exec_file, GetLastError ());
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); */
#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;
}
}
#endif
- DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
+ DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
last_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;
child_ops.to_terminal_inferior = terminal_inferior;
child_ops.to_terminal_ours_for_output = terminal_ours_for_output;
child_ops.to_terminal_ours = terminal_ours;
+ child_ops.to_terminal_save_ours = terminal_save_ours;
child_ops.to_terminal_info = child_terminal_info;
child_ops.to_kill = child_kill_inferior;
child_ops.to_load = 0;
}
void
-_initialize_inftarg (void)
+_initialize_win32_nat (void)
{
struct cmd_list_element *c;
c = add_com ("dll-symbols", class_files, dll_symbol_command,
"Load dll library symbols from FILE.");
- c->completer = filename_completer;
+ set_cmd_completer (c, filename_completer);
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.",
add_info ("dll", info_dll_command, "Status of loaded DLLs.");
add_info_alias ("sharedlibrary", "dll", 1);
+ add_prefix_cmd ("w32", class_info, info_w32_command,
+ "Print information specific to Win32 debugging.",
+ &info_w32_cmdlist, "info w32 ", 0, &infolist);
+
+ add_cmd ("selector", class_info, display_selectors,
+ "Display selectors infos.",
+ &info_w32_cmdlist);
+
add_target (&child_ops);
}
{
int len = strlen (oldini);
char *newini = alloca (len + 1);
- sprintf (newini, "%.*s.gdbinit", len - (sizeof ("gdb.ini") - 1), oldini);
+ sprintf (newini, "%.*s.gdbinit",
+ (int) (len - (sizeof ("gdb.ini") - 1)), oldini);
warning ("obsolete '%s' found. Rename to '%s'.", oldini, newini);
}
}