Use thiscall calling convention for class members
authorHannes Domani <ssbssa@yahoo.de>
Mon, 27 Apr 2020 13:58:09 +0000 (15:58 +0200)
committerHannes Domani <ssbssa@yahoo.de>
Thu, 30 Apr 2020 12:36:55 +0000 (14:36 +0200)
Non-static member functions for Windows 32bit programs need the thiscall
calling convention, so the 'this' pointer needs to be passed in ECX.

gdb/ChangeLog:

2020-04-30  Hannes Domani  <ssbssa@yahoo.de>

PR gdb/15559
* i386-tdep.c (i386_push_dummy_call): Call
i386_thiscall_push_dummy_call.
(i386_thiscall_push_dummy_call): New function.
* i386-tdep.h (i386_thiscall_push_dummy_call): Declare.
* i386-windows-tdep.c (i386_windows_push_dummy_call): New function.
(i386_windows_init_abi): Call set_gdbarch_push_dummy_call.

gdb/ChangeLog
gdb/i386-tdep.c
gdb/i386-tdep.h
gdb/i386-windows-tdep.c

index 830bc30979cba33643f816cab85f2ea48caacadc..d9f2b2c6f6bbd02629a70c5a59a0f86bfed21d73 100644 (file)
@@ -1,3 +1,13 @@
+2020-04-30  Hannes Domani  <ssbssa@yahoo.de>
+
+       PR gdb/15559
+       * i386-tdep.c (i386_push_dummy_call): Call
+       i386_thiscall_push_dummy_call.
+       (i386_thiscall_push_dummy_call): New function.
+       * i386-tdep.h (i386_thiscall_push_dummy_call): Declare.
+       * i386-windows-tdep.c (i386_windows_push_dummy_call): New function.
+       (i386_windows_init_abi): Call set_gdbarch_push_dummy_call.
+
 2020-04-29  Simon Marchi  <simon.marchi@efficios.com>
 
        * gdbarch.sh (do_read): Add shellcheck disable directive for
index 84edb3649e90baa6bdbd0f810238e9f319f5cebe..fc63635317b037e9c86ffd0c3264fac1fa055949 100644 (file)
@@ -2668,12 +2668,15 @@ i386_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr,
   return sp - 16;
 }
 
-static CORE_ADDR
-i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
-                     struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
-                     struct value **args, CORE_ADDR sp,
-                     function_call_return_method return_method,
-                     CORE_ADDR struct_addr)
+/* The "push_dummy_call" gdbarch method, optionally with the thiscall
+   calling convention.  */
+
+CORE_ADDR
+i386_thiscall_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+                              struct regcache *regcache, CORE_ADDR bp_addr,
+                              int nargs, struct value **args, CORE_ADDR sp,
+                              function_call_return_method return_method,
+                              CORE_ADDR struct_addr, bool thiscall)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   gdb_byte buf[4];
@@ -2709,7 +2712,7 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
            args_space += 4;
        }
 
-      for (i = 0; i < nargs; i++)
+      for (i = thiscall ? 1 : 0; i < nargs; i++)
        {
          int len = TYPE_LENGTH (value_enclosing_type (args[i]));
 
@@ -2761,6 +2764,10 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   /* ...and fake a frame pointer.  */
   regcache->cooked_write (I386_EBP_REGNUM, buf);
 
+  /* The 'this' pointer needs to be in ECX.  */
+  if (thiscall)
+    regcache->cooked_write (I386_ECX_REGNUM, value_contents_all (args[0]));
+
   /* MarkK wrote: This "+ 8" is all over the place:
      (i386_frame_this_id, i386_sigtramp_frame_this_id,
      i386_dummy_id).  It's there, since all frame unwinders for
@@ -2773,6 +2780,20 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   return sp + 8;
 }
 
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+                     struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
+                     struct value **args, CORE_ADDR sp,
+                     function_call_return_method return_method,
+                     CORE_ADDR struct_addr)
+{
+  return i386_thiscall_push_dummy_call (gdbarch, function, regcache, bp_addr,
+                                       nargs, args, sp, return_method,
+                                       struct_addr, false);
+}
+
 /* These registers are used for returning integers (and on some
    targets also for returning `struct' and `union' values when their
    size and alignment match an integer type).  */
index fa29e316a19bd384bebf6cafe15dc33d68116bc6..79b3b1f942898eb9b67b405294100ce0ff4ce3da 100644 (file)
@@ -399,6 +399,19 @@ extern CORE_ADDR i386_pe_skip_trampoline_code (struct frame_info *frame,
 extern CORE_ADDR i386_skip_main_prologue (struct gdbarch *gdbarch,
                                          CORE_ADDR pc);
 
+/* The "push_dummy_call" gdbarch method, optionally with the thiscall
+   calling convention.  */
+extern CORE_ADDR i386_thiscall_push_dummy_call (struct gdbarch *gdbarch,
+                                               struct value *function,
+                                               struct regcache *regcache,
+                                               CORE_ADDR bp_addr,
+                                               int nargs, struct value **args,
+                                               CORE_ADDR sp,
+                                               function_call_return_method
+                                               return_method,
+                                               CORE_ADDR struct_addr,
+                                               bool thiscall);
+
 /* Return whether the THIS_FRAME corresponds to a sigtramp routine.  */
 extern int i386_sigtramp_p (struct frame_info *this_frame);
 
index 3a07c862f23331a4206cebc575b55db270cb4f75..4824a9e5528d6c7f47b72817d2a09db4b2076f07 100644 (file)
@@ -200,6 +200,36 @@ i386_windows_auto_wide_charset (void)
   return "UTF-16";
 }
 
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+i386_windows_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+                             struct regcache *regcache, CORE_ADDR bp_addr,
+                             int nargs, struct value **args, CORE_ADDR sp,
+                             function_call_return_method return_method,
+                             CORE_ADDR struct_addr)
+{
+  /* For non-static member functions of 32bit Windows programs, the thiscall
+     calling convention is used, so the 'this' pointer is passed in ECX.  */
+  bool thiscall = false;
+
+  struct type *type = check_typedef (value_type (function));
+  if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    type = check_typedef (TYPE_TARGET_TYPE (type));
+
+  /* read_subroutine_type sets for non-static member functions the
+     artificial flag of the first parameter ('this' pointer).  */
+  if (TYPE_CODE (type) == TYPE_CODE_METHOD
+      && TYPE_NFIELDS (type) > 0
+      && TYPE_FIELD_ARTIFICIAL (type, 0)
+      && TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_PTR)
+    thiscall = 1;
+
+  return i386_thiscall_push_dummy_call (gdbarch, function, regcache, bp_addr,
+                                       nargs, args, sp, return_method,
+                                       struct_addr, thiscall);
+}
+
 /* Common parts for gdbarch initialization for Windows and Cygwin on i386.  */
 
 static void
@@ -234,6 +264,8 @@ i386_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   i386_windows_init_abi_common (info, gdbarch);
   windows_init_abi (info, gdbarch);
+
+  set_gdbarch_push_dummy_call (gdbarch, i386_windows_push_dummy_call);
 }
 
 /* gdbarch initialization for Cygwin on i386.  */