diff options
-rw-r--r-- | gdb/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/amd64-windows-tdep.c | 9 | ||||
-rw-r--r-- | gdb/i386-windows-tdep.c | 9 | ||||
-rw-r--r-- | gdb/windows-tdep.c | 99 | ||||
-rw-r--r-- | gdb/windows-tdep.h | 6 |
5 files changed, 127 insertions, 6 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7e844e6..68c8bf7 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 88ff794..e0346f8 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 a71ceda..bd6107b 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 e02b1ce..31b7b57 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 34474f2..f2dc426 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 |