This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Patch : gdbserver get_image_name on CE


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 (&current_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 (&current_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 (&current_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:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]