From 1f1ebe21723580a1bd53e97779912114ab2fa532 Mon Sep 17 00:00:00 2001
From: Hannes Domani <ssbssa@yahoo.de>
Date: Thu, 31 Jan 2019 00:48:50 +0100
Subject: [PATCH 2/6] Read minidump file.

---
 bfd/coff-i386.c          |   2 +-
 bfd/coff-x86_64.c        |   2 +-
 bfd/coffgen.c            | 415 +++++++++++++++++++++++++++++++++++++++++++++++
 bfd/libcoff-in.h         |   3 +
 bfd/libcoff.h            |   3 +
 gdb/amd64-windows-tdep.c |  76 +++++++++
 gdb/windows-tdep.c       |  29 +++-
 7 files changed, 527 insertions(+), 3 deletions(-)

diff --git a/bfd/coff-i386.c b/bfd/coff-i386.c
index 7fb59dd31c..705df2eb75 100644
--- a/bfd/coff-i386.c
+++ b/bfd/coff-i386.c
@@ -677,7 +677,7 @@ const bfd_target
     _bfd_dummy_target,
     coff_object_p,
     bfd_generic_archive_p,
-    coff_object_p
+    coff_core_file_p
   },
 #endif
   {				/* bfd_set_format */
diff --git a/bfd/coff-x86_64.c b/bfd/coff-x86_64.c
index e0b32fddb8..0dc0136cd5 100644
--- a/bfd/coff-x86_64.c
+++ b/bfd/coff-x86_64.c
@@ -795,7 +795,7 @@ const bfd_target
     _bfd_dummy_target,
     amd64coff_object_p,
     bfd_generic_archive_p,
-    amd64coff_object_p
+    coff_core_file_p
   },
   {				/* bfd_set_format.  */
     _bfd_bool_bfd_false_error,
diff --git a/bfd/coffgen.c b/bfd/coffgen.c
index 31e6fa7a08..f9f2530952 100644
--- a/bfd/coffgen.c
+++ b/bfd/coffgen.c
@@ -3183,3 +3183,418 @@ _bfd_coff_close_and_cleanup (bfd *abfd)
     }
   return _bfd_generic_close_and_cleanup (abfd);
 }
+
+/* Read minidump file.  */
+
+#pragma pack(push,4)
+
+typedef struct
+{
+  uint8_t sig[4];
+  uint32_t ver;
+  uint32_t streamCount;
+  uint32_t streamRva;
+  uint32_t checksum;
+  uint32_t timestamp;
+  uint64_t flags;
+}
+dump_header;
+
+typedef struct
+{
+  uint32_t size;
+  uint32_t rva;
+}
+dump_loc_desc;
+
+typedef struct
+{
+  uint32_t type;
+  dump_loc_desc loc;
+}
+dump_directory;
+
+typedef enum
+{
+  UnusedStream,
+  ReservedStream0,
+  ReservedStream1,
+  ThreadListStream,
+  ModuleListStream,
+  MemoryListStream,
+  ExceptionStream,
+  SystemInfoStream,
+  ThreadExListStream,
+  Memory64ListStream,
+  CommentStreamA,
+  CommentStreamW,
+  HandleDataStream,
+  FunctionTableStream,
+  UnloadedModuleListStream,
+  MiscInfoStream,
+  MemoryInfoListStream,
+  ThreadInfoListStream,
+  HandleOperationListStream,
+  TokenStream,
+  JavaScriptDataStream,
+  SystemMemoryInfoStream,
+  ProcessVmCountersStream,
+  IptTraceStream,
+  ThreadNamesStream,
+  ceStreamNull,
+  ceStreamSystemInfo,
+  ceStreamException,
+  ceStreamModuleList,
+  ceStreamProcessList,
+  ceStreamThreadList,
+  ceStreamThreadContextList,
+  ceStreamThreadCallStackList,
+  ceStreamMemoryVirtualList,
+  ceStreamMemoryPhysicalList,
+  ceStreamBucketParameters,
+  ceStreamProcessModuleMap,
+  ceStreamDiagnosisList,
+  LastReservedStream
+}
+dump_stream_type;
+
+typedef struct
+{
+  uint64_t startAddress;
+  dump_loc_desc memory;
+}
+dump_memory_desc;
+
+typedef struct
+{
+  uint32_t threadId;
+  uint32_t suspendCount;
+  uint32_t priorityClass;
+  uint32_t priority;
+  uint64_t teb;
+  dump_memory_desc stack;
+  dump_loc_desc context;
+}
+dump_thread;
+
+typedef struct
+{
+  uint64_t startAddress;
+  uint64_t size;
+}
+dump_memory_desc64;
+
+typedef struct
+{
+  uint64_t rangeCount;
+  uint64_t baseRva;
+}
+dump_memory64_list;
+
+typedef struct
+{
+  uint32_t code;
+  uint32_t flags;
+  uint64_t record;
+  uint64_t address;
+  uint32_t parameterCount;
+  uint32_t unusedAlign;
+  uint64_t information[15];
+}
+dump_exception;
+
+typedef struct
+{
+  uint32_t threadId;
+  uint32_t unusedAlign;
+  dump_exception record;
+  dump_loc_desc context;
+}
+dump_exception_stream;
+
+typedef struct
+{
+  uint32_t signature;
+  uint32_t structVersion;
+  uint32_t fileVersionMS;
+  uint32_t fileVersionLS;
+  uint32_t productVersionMS;
+  uint32_t productVersionLS;
+  uint32_t fileFlagsMask;
+  uint32_t fileFlags;
+  uint32_t fileOS;
+  uint32_t fileType;
+  uint32_t fileSubtype;
+  uint32_t fileDateMS;
+  uint32_t fileDateLS;
+}
+dump_file_info;
+
+typedef struct
+{
+  uint64_t base;
+  uint32_t size;
+  uint32_t checksum;
+  uint32_t timestamp;
+  uint32_t nameRva;
+  dump_file_info versionInfo;
+  dump_loc_desc cvRecord;
+  dump_loc_desc miscRecord;
+  uint64_t reserved0;
+  uint64_t reserved1;
+}
+dump_module;
+
+#pragma pack(pop)
+
+
+static asection *
+make_bfd_asection (bfd *abfd, const char *name, flagword flags,
+		   file_ptr filepos, bfd_size_type size, bfd_vma vma)
+{
+  asection *asect;
+  char *newname;
+
+  newname = bfd_alloc (abfd, (bfd_size_type) strlen (name) + 1);
+  if (!newname)
+    return NULL;
+
+  strcpy (newname, name);
+
+  asect = bfd_make_section_anyway_with_flags (abfd, newname, flags);
+  if (!asect)
+    return NULL;
+
+  asect->filepos = filepos;
+  asect->size = size;
+  asect->vma = vma;
+
+  return asect;
+}
+
+const bfd_target *
+coff_core_file_p (bfd *abfd)
+{
+  dump_header header;
+  asection *sec;
+  uint32_t s;
+  uint32_t moduleListRva = 0;
+  uint32_t memoryListRva = 0;
+  uint32_t memory64ListRva = 0;
+  uint32_t exceptionRva = 0;
+  uint32_t threadListRva = 0;
+  uint32_t systemInfoRva = 0;
+
+  if (bfd_bread (&header, sizeof header, abfd) != sizeof header)
+    goto fail;
+
+  if (header.sig[0] != 'M' || header.sig[1] != 'D' ||
+      header.sig[2] != 'M' || header.sig[3] != 'P')
+    goto fail;
+
+  for (s = 0; s < header.streamCount; s++)
+    {
+      dump_directory dir;
+      if (bfd_bread (&dir, sizeof dir, abfd) != sizeof dir)
+	goto fail;
+
+      switch (dir.type)
+	{
+	case ModuleListStream:
+	  moduleListRva = dir.loc.rva;
+	  break;
+	case MemoryListStream:
+	  memoryListRva = dir.loc.rva;
+	  break;
+	case Memory64ListStream:
+	  memory64ListRva = dir.loc.rva;
+	  break;
+	case ExceptionStream:
+	  exceptionRva = dir.loc.rva;
+	  break;
+	case ThreadListStream:
+	  threadListRva = dir.loc.rva;
+	  break;
+	case SystemInfoStream:
+	  systemInfoRva = dir.loc.rva;
+	  break;
+	}
+    }
+
+  if (moduleListRva)
+    {
+      uint32_t moduleCount;
+      dump_module module;
+      char secname[32];
+      uint32_t size;
+      uint32_t m;
+
+      if (bfd_seek (abfd, moduleListRva, SEEK_SET) != 0
+	  || bfd_bread (&moduleCount, sizeof moduleCount, abfd)
+	  != sizeof moduleCount)
+	goto fail;
+
+      for (m = 0; m < moduleCount; m++)
+	{
+	  if (bfd_bread (&module, sizeof module, abfd) != sizeof module)
+	    goto fail;
+
+	  if (bfd_seek (abfd, module.nameRva, SEEK_SET) != 0
+	      || bfd_bread (&size, sizeof size, abfd) != sizeof size)
+	    goto fail;
+
+	  sprintf (secname, ".coremodule/%llx", module.base);
+
+	  sec = make_bfd_asection (abfd, secname,
+				   SEC_HAS_CONTENTS,
+				   module.nameRva + 4,
+				   size,
+				   0);
+	  if (!sec)
+	    goto fail;
+
+	  if (bfd_seek (abfd, moduleListRva + 4 + (m + 1) * sizeof module,
+			SEEK_SET) != 0)
+	    goto fail;
+	}
+    }
+
+  if (memoryListRva)
+    {
+      dump_memory_desc desc;
+      uint32_t rangeCount;
+      uint32_t r;
+
+      if (bfd_seek (abfd, memoryListRva, SEEK_SET) != 0
+	  || bfd_bread (&rangeCount, sizeof rangeCount, abfd)
+	  != sizeof rangeCount)
+	goto fail;
+
+      for (r = 0; r < rangeCount; r++)
+	{
+	  if (bfd_bread (&desc, sizeof desc, abfd) != sizeof desc)
+	    goto fail;
+
+	  sec = make_bfd_asection (abfd, ".data",
+				   SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS,
+				   desc.memory.rva,
+				   desc.memory.size,
+				   desc.startAddress);
+	  if (!sec)
+	    goto fail;
+	}
+    }
+
+  if (memory64ListRva)
+    {
+      dump_memory64_list list64;
+      dump_memory_desc64 desc64;
+      uint64_t r;
+
+      if (bfd_seek (abfd, memory64ListRva, SEEK_SET) != 0
+	  || bfd_bread (&list64, sizeof list64, abfd) != sizeof list64)
+	goto fail;
+
+      for (r = 0; r < list64.rangeCount; r++)
+	{
+	  if (bfd_bread (&desc64, sizeof desc64, abfd) != sizeof desc64)
+	    goto fail;
+
+	  sec = make_bfd_asection (abfd, ".data",
+				   SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS,
+				   list64.baseRva,
+				   desc64.size,
+				   desc64.startAddress);
+	  if (!sec)
+	    goto fail;
+
+	  list64.baseRva += desc64.size;
+	}
+    }
+
+  uint32_t exceptionThreadId = 0;
+  if (exceptionRva)
+    {
+      dump_exception_stream exception;
+      char secname[32];
+
+      if (bfd_seek (abfd, exceptionRva, SEEK_SET) != 0
+	  || bfd_bread (&exception, sizeof exception, abfd) != sizeof exception)
+	goto fail;
+
+      sec = make_bfd_asection (abfd, ".reg",
+			       SEC_HAS_CONTENTS,
+			       exception.context.rva,
+			       exception.context.size,
+			       0);
+      if (!sec)
+	goto fail;
+
+      sprintf (secname, ".reg/%u", exception.threadId);
+      sec = make_bfd_asection (abfd, secname,
+			       SEC_HAS_CONTENTS,
+			       exception.context.rva,
+			       exception.context.size,
+			       0);
+      if (!sec)
+	goto fail;
+
+      exceptionThreadId = exception.threadId;
+    }
+
+  if (threadListRva)
+    {
+      uint32_t threadCount;
+      dump_thread thread;
+      char secname[32];
+      uint32_t t;
+
+      if (bfd_seek (abfd, threadListRva, SEEK_SET) != 0
+	  || bfd_bread (&threadCount, sizeof threadCount, abfd)
+	  != sizeof threadCount)
+	goto fail;
+
+      for (t = 0; t < threadCount; t++)
+	{
+	  if (bfd_bread (&thread, sizeof thread, abfd) != sizeof thread)
+	    goto fail;
+
+	  sec = make_bfd_asection (abfd, ".stack",
+				   SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS,
+				   thread.stack.memory.rva,
+				   thread.stack.memory.size,
+				   thread.stack.startAddress);
+	  if (!sec)
+	    goto fail;
+
+	  if (thread.threadId != exceptionThreadId)
+	    {
+	      sprintf (secname, ".reg/%u", thread.threadId);
+	      sec = make_bfd_asection (abfd, secname,
+				       SEC_HAS_CONTENTS,
+				       thread.context.rva,
+				       thread.context.size,
+				       0);
+	      if (!sec)
+		goto fail;
+	    }
+	}
+    }
+
+  if (systemInfoRva)
+    {
+      uint16_t arch;
+      if (bfd_seek (abfd, systemInfoRva, SEEK_SET) != 0
+	  || bfd_bread (&arch, sizeof arch, abfd) != sizeof arch
+	  || (arch != 0 && arch != 9))
+	goto fail;
+
+      bfd_default_set_arch_mach (abfd, bfd_arch_i386,
+				 arch == 9 ? bfd_mach_x86_64 : 0);
+    }
+
+  return abfd->xvec;
+
+fail:
+  return NULL;
+}
diff --git a/bfd/libcoff-in.h b/bfd/libcoff-in.h
index 807817c94e..7c50313961 100644
--- a/bfd/libcoff-in.h
+++ b/bfd/libcoff-in.h
@@ -583,6 +583,9 @@ extern bfd_boolean bfd_coff_gc_sections
 extern const char *bfd_coff_group_name
   (bfd *, const asection *);
 
+extern const bfd_target *coff_core_file_p
+  (bfd *);
+
 #define coff_get_section_contents_in_window \
   _bfd_generic_get_section_contents_in_window
 
diff --git a/bfd/libcoff.h b/bfd/libcoff.h
index e6af9d6130..ee73e9f982 100644
--- a/bfd/libcoff.h
+++ b/bfd/libcoff.h
@@ -587,6 +587,9 @@ extern bfd_boolean bfd_coff_gc_sections
 extern const char *bfd_coff_group_name
   (bfd *, const asection *);
 
+extern const bfd_target *coff_core_file_p
+  (bfd *);
+
 #define coff_get_section_contents_in_window \
   _bfd_generic_get_section_contents_in_window
 
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index d4d79682dd..6e1774a617 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -33,6 +33,76 @@
 #include "value.h"
 #include <algorithm>
 
+#define AMD64_WINDOWS_SIZEOF_GREGSET 1232
+
+static int amd64_windows_gregset_reg_offset[] =
+{
+  120, /* rax */
+  144, /* rbx */
+  128, /* rcx */
+  136, /* rdx */
+
+  168, /* rsi */
+  176, /* rdi */
+  160, /* rbp */
+  152, /* rsp */
+
+  184, /* r8 */
+  192, /* r9 */
+  200, /* r10 */
+  208, /* r11 */
+  216, /* r12 */
+  224, /* r13 */
+  232, /* r14 */
+  240, /* r15 */
+
+  248, /* rip */
+  68, /* eflags */
+  56, /* cs */
+  66, /* ss */
+
+  58, /* ds */
+  60, /* es */
+  62, /* fs */
+  64, /* gs */
+
+  288, /* st0 */
+  304, /* st1 */
+  320, /* st2 */
+  336, /* st3 */
+  352, /* st4 */
+  368, /* st5 */
+  384, /* st6 */
+  400, /* st7 */
+
+  256, /* fctrl */
+  258, /* fstat */
+  260, /* ftag */
+  268, /* fiseg */
+  264, /* fioff */
+  276, /* foseg */
+  272, /* fooff */
+  262, /* fop */
+
+  416, /* xmm0 */
+  432, /* xmm1 */
+  448, /* xmm2 */
+  464, /* xmm3 */
+  480, /* xmm4 */
+  496, /* xmm5 */
+  512, /* xmm6 */
+  528, /* xmm7 */
+  544, /* xmm8 */
+  560, /* xmm9 */
+  576, /* xmm10 */
+  592, /* xmm11 */
+  608, /* xmm12 */
+  624, /* xmm13 */
+  640, /* xmm14 */
+  656, /* xmm15 */
+  280, /* mxcsr */
+};
+
 /* The registers used to pass integer arguments during a function call.  */
 static int amd64_windows_dummy_call_integer_regs[] =
 {
@@ -1211,6 +1281,8 @@ amd64_windows_auto_wide_charset (void)
 static void
 amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   /* The dwarf2 unwinder (appended very early by i386_gdbarch_init) is
      preferred over the SEH one.  The reasons are:
      - binaries without SEH but with dwarf2 debug info are correctly handled
@@ -1241,6 +1313,10 @@ amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   set_gdbarch_skip_prologue (gdbarch, amd64_windows_skip_prologue);
 
+  tdep->gregset_reg_offset = amd64_windows_gregset_reg_offset;
+  tdep->gregset_num_regs = ARRAY_SIZE (amd64_windows_gregset_reg_offset);
+  tdep->sizeof_gregset = AMD64_WINDOWS_SIZEOF_GREGSET;
+
   set_gdbarch_auto_wide_charset (gdbarch, amd64_windows_auto_wide_charset);
 }
 
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index 91a778cd81..6bbee97910 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -34,6 +34,9 @@
 #include "solib.h"
 #include "solib-target.h"
 #include "gdbcore.h"
+#include "charset.h"
+#include "coff/internal.h"
+#include "libcoff.h"
 
 /* Windows signal numbers differ between MinGW flavors and between
    those and Cygwin.  The below enumeration was gleaned from the
@@ -828,10 +831,13 @@ core_process_module_section (bfd *abfd, asection *sect, void *obj)
   char *module_name;
   size_t module_name_size;
   CORE_ADDR base_addr;
+  int is_module, is_coremodule;
 
   gdb_byte *buf = NULL;
 
-  if (!startswith (sect->name, ".module"))
+  is_module = startswith (sect->name, ".module");
+  is_coremodule = startswith (sect->name, ".coremodule/");
+  if (!is_module && !is_coremodule)
     return;
 
   buf = (gdb_byte *) xmalloc (bfd_section_size (sect) + 1);
@@ -845,6 +851,27 @@ core_process_module_section (bfd *abfd, asection *sect, void *obj)
     goto out;
 
 
+  if (is_coremodule)
+    {
+      auto_obstack host_name;
+      convert_between_encodings (target_wide_charset (data->gdbarch),
+				 host_charset (),
+				 buf, bfd_section_size (sect), 2,
+				 &host_name, translit_char);
+      obstack_grow_str0 (&host_name, "");
+      module_name = (char *) obstack_base (&host_name);
+
+      sscanf (sect->name + 12, "%llx", &base_addr);
+
+      if (data->module_count != 0)
+	windows_xfer_shared_library (module_name, base_addr,
+				     NULL, data->gdbarch, data->obstack);
+      data->module_count++;
+
+      xfree (buf);
+      return;
+    }
+
 
   /* A DWORD (data_type) followed by struct windows_core_module_info.  */
 
-- 
2.15.1.windows.2

