This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: Patch : gdbserver get_image_name on CE
- From: Danny Backx <danny dot backx at scarlet dot be>
- To: gdb-patches at sourceware dot org
- Date: Sat, 13 Jun 2009 16:29:45 +0200
- Subject: Re: Patch : gdbserver get_image_name on CE
- Reply-to: danny dot backx at scarlet dot be
As I said gdbserver works with this patch, on CE on an x86 clone.
For the record, I'm testing this with a Via Eden ULV processor on
Windows Embedded CE 6.0 .
Several issues solved with this patch :
1. Initialize the breakpoint structure to the right instruction.
2. Handle a case where the inferior refuses to start. See the
code after WaitForDebugEvent in win32-low.c .
3. Setjmp won't work on this platform, I've "#if 0"-ed it out.
Clearly not the right solution. Comment please.
4. Handle the failing call to GetThreadContext.
5. Read the DLL names in a way that works on x86.
The patch I've attached is relative to gdb-6.8 .
The configure.srv bit in the attachment was sent (by me) and committed
(by Pedro) earlier, don't pay attention to it.
The patch for #5 was also recently sent by me, probably not committed
yet.
After comments on this, I'll transform this into a real patch.
Note that gdb also requires a bit of work, I've not polluted this patch
with that. I have it working too.
Danny
--
Danny Backx ; danny.backx - at - scarlet.be ; http://danny.backx.info
diff -c /home/danny/src/gdb/gdb/gdb-6.8.orig/gdb/gdbserver/configure.srv ./configure.srv
*** /home/danny/src/gdb/gdb/gdb-6.8.orig/gdb/gdbserver/configure.srv 2008-02-11 23:00:31.000000000 +0100
--- ./configure.srv 2009-04-17 19:49:46.000000000 +0200
***************
*** 65,70 ****
--- 65,79 ----
srv_linux_regsets=yes
srv_linux_thread_db=yes
;;
+ i[34567]86-*-mingw*ce*)
+ srv_regobj=reg-i386.o
+ srv_tgtobj="win32-low.o win32-i386-low.o"
+ srv_tgtobj="${srv_tgtobj} wincecompat.o"
+ # hostio_last_error implementation is in win32-low.c
+ srv_hostio_err_objs=""
+ srv_mingw=yes
+ srv_mingwce=yes
+ ;;
i[34567]86-*-mingw*) srv_regobj=reg-i386.o
srv_tgtobj="win32-low.o win32-i386-low.o"
srv_mingw=yes
diff -c /home/danny/src/gdb/gdb/gdb-6.8.orig/gdb/gdbserver/server.c ./server.c
*** /home/danny/src/gdb/gdb/gdb-6.8.orig/gdb/gdbserver/server.c 2008-02-19 22:36:54.000000000 +0100
--- ./server.c 2009-06-13 11:57:58.000000000 +0200
***************
*** 1061,1071 ****
--- 1061,1073 ----
continue;
}
+ #if 0
if (setjmp (toplevel))
{
fprintf (stderr, "Exiting\n");
exit (1);
}
+ #endif
port = *next_arg;
next_arg++;
***************
*** 1141,1153 ****
shared library event" notice on gdb side. */
dlls_changed = 0;
if (setjmp (toplevel))
{
fprintf (stderr, "Killing inferior\n");
kill_inferior ();
exit (1);
}
!
if (status == 'W' || status == 'X')
was_running = 0;
else
--- 1143,1156 ----
shared library event" notice on gdb side. */
dlls_changed = 0;
+ #if 0
if (setjmp (toplevel))
{
fprintf (stderr, "Killing inferior\n");
kill_inferior ();
exit (1);
}
! #endif
if (status == 'W' || status == 'X')
was_running = 0;
else
***************
*** 1164,1169 ****
--- 1167,1173 ----
remote_open (port);
restart:
+ #if 0
if (setjmp (toplevel) != 0)
{
/* An error occurred. */
***************
*** 1173,1178 ****
--- 1177,1183 ----
putpkt (own_buf);
}
}
+ #endif
disable_async_io ();
while (!exit_requested)
Only in .: spu-low.c~
diff -c /home/danny/src/gdb/gdb/gdb-6.8.orig/gdb/gdbserver/utils.c ./utils.c
*** /home/danny/src/gdb/gdb/gdb-6.8.orig/gdb/gdbserver/utils.c 2008-01-01 23:53:14.000000000 +0100
--- ./utils.c 2009-05-31 15:38:07.000000000 +0200
***************
*** 65,71 ****
--- 65,75 ----
fflush (stdout);
vfprintf (stderr, string, args);
fprintf (stderr, "\n");
+ #ifdef __MINGW32CE__
+ exit(1);
+ #else
longjmp (toplevel, 1);
+ #endif
}
/* Print an error message and exit reporting failure.
diff -c /home/danny/src/gdb/gdb/gdb-6.8.orig/gdb/gdbserver/win32-i386-low.c ./win32-i386-low.c
*** /home/danny/src/gdb/gdb/gdb-6.8.orig/gdb/gdbserver/win32-i386-low.c 2008-01-01 23:53:14.000000000 +0100
--- ./win32-i386-low.c 2009-06-13 11:50:19.000000000 +0200
***************
*** 36,51 ****
debug_registers_used = 0;
}
static void
i386_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
{
! th->context.ContextFlags = \
! CONTEXT_FULL | \
! CONTEXT_FLOATING_POINT | \
! CONTEXT_EXTENDED_REGISTERS | \
CONTEXT_DEBUG_REGISTERS;
! GetThreadContext (th->h, &th->context);
debug_registers_changed = 0;
--- 36,71 ----
debug_registers_used = 0;
}
+ /*
+ * According to Mike Stall's .net debugging blog
+ * (http://blogs.msdn.com/jmstall/archive/2005/01/18/355697.aspx)
+ * the CONTEXT_EXTENDED_REGISTERS flag must be omitted if hardware doesn't
+ * support it. So I guess the only reasonable thing to do is just try.
+ */
static void
i386_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
{
! /* try all flags */
! th->context.ContextFlags =
! CONTEXT_FULL |
! CONTEXT_FLOATING_POINT |
! CONTEXT_EXTENDED_REGISTERS |
CONTEXT_DEBUG_REGISTERS;
! if (GetThreadContext (th->h, &th->context) == 0) {
! DWORD e = GetLastError();
!
! if (e == ERROR_INVALID_PARAMETER) {
! /* try limited set */
! th->context.ContextFlags = CONTEXT_FULL |
! CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS;
! if (GetThreadContext (th->h, &th->context) == 0) {
! DWORD e = GetLastError();
! printf("GetThreadContext failure %d\n", e);
! return;
! }
! }
! }
debug_registers_changed = 0;
***************
*** 190,195 ****
--- 210,236 ----
collect_register (r, context_offset);
}
+ /*
+ * The INT 3 instruction is traditionally used for x86 platform breakpointing.
+ * Microsoft also appears to use a DebugBreak function, which probably does the same.
+ * Gas translates "int $3" (or "int3") to a one-byte instruction : 0xCC .
+ *
+ * From Wikipedia :
+ *
+ * The INT 3 instruction is defined for use by debuggers to temporarily replace
+ * an instruction in a running program, in order to set a breakpoint. Other INT
+ * instructions are encoded using two bytes. This makes them unsuitable for use
+ * in patching instructions (which can be one byte long).
+ *
+ * The opcode for INT 3 is 0xCC, as opposite from the opcode for INT immediate,
+ * which is 0xCD imm8. According to Intel documentation: "Intel and Microsoft
+ * assemblers will not generate the CD03 opcode from any mnemonic" and 0xCC
+ * has some special features, which are not shared by "the normal 2-byte
+ * opcode for INT 3 (CD03)" [IA-32 Arch. Software Developerâs Manual. Vol. 2A]
+ */
+ static const unsigned char i386_wince_breakpoint = 0xCC;
+ #define i386_wince_breakpoint_len 1
+
struct win32_target_ops the_low_target = {
sizeof (mappings) / sizeof (mappings[0]),
i386_initial_stuff,
***************
*** 199,205 ****
i386_fetch_inferior_register,
i386_store_inferior_register,
i386_single_step,
! NULL, /* breakpoint */
! 0, /* breakpoint_len */
"i386" /* arch_string */
};
--- 240,246 ----
i386_fetch_inferior_register,
i386_store_inferior_register,
i386_single_step,
! &i386_wince_breakpoint, /* breakpoint */
! i386_wince_breakpoint_len, /* breakpoint_len */
"i386" /* arch_string */
};
diff -c /home/danny/src/gdb/gdb/gdb-6.8.orig/gdb/gdbserver/win32-low.c ./win32-low.c
*** /home/danny/src/gdb/gdb/gdb-6.8.orig/gdb/gdbserver/win32-low.c 2008-02-14 23:41:39.000000000 +0100
--- ./win32-low.c 2009-06-13 16:18:48.000000000 +0200
***************
*** 894,907 ****
loaded_dll (buf2, load_addr);
}
static 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.
--- 894,912 ----
loaded_dll (buf2, load_addr);
}
+ /*
+ * Warning : some parts of this function rely on sizeof(WCHAR) == 2
+ */
static char *
get_image_name (HANDLE h, void *address, int unicode)
{
! static char buf[(2 * MAX_PATH) + 1]; /* here */
DWORD size = unicode ? sizeof (WCHAR) : sizeof (char);
char *address_ptr;
+ #ifndef _WIN32_WCE
int len = 0;
! char b[2]; /* here */
! #endif
DWORD done;
/* Attempt to read the name of the dll that was detected.
***************
*** 924,932 ****
return NULL;
#endif
/* Find the length of the string */
while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done)
! && (b[0] != 0 || b[size - 1] != 0) && done == size)
continue;
if (!unicode)
--- 929,956 ----
return NULL;
#endif
+ #ifdef _WIN32_WCE
+ /* Always unicode */
+ /* Assume you can read it all in one go, or otherwise the done variable will
+ * tell you how far you've read.
+ */
+ WCHAR *wbuf = alloca ((MAX_PATH + 1) * size);
+ ReadProcessMemory (h, address_ptr, wbuf, MAX_PATH * size, &done);
+ if (done < 0 || done > MAX_PATH * size)
+ buf[0] = '\0';
+ else {
+ int n;
+ n = wcstombs (buf, wbuf, done);
+ if (n == (size_t)-1)
+ buf[0] = '\0';
+ /* No need to address the length limit case of the wcstombs call,
+ * buf has been allocated large enough. */
+ }
+ return buf;
+ #else
/* Find the length of the string */
while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done)
! && (b[0] != 0 || b[size - 1] != 0) && done == size) /* here */
continue;
if (!unicode)
***************
*** 936,946 ****
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;
}
typedef BOOL (WINAPI *winapi_EnumProcessModules) (HANDLE, HMODULE *,
--- 960,969 ----
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;
+ #endif
}
typedef BOOL (WINAPI *winapi_EnumProcessModules) (HANDLE, HMODULE *,
***************
*** 990,997 ****
DWORD cbNeeded;
BOOL ok;
! if (!load_psapi ())
goto failed;
cbNeeded = 0;
ok = (*win32_EnumProcessModules) (current_process_handle,
--- 1013,1021 ----
DWORD cbNeeded;
BOOL ok;
! if (!load_psapi ()) {
goto failed;
+ }
cbNeeded = 0;
ok = (*win32_EnumProcessModules) (current_process_handle,
***************
*** 1144,1149 ****
--- 1168,1174 ----
/* Windows does not report the image name of the dlls in the debug
event on attaches. We resort to iterating over the list of
loaded dlls looking for a match by image base. */
+ /* Note : no psapi.dll on CE, fall back to get_image_name below. */
if (!psapi_get_dll_name ((DWORD) event->lpBaseOfDll, dll_buf))
{
if (!server_waiting)
***************
*** 1368,1373 ****
--- 1393,1399 ----
happen is the user will see a spurious breakpoint. */
current_event.dwDebugEventCode = 0;
+ OUTMSG2(("attaching: before WaitForDebugEvent\n"));
if (!WaitForDebugEvent (¤t_event, 0))
{
OUTMSG2(("no attach events left\n"));
***************
*** 1383,1390 ****
/* Keep the wait time low enough for confortable remote
interruption, but high enough so gdbserver doesn't become a
bottleneck. */
! if (!WaitForDebugEvent (¤t_event, 250))
return 0;
}
gotevent:
--- 1409,1427 ----
/* Keep the wait time low enough for confortable remote
interruption, but high enough so gdbserver doesn't become a
bottleneck. */
! if (!WaitForDebugEvent (¤t_event, 250)) {
! /*
! * Sometimes an application will just not start up.
! * Detect this here, return in such a way that the loop ends.
! */
! DWORD e = GetLastError();
!
! if (e == ERROR_PIPE_NOT_CONNECTED) {
! ourstatus->kind = TARGET_WAITKIND_EXITED;
! return 1; /* break the loop in our caller */
! }
return 0;
+ }
}
gotevent: