summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog10
-rw-r--r--gdb/amd64-windows-tdep.c9
-rw-r--r--gdb/i386-windows-tdep.c9
-rw-r--r--gdb/windows-tdep.c99
-rw-r--r--gdb/windows-tdep.h6
5 files changed, 127 insertions, 6 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7e844e63ebd..68c8bf74716 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,15 @@
2020-03-16 Simon Marchi <simon.marchi@efficios.com>
+ * windows-tdep.h (is_linked_with_cygwin_dll): New declaration.
+ * windows-tdep.c (CYGWIN_DLL_NAME): New.
+ (pe_import_directory_entry): New struct type.
+ (is_linked_with_cygwin_dll): New function.
+ * amd64-windows-tdep.c (amd64_windows_osabi_sniffer): Select
+ GDB_OSABI_CYGWIN if the BFD is linked with the Cygwin DLL.
+ * i386-windows-tdep.c (i386_windows_osabi_sniffer): Likewise.
+
+2020-03-16 Simon Marchi <simon.marchi@efficios.com>
+
* i386-windows-tdep.c: Mass-rename "cygwin" to "windows", except
i386_cygwin_core_osabi_sniffer.
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index 88ff794abcb..e0346f8628f 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -1249,10 +1249,13 @@ amd64_windows_osabi_sniffer (bfd *abfd)
{
const char *target_name = bfd_get_target (abfd);
- if (strcmp (target_name, "pei-x86-64") == 0)
- return GDB_OSABI_WINDOWS;
+ if (!streq (target_name, "pei-x86-64"))
+ return GDB_OSABI_UNKNOWN;
- return GDB_OSABI_UNKNOWN;
+ if (is_linked_with_cygwin_dll (abfd))
+ return GDB_OSABI_CYGWIN;
+
+ return GDB_OSABI_WINDOWS;
}
void _initialize_amd64_windows_tdep ();
diff --git a/gdb/i386-windows-tdep.c b/gdb/i386-windows-tdep.c
index a71ceda781f..bd6107b02f1 100644
--- a/gdb/i386-windows-tdep.c
+++ b/gdb/i386-windows-tdep.c
@@ -232,10 +232,13 @@ i386_windows_osabi_sniffer (bfd *abfd)
{
const char *target_name = bfd_get_target (abfd);
- if (strcmp (target_name, "pei-i386") == 0)
- return GDB_OSABI_WINDOWS;
+ if (!streq (target_name, "pei-i386"))
+ return GDB_OSABI_UNKNOWN;
- return GDB_OSABI_UNKNOWN;
+ if (is_linked_with_cygwin_dll (abfd))
+ return GDB_OSABI_CYGWIN;
+
+ return GDB_OSABI_WINDOWS;
}
static enum gdb_osabi
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index e02b1ceed38..31b7b57005d 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -38,6 +38,8 @@
#include "libcoff.h"
#include "solist.h"
+#define CYGWIN_DLL_NAME "cygwin1.dll"
+
/* Windows signal numbers differ between MinGW flavors and between
those and Cygwin. The below enumeration was gleaned from the
respective headers; the ones marked with MinGW64/Cygwin are defined
@@ -898,6 +900,103 @@ static const struct internalvar_funcs tlb_funcs =
NULL
};
+/* Layout of an element of a PE's Import Directory Table. Based on:
+
+ https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-directory-table
+ */
+
+struct pe_import_directory_entry
+{
+ uint32_t import_lookup_table_rva;
+ uint32_t timestamp;
+ uint32_t forwarder_chain;
+ uint32_t name_rva;
+ uint32_t import_address_table_rva;
+};
+
+gdb_static_assert (sizeof (pe_import_directory_entry) == 20);
+
+/* See windows-tdep.h. */
+
+bool
+is_linked_with_cygwin_dll (bfd *abfd)
+{
+ /* The list of DLLs a PE is linked to is in the .idata section. See:
+
+ https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-idata-section
+ */
+ asection *idata_section = bfd_get_section_by_name (abfd, ".idata");
+ if (idata_section == nullptr)
+ return false;
+
+ /* Find the virtual address of the .idata section. We must subtract this
+ from the RVAs (relative virtual addresses) to obtain an offset in the
+ section. */
+ bfd_vma idata_addr =
+ pe_data (abfd)->pe_opthdr.DataDirectory[PE_IMPORT_TABLE].VirtualAddress;
+
+ /* Map the section's data. */
+ bfd_size_type idata_size;
+ const gdb_byte *const idata_contents
+ = gdb_bfd_map_section (idata_section, &idata_size);
+ if (idata_contents == nullptr)
+ {
+ warning (_("Failed to get content of .idata section."));
+ return false;
+ }
+
+ const gdb_byte *iter = idata_contents;
+ const gdb_byte *end = idata_contents + idata_size;
+ const pe_import_directory_entry null_dir_entry = { 0 };
+
+ /* Iterate through all directory entries. */
+ while (true)
+ {
+ /* Is there enough space left in the section for another entry? */
+ if (iter + sizeof (pe_import_directory_entry) > end)
+ {
+ warning (_("Failed to parse .idata section: unexpected end of "
+ ".idata section."));
+ break;
+ }
+
+ pe_import_directory_entry *dir_entry = (pe_import_directory_entry *) iter;
+
+ /* Is it the end of list marker? */
+ if (memcmp (dir_entry, &null_dir_entry,
+ sizeof (pe_import_directory_entry)) == 0)
+ break;
+
+ bfd_vma name_addr = dir_entry->name_rva;
+
+ /* If the name's virtual address is smaller than the section's virtual
+ address, there's a problem. */
+ if (name_addr < idata_addr
+ || name_addr >= (idata_addr + idata_size))
+ {
+ warning (_("\
+Failed to parse .idata section: name's virtual address (0x%" BFD_VMA_FMT "x) \
+is outside .idata section's range [0x%" BFD_VMA_FMT "x, 0x%" BFD_VMA_FMT "x[."),
+ name_addr, idata_addr, idata_addr + idata_size);
+ break;
+ }
+
+ const gdb_byte *name = &idata_contents[name_addr - idata_addr];
+
+ /* Make sure we don't overshoot the end of the section with the streq. */
+ if (name + sizeof(CYGWIN_DLL_NAME) > end)
+ continue;
+
+ /* Finally, check if this is the dll name we are looking for. */
+ if (streq ((const char *) name, CYGWIN_DLL_NAME))
+ return true;
+
+ iter += sizeof(pe_import_directory_entry);
+ }
+
+ return false;
+}
+
void _initialize_windows_tdep ();
void
_initialize_windows_tdep ()
diff --git a/gdb/windows-tdep.h b/gdb/windows-tdep.h
index 34474f259c2..f2dc4260469 100644
--- a/gdb/windows-tdep.h
+++ b/gdb/windows-tdep.h
@@ -33,4 +33,10 @@ extern void windows_xfer_shared_library (const char* so_name,
extern void windows_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch);
+
+/* Return true if the Portable Executable behind ABFD uses the Cygwin dll
+ (cygwin1.dll). */
+
+extern bool is_linked_with_cygwin_dll (bfd *abfd);
+
#endif