/* Target-vector operations for controlling windows child processes, for GDB.
- Copyright (C) 1995-2012 Free Software Foundation, Inc.
+ Copyright (C) 1995-2014 Free Software Foundation, Inc.
Contributed by Cygnus Solutions, A Red Hat Company.
#include "objfiles.h"
#include "gdb_bfd.h"
#include "gdb_obstack.h"
-#include "gdb_string.h"
+#include <string.h>
#include "gdbthread.h"
#include "gdbcmd.h"
-#include <sys/param.h>
#include <unistd.h>
#include "exec.h"
#include "solist.h"
check (BOOL ok, const char *file, int line)
{
if (!ok)
- printf_filtered ("error return %s:%d was %lu\n", file, line,
- GetLastError ());
+ printf_filtered ("error return %s:%d was %u\n", file, line,
+ (unsigned) GetLastError ());
}
/* Find a thread record given a thread id. If GET_CONTEXT is not 0,
if (SuspendThread (th->h) == (DWORD) -1)
{
DWORD err = GetLastError ();
- warning (_("SuspendThread failed. (winerr %d)"),
- (int) err);
+
+ warning (_("SuspendThread (tid=0x%x) failed."
+ " (winerr %u)"),
+ (unsigned) id, (unsigned) err);
return NULL;
}
th->suspended = 1;
/* Delete a thread from the list of threads. */
static void
-windows_delete_thread (ptid_t ptid)
+windows_delete_thread (ptid_t ptid, DWORD exit_code)
{
thread_info *th;
DWORD id;
if (info_verbose)
printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (ptid));
+ else if (print_thread_events && id != main_thread_id)
+ printf_unfiltered (_("[%s exited with code %u]\n"),
+ target_pid_to_str (ptid), (unsigned) exit_code);
delete_thread (ptid);
for (th = &thread_head;
len = GetModuleFileNameEx (current_process_handle,
DllHandle[i], pathbuf, __PMAX);
if (len == 0)
- error (_("Error getting dll name: %lu."), GetLastError ());
+ error (_("Error getting dll name: %u."),
+ (unsigned) GetLastError ());
if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, pathbuf, dll_name_ret,
__PMAX) < 0)
error (_("Error converting dll name to POSIX: %d."), errno);
dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+ /* Try getting the DLL name by searching the list of known modules
+ and matching their base address against this new DLL's base address.
+
+ FIXME: brobecker/2013-12-10:
+ It seems odd to be going through this search if the DLL name could
+ simply be extracted via "event->lpImageName". Moreover, some
+ experimentation with various versions of Windows seem to indicate
+ that it might still be too early for this DLL to be listed when
+ querying the system about the current list of modules, thus making
+ this attempt pointless.
+
+ This code can therefore probably be removed. But at the time of
+ this writing, we are too close to creating the GDB 7.7 branch
+ for us to make such a change. We are therefore defering it. */
+
if (!get_module_name (event->lpBaseOfDll, dll_buf))
dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
dll_name = dll_buf;
+ /* Try getting the DLL name via the lpImageName field of the event.
+ Note that Microsoft documents this fields as strictly optional,
+ in the sense that it might be NULL. And the first DLL event in
+ particular is explicitly documented as "likely not pass[ed]"
+ (source: MSDN LOAD_DLL_DEBUG_INFO structure). */
if (*dll_name == '\0')
dll_name = get_image_name (current_process_handle,
event->lpImageName, event->fUnicode);
if (so->next->lm_info->load_addr == lpBaseOfDll)
{
struct so_list *sodel = so->next;
+
so->next = sodel->next;
if (!so->next)
solib_end = so;
DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name));
windows_free_so (sodel);
- solib_add (NULL, 0, NULL, auto_solib_add);
return 1;
}
char *p;
int sig = strtol (s + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0);
int gotasig = gdb_signal_from_host (sig);
+
ourstatus->value.sig = gotasig;
if (gotasig)
{
LPCVOID x;
- DWORD n;
+ SIZE_T n;
+
ourstatus->kind = TARGET_WAITKIND_STOPPED;
retval = strtoul (p, &p, 0);
if (!retval)
retval = main_thread_id;
- else if ((x = (LPCVOID) strtoul (p, &p, 0))
+ else if ((x = (LPCVOID) (uintptr_t) strtoull (p, NULL, 0))
&& ReadProcessMemory (current_process_handle, x,
&saved_context,
__COPY_CONTEXT_SIZE, &n)
if (GetThreadSelectorEntry (thread, sel, &info))
{
int base, limit;
- printf_filtered ("0x%03lx: ", sel);
+ printf_filtered ("0x%03x: ", (unsigned) sel);
if (!info.HighWord.Bits.Pres)
{
puts_filtered ("Segment not present\n");
if (err == ERROR_NOT_SUPPORTED)
printf_filtered ("Function not supported\n");
else
- printf_filtered ("Invalid selector 0x%lx.\n",sel);
+ printf_filtered ("Invalid selector 0x%x.\n", (unsigned) sel);
return 0;
}
}
/* Treat unhandled first chance exceptions specially. */
if (current_event.u.Exception.dwFirstChance)
return -1;
- printf_unfiltered ("gdb: unknown target exception 0x%08lx at %s\n",
- current_event.u.Exception.ExceptionRecord.ExceptionCode,
+ printf_unfiltered ("gdb: unknown target exception 0x%08x at %s\n",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode,
host_address_to_string (
current_event.u.Exception.ExceptionRecord.ExceptionAddress));
ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
thread_info *th;
BOOL res;
- DEBUG_EVENTS (("ContinueDebugEvent (cpid=%ld, ctid=%lx, %s);\n",
- current_event.dwProcessId, current_event.dwThreadId,
+ DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=0x%x, %s);\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId,
continue_status == DBG_CONTINUE ?
"DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED"));
open_process_used = 1;
else
{
- error (_("OpenProcess call failed, GetLastError = %lud"),
- GetLastError ());
+ error (_("OpenProcess call failed, GetLastError = %u"),
+ (unsigned) GetLastError ());
/* We can not debug anything in that case. */
}
main_thread_id = current_event.dwThreadId;
switch (event_code)
{
case CREATE_THREAD_DEBUG_EVENT:
- DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
+ DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
"CREATE_THREAD_DEBUG_EVENT"));
break;
case EXIT_THREAD_DEBUG_EVENT:
- DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
+ DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
"EXIT_THREAD_DEBUG_EVENT"));
if (current_event.dwThreadId != main_thread_id)
{
windows_delete_thread (ptid_build (current_event.dwProcessId, 0,
- current_event.dwThreadId));
+ current_event.dwThreadId),
+ current_event.u.ExitThread.dwExitCode);
th = &dummy_thread_info;
}
break;
case CREATE_PROCESS_DEBUG_EVENT:
- DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
+ DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
"CREATE_PROCESS_DEBUG_EVENT"));
current_process_handle = current_event.u.CreateProcessInfo.hProcess;
if (main_thread_id)
windows_delete_thread (ptid_build (current_event.dwProcessId, 0,
- main_thread_id));
+ main_thread_id),
+ 0);
main_thread_id = current_event.dwThreadId;
/* Add the main thread. */
th = windows_add_thread (ptid_build (current_event.dwProcessId, 0,
break;
case EXIT_PROCESS_DEBUG_EVENT:
- DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
+ DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
"EXIT_PROCESS_DEBUG_EVENT"));
break;
case LOAD_DLL_DEBUG_EVENT:
- DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
+ DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
"LOAD_DLL_DEBUG_EVENT"));
break;
case UNLOAD_DLL_DEBUG_EVENT:
- DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
+ DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
"UNLOAD_DLL_DEBUG_EVENT"));
break;
case EXCEPTION_DEBUG_EVENT:
- DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
+ DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
"EXCEPTION_DEBUG_EVENT"));
break;
case OUTPUT_DEBUG_STRING_EVENT: /* Message from the kernel. */
- DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n",
+ DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
"OUTPUT_DEBUG_STRING_EVENT"));
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);
- printf_unfiltered (" unknown event code %ld\n",
- current_event.dwDebugEventCode);
+ printf_unfiltered ("gdb: kernel event for pid=%u tid=0x%x\n",
+ (unsigned) current_event.dwProcessId,
+ (unsigned) current_event.dwThreadId);
+ printf_unfiltered (" unknown event code %u\n",
+ (unsigned) current_event.dwDebugEventCode);
break;
}
}
}
+/* On certain versions of Windows, the information about ntdll.dll
+ is not available yet at the time we get the LOAD_DLL_DEBUG_EVENT,
+ thus preventing us from reporting this DLL as an SO. This has been
+ witnessed on Windows 8.1, for instance. A possible explanation
+ is that ntdll.dll might be mapped before the SO info gets created
+ by the Windows system -- ntdll.dll is the first DLL to be reported
+ via LOAD_DLL_DEBUG_EVENT and other DLLs do not seem to suffer from
+ that problem.
+
+ If we indeed are missing ntdll.dll, this function tries to recover
+ from this issue, after the fact. Do nothing if we encounter any
+ issue trying to locate that DLL. */
+
+static void
+windows_ensure_ntdll_loaded (void)
+{
+ struct so_list *so;
+ HMODULE dummy_hmodule;
+ DWORD cb_needed;
+ HMODULE *hmodules;
+ int i;
+
+ for (so = solib_start.next; so != NULL; so = so->next)
+ if (FILENAME_CMP (lbasename (so->so_name), "ntdll.dll") == 0)
+ return; /* ntdll.dll already loaded, nothing to do. */
+
+ if (EnumProcessModules (current_process_handle, &dummy_hmodule,
+ sizeof (HMODULE), &cb_needed) == 0)
+ return;
+
+ if (cb_needed < 1)
+ return;
+
+ hmodules = (HMODULE *) alloca (cb_needed);
+ if (EnumProcessModules (current_process_handle, hmodules,
+ cb_needed, &cb_needed) == 0)
+ return;
+
+ for (i = 0; i < (int) (cb_needed / sizeof (HMODULE)); i++)
+ {
+ MODULEINFO mi;
+#ifdef __USEWIDE
+ wchar_t dll_name[__PMAX];
+ char name[__PMAX];
+#else
+ char dll_name[__PMAX];
+ char *name;
+#endif
+ if (GetModuleInformation (current_process_handle, hmodules[i],
+ &mi, sizeof (mi)) == 0)
+ continue;
+ if (GetModuleFileNameEx (current_process_handle, hmodules[i],
+ dll_name, sizeof (dll_name)) == 0)
+ continue;
+#ifdef __USEWIDE
+ wcstombs (name, dll_name, __PMAX);
+#else
+ name = dll_name;
+#endif
+ if (FILENAME_CMP (lbasename (name), "ntdll.dll") == 0)
+ {
+ solib_end->next = windows_make_so (name, mi.lpBaseOfDll);
+ solib_end = solib_end->next;
+ return;
+ }
+ }
+}
+
static void
do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
{
break;
}
+ /* FIXME: brobecker/2013-12-10: We should try another approach where
+ we first ignore all DLL load/unload events up until this point,
+ and then iterate over all modules to create the associated shared
+ objects. This is a fairly significant change, however, and we are
+ close to creating a release branch, so we are delaying it a bit,
+ after the branch is created. */
+ windows_ensure_ntdll_loaded ();
+
windows_initialization_done = 1;
inf->control.stop_soon = NO_STOP_QUIETLY;
stop_after_trap = 0;
}
static void
-windows_detach (struct target_ops *ops, char *args, int from_tty)
+windows_detach (struct target_ops *ops, const char *args, int from_tty)
{
int detached = 1;
if (!DebugActiveProcessStop (current_event.dwProcessId))
{
- error (_("Can't detach process %lu (error %lu)"),
- current_event.dwProcessId, GetLastError ());
+ error (_("Can't detach process %u (error %u)"),
+ (unsigned) current_event.dwProcessId, (unsigned) GetLastError ());
detached = 0;
}
DebugSetProcessKillOnExit (FALSE);
char *exec_file = get_exec_file (0);
if (exec_file == 0)
exec_file = "";
- printf_unfiltered ("Detaching from program: %s, Pid %lu\n", exec_file,
- current_event.dwProcessId);
+ printf_unfiltered ("Detaching from program: %s, Pid %u\n", exec_file,
+ (unsigned) current_event.dwProcessId);
gdb_flush (gdb_stdout);
}
+ i386_cleanup_dregs ();
inferior_ptid = null_ptid;
detach_inferior (current_event.dwProcessId);
/* Try to find exe name as symlink target of /proc/<pid>/exe. */
int nchars;
char procexe[sizeof ("/proc/4294967295/exe")];
- sprintf (procexe, "/proc/%u/exe", pid);
+
+ xsnprintf (procexe, sizeof (procexe), "/proc/%u/exe", pid);
nchars = readlink (procexe, path, sizeof(path));
if (nchars > 0 && nchars < sizeof (path))
{
cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t));
swprintf (cygallargs, len, L" -c 'exec %s %s'", exec_file, allargs);
#else
- cygallargs = (char *)
- alloca (sizeof (" -c 'exec '") + strlen (exec_file)
- + strlen (allargs) + 2);
- sprintf (cygallargs, " -c 'exec %s %s'", exec_file, allargs);
+ 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
toexec = shell;
flags |= DEBUG_PROCESS;
#endif
if (!ret)
- error (_("Error creating process %s, (error %d)."),
+ error (_("Error creating process %s, (error %u)."),
exec_file, (unsigned) GetLastError ());
CloseHandle (pi.hThread);
registers_changed (); /* refresh register state */
}
-static int
-windows_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len,
- int write, struct mem_attrib *mem,
- struct target_ops *target)
+/* Helper for windows_xfer_partial that handles memory transfers.
+ Arguments are like target_xfer_partial. */
+
+static LONGEST
+windows_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
+ ULONGEST memaddr, LONGEST len)
{
SIZE_T done = 0;
- if (write)
+ BOOL success;
+ DWORD lasterror = 0;
+
+ if (writebuf != NULL)
{
- DEBUG_MEM (("gdb: write target memory, %d bytes at 0x%08lx\n",
- len, (DWORD) (uintptr_t) memaddr));
- if (!WriteProcessMemory (current_process_handle,
- (LPVOID) (uintptr_t) memaddr, our,
- len, &done))
- done = 0;
+ DEBUG_MEM (("gdb: write target memory, %s bytes at %s\n",
+ plongest (len), core_addr_to_string (memaddr)));
+ success = WriteProcessMemory (current_process_handle,
+ (LPVOID) (uintptr_t) memaddr, writebuf,
+ len, &done);
+ if (!success)
+ lasterror = GetLastError ();
FlushInstructionCache (current_process_handle,
(LPCVOID) (uintptr_t) memaddr, len);
}
else
{
- DEBUG_MEM (("gdb: read target memory, %d bytes at 0x%08lx\n",
- len, (DWORD) (uintptr_t) memaddr));
- if (!ReadProcessMemory (current_process_handle,
- (LPCVOID) (uintptr_t) memaddr, our,
- len, &done))
- done = 0;
+ DEBUG_MEM (("gdb: read target memory, %s bytes at %s\n",
+ plongest (len), core_addr_to_string (memaddr)));
+ success = ReadProcessMemory (current_process_handle,
+ (LPCVOID) (uintptr_t) memaddr, readbuf,
+ len, &done);
+ if (!success)
+ lasterror = GetLastError ();
}
- return done;
+ if (!success && lasterror == ERROR_PARTIAL_COPY && done > 0)
+ return done;
+ else
+ return success ? done : TARGET_XFER_E_IO;
}
static void
}
static void
-windows_close (int x)
+windows_close (void)
{
DEBUG_EVENTS (("gdb: windows_close, inferior_ptid=%d\n",
- PIDGET (inferior_ptid)));
+ ptid_get_pid (inferior_ptid)));
}
/* Convert pid to printable format. */
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);
+ target_gdbarch (), &obstack);
obstack_grow_str0 (&obstack, "</library-list>\n");
buf = obstack_finish (&obstack);
len_avail = strlen (buf);
if (offset >= len_avail)
- return 0;
-
- if (len > len_avail - offset)
- len = len_avail - offset;
- memcpy (readbuf, buf + offset, len);
+ len= 0;
+ else
+ {
+ if (len > len_avail - offset)
+ len = len_avail - offset;
+ memcpy (readbuf, buf + offset, len);
+ }
obstack_free (&obstack, NULL);
return len;
switch (object)
{
case TARGET_OBJECT_MEMORY:
- if (readbuf)
- return (*ops->deprecated_xfer_memory) (offset, readbuf,
- len, 0/*read*/, NULL, ops);
- if (writebuf)
- return (*ops->deprecated_xfer_memory) (offset, (gdb_byte *) writebuf,
- len, 1/*write*/, NULL, ops);
- return -1;
+ return windows_xfer_memory (readbuf, writebuf, offset, len);
case TARGET_OBJECT_LIBRARIES:
return windows_xfer_shared_libraries (ops, object, annex, readbuf,
windows_ops.to_fetch_registers = windows_fetch_inferior_registers;
windows_ops.to_store_registers = windows_store_inferior_registers;
windows_ops.to_prepare_to_store = windows_prepare_to_store;
- windows_ops.deprecated_xfer_memory = windows_xfer_memory;
windows_ops.to_xfer_partial = windows_xfer_partial;
windows_ops.to_files_info = windows_files_info;
windows_ops.to_insert_breakpoint = memory_insert_breakpoint;
{
int len = strlen (oldini);
char *newini = alloca (len + 1);
- sprintf (newini, "%.*s.gdbinit",
- (int) (len - (sizeof ("gdb.ini") - 1)), oldini);
+
+ xsnprintf (newini, len + 1, "%.*s.gdbinit",
+ (int) (len - (sizeof ("gdb.ini") - 1)), oldini);
warning (_("obsolete '%s' found. Rename to '%s'."), oldini, newini);
}
}