[v2,1/2] Display ExceptionRecord for $_siginfo

Message ID 20200208162614.4918-1-ssbssa@yahoo.de
State New, archived
Headers

Commit Message

Terekhov, Mikhail via Gdb-patches Feb. 8, 2020, 4:26 p.m. UTC
  Uses the $_siginfo convenience variable to show the last exception.

The type looks like this:

(gdb) pt $_siginfo
type = struct EXCEPTION_RECORD {
    DWORD ExceptionCode;
    DWORD ExceptionFlags;
    struct EXCEPTION_RECORD *ExceptionRecord;
    PVOID ExceptionAddress;
    DWORD NumberParameters;
    ULONG_PTR ExceptionInformation[15];
}

EXCEPTION_RECORD is documented at [1].

Example:

Program received signal SIGSEGV, Segmentation fault.
main () at crasher.c:4
4         *(int*)0x123 = 0;
(gdb) p $_siginfo
$1 = {
  ExceptionCode = 3221225477,
  ExceptionFlags = 0,
  ExceptionRecord = 0x0,
  ExceptionAddress = 0x401632 <main+18>,
  NumberParameters = 2,
  ExceptionInformation = {1, 291, 0 <repeats 13 times>}
}
(gdb) p/x $_siginfo.ExceptionCode
$2 = 0xc0000005
(gdb) p/x $_siginfo.ExceptionInformation[1]
$3 = 0x123

And 0xc0000005 is the value of EXCEPTION_ACCESS_VIOLATION.

[1] https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record

gdb/ChangeLog:

2020-02-08  Hannes Domani  <ssbssa@yahoo.de>

	* windows-nat.c (handle_exception): Set siginfo_er.
	(windows_nat_target::mourn_inferior): Reset siginfo_er.
	(windows_xfer_siginfo): New function.
	(windows_nat_target::xfer_partial): Call windows_xfer_siginfo.
	* windows-tdep.c (struct windows_gdbarch_data): New struct.
	(init_windows_gdbarch_data): New function.
	(get_windows_gdbarch_data): New function.
	(windows_get_siginfo_type): New function.
	(windows_init_abi): Register windows_get_siginfo_type.
	(_initialize_windows_tdep): Register init_windows_gdbarch_data.

gdbserver/ChangeLog:

2020-02-08  Hannes Domani  <ssbssa@yahoo.de>

	* win32-low.c (win32_clear_inferiors): Reset siginfo_er.
	(handle_exception): Set siginfo_er.
	(win32_xfer_siginfo): New function.
---
v2:
- coding style fixes
- more comments
- use documented field type names in EXCEPTION_RECORD
---
 gdb/windows-nat.c     | 31 +++++++++++++++++++
 gdb/windows-tdep.c    | 72 +++++++++++++++++++++++++++++++++++++++++++
 gdbserver/win32-low.c | 30 +++++++++++++++++-
 3 files changed, 132 insertions(+), 1 deletion(-)
  

Comments

Simon Marchi Feb. 8, 2020, 8 p.m. UTC | #1
On 2020-02-08 11:26 a.m., Hannes Domani via gdb-patches wrote:
> Uses the $_siginfo convenience variable to show the last exception.
> 
> The type looks like this:
> 
> (gdb) pt $_siginfo
> type = struct EXCEPTION_RECORD {
>     DWORD ExceptionCode;
>     DWORD ExceptionFlags;
>     struct EXCEPTION_RECORD *ExceptionRecord;
>     PVOID ExceptionAddress;
>     DWORD NumberParameters;
>     ULONG_PTR ExceptionInformation[15];
> }
> 
> EXCEPTION_RECORD is documented at [1].
> 
> Example:
> 
> Program received signal SIGSEGV, Segmentation fault.
> main () at crasher.c:4
> 4         *(int*)0x123 = 0;
> (gdb) p $_siginfo
> $1 = {
>   ExceptionCode = 3221225477,
>   ExceptionFlags = 0,
>   ExceptionRecord = 0x0,
>   ExceptionAddress = 0x401632 <main+18>,
>   NumberParameters = 2,
>   ExceptionInformation = {1, 291, 0 <repeats 13 times>}
> }
> (gdb) p/x $_siginfo.ExceptionCode
> $2 = 0xc0000005
> (gdb) p/x $_siginfo.ExceptionInformation[1]
> $3 = 0x123
> 
> And 0xc0000005 is the value of EXCEPTION_ACCESS_VIOLATION.
> 
> [1] https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record

Eli, could you please comment on this from a Windows user point of view, if this looks
correct to you?  Also, does this need a manual/NEWS update?

The patch otherwise looks ok to me.

Simon
  
Eli Zaretskii Feb. 8, 2020, 8:13 p.m. UTC | #2
> From: Simon Marchi <simark@simark.ca>
> Date: Sat, 8 Feb 2020 15:00:10 -0500
> 
> > Program received signal SIGSEGV, Segmentation fault.
> > main () at crasher.c:4
> > 4         *(int*)0x123 = 0;
> > (gdb) p $_siginfo
> > $1 = {
> >   ExceptionCode = 3221225477,
> >   ExceptionFlags = 0,
> >   ExceptionRecord = 0x0,
> >   ExceptionAddress = 0x401632 <main+18>,
> >   NumberParameters = 2,
> >   ExceptionInformation = {1, 291, 0 <repeats 13 times>}
> > }
> > (gdb) p/x $_siginfo.ExceptionCode
> > $2 = 0xc0000005
> > (gdb) p/x $_siginfo.ExceptionInformation[1]
> > $3 = 0x123
> > 
> > And 0xc0000005 is the value of EXCEPTION_ACCESS_VIOLATION.
> > 
> > [1] https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
> 
> Eli, could you please comment on this from a Windows user point of view, if this looks
> correct to you?

LGTM, although I'd prefer to have ExceptionCode be printed in hex by
default.  But I guess that could be tricky, and the next patch makes
then print as symbolic names anyway.

> Also, does this need a manual/NEWS update?

I think only NEWS, because the manual already says "on some targets",
and gives an example from GNU/Linux only.

Thanks.
  

Patch

diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 366c98fbf3..76fcdd6bd4 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -236,6 +236,7 @@  static DEBUG_EVENT current_event;	/* The current debug event from
 					   WaitForDebugEvent */
 static HANDLE current_process_handle;	/* Currently executing process */
 static windows_thread_info *current_thread;	/* Info on currently selected thread */
+static EXCEPTION_RECORD siginfo_er;	/* Contents of $_siginfo */
 
 /* Counts of things.  */
 static int exception_count = 0;
@@ -1167,6 +1168,8 @@  handle_exception (struct target_waitstatus *ourstatus)
   DWORD code = rec->ExceptionCode;
   handle_exception_result result = HANDLE_EXCEPTION_HANDLED;
 
+  memcpy (&siginfo_er, rec, sizeof siginfo_er);
+
   ourstatus->kind = TARGET_WAITKIND_STOPPED;
 
   /* Record the context of the current thread.  */
@@ -2863,6 +2866,7 @@  windows_nat_target::mourn_inferior ()
       CHECK (CloseHandle (current_process_handle));
       open_process_used = 0;
     }
+  siginfo_er.ExceptionCode = 0;
   inf_child_target::mourn_inferior ();
 }
 
@@ -2996,6 +3000,30 @@  windows_xfer_shared_libraries (struct target_ops *ops,
   return len != 0 ? TARGET_XFER_OK : TARGET_XFER_EOF;
 }
 
+/* Helper for windows_nat_target::xfer_partial that handles signal info.  */
+
+static enum target_xfer_status
+windows_xfer_siginfo (gdb_byte *readbuf, ULONGEST offset, ULONGEST len,
+		      ULONGEST *xfered_len)
+{
+  if (siginfo_er.ExceptionCode == 0)
+    return TARGET_XFER_E_IO;
+
+  if (readbuf == nullptr)
+    return TARGET_XFER_E_IO;
+
+  if (offset > sizeof (siginfo_er))
+    return TARGET_XFER_E_IO;
+
+  if (offset + len > sizeof (siginfo_er))
+    len = sizeof (siginfo_er) - offset;
+
+  memcpy (readbuf, (char *) &siginfo_er + offset, len);
+  *xfered_len = len;
+
+  return TARGET_XFER_OK;
+}
+
 enum target_xfer_status
 windows_nat_target::xfer_partial (enum target_object object,
 				  const char *annex, gdb_byte *readbuf,
@@ -3011,6 +3039,9 @@  windows_nat_target::xfer_partial (enum target_object object,
       return windows_xfer_shared_libraries (this, object, annex, readbuf,
 					    writebuf, offset, len, xfered_len);
 
+    case TARGET_OBJECT_SIGNAL_INFO:
+      return windows_xfer_siginfo (readbuf, offset, len, xfered_len);
+
     default:
       if (beneath () == NULL)
 	{
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index 6c9632d035..ad65b1b403 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -153,6 +153,30 @@  static const int FULL_TIB_SIZE = 0x1000;
 
 static bool maint_display_all_tib = false;
 
+static struct gdbarch_data *windows_gdbarch_data_handle;
+
+struct windows_gdbarch_data
+{
+  struct type *siginfo_type;
+};
+
+/* Allocate windows_gdbarch_data for an arch.  */
+
+static void *
+init_windows_gdbarch_data (struct gdbarch *gdbarch)
+{
+  return GDBARCH_OBSTACK_ZALLOC (gdbarch, struct windows_gdbarch_data);
+}
+
+/* Get windows_gdbarch_data of an arch.  */
+
+static struct windows_gdbarch_data *
+get_windows_gdbarch_data (struct gdbarch *gdbarch)
+{
+  return ((struct windows_gdbarch_data *)
+	  gdbarch_data (gdbarch, windows_gdbarch_data_handle));
+}
+
 /* Define Thread Local Base pointer type.  */
 
 static struct type *
@@ -656,6 +680,49 @@  windows_gdb_signal_to_target (struct gdbarch *gdbarch, enum gdb_signal signal)
   return -1;
 }
 
+/* Implement the "get_siginfo_type" gdbarch method.  */
+
+static struct type *
+windows_get_siginfo_type (struct gdbarch *gdbarch)
+{
+  struct windows_gdbarch_data *windows_gdbarch_data;
+  struct type *dword_type, *pvoid_type, *ulongptr_type;
+  struct type *siginfo_ptr_type, *siginfo_type;
+
+  windows_gdbarch_data = get_windows_gdbarch_data (gdbarch);
+  if (windows_gdbarch_data->siginfo_type != NULL)
+    return windows_gdbarch_data->siginfo_type;
+
+  dword_type = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch),
+				  1, "DWORD");
+  pvoid_type = arch_pointer_type (gdbarch, gdbarch_ptr_bit (gdbarch), "PVOID",
+				  builtin_type (gdbarch)->builtin_void);
+  ulongptr_type = arch_integer_type (gdbarch, gdbarch_ptr_bit (gdbarch),
+				     1, "ULONG_PTR");
+
+  siginfo_type = arch_composite_type (gdbarch, "EXCEPTION_RECORD",
+				      TYPE_CODE_STRUCT);
+  siginfo_ptr_type = arch_pointer_type (gdbarch, gdbarch_ptr_bit (gdbarch),
+					NULL, siginfo_type);
+
+  append_composite_type_field (siginfo_type, "ExceptionCode", dword_type);
+  append_composite_type_field (siginfo_type, "ExceptionFlags", dword_type);
+  append_composite_type_field (siginfo_type, "ExceptionRecord",
+			       siginfo_ptr_type);
+  append_composite_type_field (siginfo_type, "ExceptionAddress",
+			       pvoid_type);
+  append_composite_type_field (siginfo_type, "NumberParameters", dword_type);
+  /* The 64-bit variant needs some padding.  */
+  append_composite_type_field_aligned (siginfo_type, "ExceptionInformation",
+				       lookup_array_range_type (ulongptr_type,
+								0, 14),
+				       TYPE_LENGTH (ulongptr_type));
+
+  windows_gdbarch_data->siginfo_type = siginfo_type;
+
+  return siginfo_type;
+}
+
 /* To be called from the various GDB_OSABI_CYGWIN handlers for the
    various Windows architectures and machine types.  */
 
@@ -675,6 +742,8 @@  windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_gdb_signal_to_target (gdbarch, windows_gdb_signal_to_target);
 
   set_solib_ops (gdbarch, &solib_target_so_ops);
+
+  set_gdbarch_get_siginfo_type (gdbarch, windows_get_siginfo_type);
 }
 
 /* Implementation of `tlb' variable.  */
@@ -690,6 +759,9 @@  void _initialize_windows_tdep ();
 void
 _initialize_windows_tdep ()
 {
+  windows_gdbarch_data_handle
+    = gdbarch_data_register_post_init (init_windows_gdbarch_data);
+
   init_w32_command_list ();
   add_cmd ("thread-information-block", class_info, display_tib,
 	   _("Display thread information block."),
diff --git a/gdbserver/win32-low.c b/gdbserver/win32-low.c
index 2c4a9b1074..9d0343788f 100644
--- a/gdbserver/win32-low.c
+++ b/gdbserver/win32-low.c
@@ -75,6 +75,7 @@  static int attaching = 0;
 static HANDLE current_process_handle = NULL;
 static DWORD current_process_id = 0;
 static DWORD main_thread_id = 0;
+static EXCEPTION_RECORD siginfo_er;	/* Contents of $_siginfo */
 static enum gdb_signal last_sig = GDB_SIGNAL_0;
 
 /* The current debug event from WaitForDebugEvent.  */
@@ -801,6 +802,7 @@  win32_clear_inferiors (void)
     CloseHandle (current_process_handle);
 
   for_each_thread (delete_thread_info);
+  siginfo_er.ExceptionCode = 0;
   clear_inferiors ();
 }
 
@@ -1230,6 +1232,9 @@  handle_exception (struct target_waitstatus *ourstatus)
 {
   DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
 
+  memcpy (&siginfo_er, &current_event.u.Exception.ExceptionRecord,
+	  sizeof siginfo_er);
+
   ourstatus->kind = TARGET_WAITKIND_STOPPED;
 
   switch (code)
@@ -1772,6 +1777,29 @@  wince_hostio_last_error (char *buf)
 }
 #endif
 
+/* Write Windows signal info.  */
+
+static int
+win32_xfer_siginfo (const char *annex, unsigned char *readbuf,
+		    unsigned const char *writebuf, CORE_ADDR offset, int len)
+{
+  if (siginfo_er.ExceptionCode == 0)
+    return -1;
+
+  if (readbuf == nullptr)
+    return -1;
+
+  if (offset > sizeof (siginfo_er))
+    return -1;
+
+  if (offset + len > sizeof (siginfo_er))
+    len = sizeof (siginfo_er) - offset;
+
+  memcpy (readbuf, (char *) &siginfo_er + offset, len);
+
+  return len;
+}
+
 /* Write Windows OS Thread Information Block address.  */
 
 static int
@@ -1833,7 +1861,7 @@  static process_stratum_target win32_target_ops = {
   hostio_last_error_from_errno,
 #endif
   NULL, /* qxfer_osdata */
-  NULL, /* qxfer_siginfo */
+  win32_xfer_siginfo,
   NULL, /* supports_non_stop */
   NULL, /* async */
   NULL, /* start_non_stop */