v2 splits the vendoring of libudis86 into importing the original files and then patching them (and adding them to Makefile.am at that point). It also has both x86_64 and aarch64 implementations exit loops on rets or unconditional jumps.
Jeremy Drake (5): Cygwin: factor out find_fast_cwd_pointer to arch-specific file. Cygwin: vendor libudis86 1.7.2/libudis86 Cygwin: patch libudis86 to build as part of Cygwin Cygwin: use udis86 to find fast cwd pointer on x64 Cygwin: add find_fast_cwd_pointer_aarch64. winsup/cygwin/Makefile.am | 14 +- winsup/cygwin/fastcwd_aarch64.cc | 203 + winsup/cygwin/path.cc | 145 +- winsup/cygwin/udis86/decode.c | 1113 ++++ winsup/cygwin/udis86/decode.h | 195 + winsup/cygwin/udis86/extern.h | 109 + winsup/cygwin/udis86/itab.c | 8404 ++++++++++++++++++++++++ winsup/cygwin/udis86/itab.h | 680 ++ winsup/cygwin/udis86/types.h | 260 + winsup/cygwin/udis86/udint.h | 91 + winsup/cygwin/udis86/udis86.c | 464 ++ winsup/cygwin/x86_64/fastcwd_x86_64.cc | 172 + 12 files changed, 11727 insertions(+), 123 deletions(-) create mode 100644 winsup/cygwin/fastcwd_aarch64.cc create mode 100644 winsup/cygwin/udis86/decode.c create mode 100644 winsup/cygwin/udis86/decode.h create mode 100644 winsup/cygwin/udis86/extern.h create mode 100644 winsup/cygwin/udis86/itab.c create mode 100644 winsup/cygwin/udis86/itab.h create mode 100644 winsup/cygwin/udis86/types.h create mode 100644 winsup/cygwin/udis86/udint.h create mode 100644 winsup/cygwin/udis86/udis86.c create mode 100644 winsup/cygwin/x86_64/fastcwd_x86_64.cc Range-diff against v1: 1: fc59147412 = 1: 25a8b233f5 Cygwin: factor out find_fast_cwd_pointer to arch-specific file. 2: 5b5bccfc81 ! 2: faa2688d1f Cygwin: vendor libudis86 1.7.2 @@ Metadata Author: Jeremy Drake <cyg...@jdrake.com> ## Commit message ## - Cygwin: vendor libudis86 1.7.2 + Cygwin: vendor libudis86 1.7.2/libudis86 This does not include the source files responsible for generating AT&T- - or Intel-syntax assembly output, and ifdefs out the large table of - opcode strings since we're only interested in walking machine code, not - generating disassembly. - - Also included is a diff from the original libudis86 sources. + or Intel-syntax assembly output, or upstream's Makefile.{am,in}. Signed-off-by: Jeremy Drake <cyg...@jdrake.com> - ## winsup/cygwin/Makefile.am ## -@@ winsup/cygwin/Makefile.am: LIB_NAME=libcygwin.a - # sources - # - --# These objects are included directly into the import library - if TARGET_X86_64 - TARGET_FILES= \ - x86_64/bcopy.S \ -@@ winsup/cygwin/Makefile.am: TARGET_FILES= \ - x86_64/wmempcpy.S - endif - -+# These objects are included directly into the import library - LIB_FILES= \ - lib/_cygwin_crt0_common.cc \ - lib/atexit.c \ -@@ winsup/cygwin/Makefile.am: SEC_FILES= \ - TZCODE_FILES= \ - tzcode/localtime_wrapper.c - -+if TARGET_X86_64 -+UDIS86_FILES= \ -+ udis86/decode.c \ -+ udis86/itab.c \ -+ udis86/udis86.c -+endif -+ - DLL_FILES= \ - advapi32.cc \ - aio.cc \ -@@ winsup/cygwin/Makefile.am: libdll_a_SOURCES= \ - $(MM_FILES) \ - $(SEC_FILES) \ - $(TZCODE_FILES) \ -+ $(UDIS86_FILES) \ - $(GENERATED_FILES) - - # -@@ winsup/cygwin/Makefile.am: BUILT_SOURCES = \ - - # Every time we touch a source file, the version info has to be rebuilt - # to maintain a correct build date, especially in uname release output --dirs = $(srcdir) $(srcdir)/fhandler $(srcdir)/lib $(srcdir)/libc $(srcdir)/math $(srcdir)/mm $(srcdir)/regex $(srcdir)/sec $(srcdir)/tzcode -+dirs = $(srcdir) $(srcdir)/fhandler $(srcdir)/lib $(srcdir)/libc $(srcdir)/math $(srcdir)/mm $(srcdir)/regex $(srcdir)/sec $(srcdir)/tzcode $(srcdir)/udis86 - find_src_files = $(wildcard $(dir)/*.[chS]) $(wildcard $(dir)/*.cc) - src_files := $(foreach dir,$(dirs),$(find_src_files)) - - ## winsup/cygwin/udis86/decode.c (new) ## @@ +/* udis86 - libudis86/decode.c @@ winsup/cygwin/udis86/decode.c (new) + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ -+#include "winsup.h" -+#include "types.h" +#include "udint.h" ++#include "types.h" +#include "decode.h" + +#ifndef __UD_STANDALONE__ @@ winsup/cygwin/udis86/decode.c (new) +decode_prefixes(struct ud *u) +{ + int done = 0; -+ uint8_t curr = 0, last = 0; ++ uint8_t curr, last = 0; + UD_RETURN_ON_ERROR(u); + + do { @@ winsup/cygwin/udis86/decode.c (new) + break; + case OP_F: + u->br_far = 1; -+ fallthrough; ++ /* intended fall through */ + case OP_M: + if (MODRM_MOD(modrm(u)) == 3) { + UDERR(u, "expected modrm.mod != 3\n"); + } -+ fallthrough; ++ /* intended fall through */ + case OP_E: + decode_modrm_rm(u, operand, REGCLASS_GPR, size); + break; @@ winsup/cygwin/udis86/decode.c (new) + if (MODRM_MOD(modrm(u)) != 3) { + UDERR(u, "expected modrm.mod == 3\n"); + } -+ fallthrough; ++ /* intended fall through */ + case OP_Q: + decode_modrm_rm(u, operand, REGCLASS_MMX, size); + break; @@ winsup/cygwin/udis86/decode.c (new) + if (MODRM_MOD(modrm(u)) != 3) { + UDERR(u, "expected modrm.mod == 3\n"); + } -+ fallthrough; ++ /* intended fall through */ + case OP_W: + decode_modrm_rm(u, operand, REGCLASS_XMM, size); + break; @@ winsup/cygwin/udis86/decode.h (new) + return (primary_opcode & 0x02) != 0; +} + -+extern const struct ud_itab_entry ud_itab[]; -+extern const struct ud_lookup_table_list_entry ud_lookup_table_list[]; ++extern struct ud_itab_entry ud_itab[]; ++extern struct ud_lookup_table_list_entry ud_lookup_table_list[]; + +#endif /* UD_DECODE_H */ + @@ winsup/cygwin/udis86/extern.h (new) + +extern unsigned int ud_disassemble(struct ud*); + -+#ifndef __INSIDE_CYGWIN__ +extern void ud_translate_intel(struct ud*); + +extern void ud_translate_att(struct ud*); -+#endif /* __INSIDE_CYGWIN__ */ + +extern const char* ud_insn_asm(const struct ud* u); + @@ winsup/cygwin/udis86/extern.h (new) + +extern enum ud_mnemonic_code ud_insn_mnemonic(const struct ud *u); + -+#ifndef __INSIDE_CYGWIN__ +extern const char* ud_lookup_mnemonic(enum ud_mnemonic_code c); -+#endif /* __INSIDE_CYGWIN__ */ + +extern void ud_set_user_opaque_data(struct ud*, void*); + @@ winsup/cygwin/udis86/extern.h (new) ## winsup/cygwin/udis86/itab.c (new) ## @@ +/* itab.c -- generated by udis86:scripts/ud_itab.py, do no edit */ -+#include "winsup.h" +#include "decode.h" + +#define GROUP(n) (0x8000 | (n)) @@ winsup/cygwin/udis86/itab.c (new) +}; + + -+const struct ud_lookup_table_list_entry ud_lookup_table_list[] = { ++struct ud_lookup_table_list_entry ud_lookup_table_list[] = { + /* 000 */ { ud_itab__0, UD_TAB__OPC_TABLE, "table0" }, + /* 001 */ { ud_itab__1, UD_TAB__OPC_MODE, "/m" }, + /* 002 */ { ud_itab__2, UD_TAB__OPC_MODE, "/m" }, @@ winsup/cygwin/udis86/itab.c (new) +#define O_sIv { OP_sI, SZ_V } +#define O_sIz { OP_sI, SZ_Z } + -+const struct ud_itab_entry ud_itab[] = { ++struct ud_itab_entry ud_itab[] = { + /* 0000 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0001 */ { UD_Iadd, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0002 */ { UD_Iadd, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, @@ winsup/cygwin/udis86/itab.c (new) +}; + + -+#ifndef __INSIDE_CYGWIN__ +const char * ud_mnemonics_str[] = { +"invalid", + "3dnow", @@ winsup/cygwin/udis86/itab.c (new) + "movbe", + "crc32" +}; -+#endif /* __INSIDE_CYGWIN__ */ ## winsup/cygwin/udis86/itab.h (new) ## @@ @@ winsup/cygwin/udis86/itab.h (new) + UD_MAX_MNEMONIC_CODE +} UD_ATTR_PACKED; + -+#ifndef __INSIDE_CYGWIN__ +extern const char * ud_mnemonics_str[]; -+#endif /* __INSIDE_CYGWIN__ */ + +#endif /* UD_ITAB_H */ @@ winsup/cygwin/udis86/types.h (new) +#endif +#endif /* __KERNEL__ */ + -+#ifdef __INSIDE_CYGWIN__ -+# include <inttypes.h> -+# ifndef __UD_STANDALONE__ -+# define __UD_STANDALONE__ 1 -+# endif -+#endif /* __INSIDE_CYGWIN__ */ -+ -+ +#if defined(_MSC_VER) || defined(__BORLANDC__) +# include <stdint.h> +# include <stdio.h> @@ winsup/cygwin/udis86/types.h (new) + uint8_t modrm; + uint8_t primary_opcode; + void * user_opaque_data; -+ const struct ud_itab_entry * itab_entry; -+ const struct ud_lookup_table_list_entry *le; ++ struct ud_itab_entry * itab_entry; ++ struct ud_lookup_table_list_entry *le; +}; + +/* ----------------------------------------------------------------------------- @@ winsup/cygwin/udis86/types.h (new) +typedef struct ud ud_t; +typedef struct ud_operand ud_operand_t; + -+#ifndef __INSIDE_CYGWIN__ +#define UD_SYN_INTEL ud_translate_intel +#define UD_SYN_ATT ud_translate_att -+#endif /* __INSIDE_CYGWIN__ */ +#define UD_EOI (-1) +#define UD_INP_CACHE_SZ 32 +#define UD_VENDOR_AMD 0 @@ winsup/cygwin/udis86/udint.h (new) +#ifndef _UDINT_H_ +#define _UDINT_H_ + -+#ifndef __INSIDE_CYGWIN__ -+# ifdef HAVE_CONFIG_H -+# include <config.h> -+# endif /* HAVE_CONFIG_H */ -+#endif /* __INSIDE_CYGWIN__ */ ++#ifdef HAVE_CONFIG_H ++# include <config.h> ++#endif /* HAVE_CONFIG_H */ + +#if defined(UD_DEBUG) && HAVE_ASSERT_H +# include <assert.h> @@ winsup/cygwin/udis86/udint.h (new) + +#endif /* _UDINT_H_ */ - ## winsup/cygwin/udis86/udis86-modifications.diff (new) ## -@@ -+diff -ur udis86-1.7.2/libudis86/decode.c udis86/decode.c -+--- udis86-1.7.2/libudis86/decode.c -++++ udis86/decode.c -+@@ -23,8 +23,9 @@ -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+-#include "udint.h" -++#include "winsup.h" -+ #include "types.h" -++#include "udint.h" -+ #include "decode.h" -+ -+ #ifndef __UD_STANDALONE__ -+@@ -204,7 +205,7 @@ -+ decode_prefixes(struct ud *u) -+ { -+ int done = 0; -+- uint8_t curr, last = 0; -++ uint8_t curr = 0, last = 0; -+ UD_RETURN_ON_ERROR(u); -+ -+ do { -+@@ -653,12 +654,12 @@ -+ break; -+ case OP_F: -+ u->br_far = 1; -+- /* intended fall through */ -++ fallthrough; -+ case OP_M: -+ if (MODRM_MOD(modrm(u)) == 3) { -+ UDERR(u, "expected modrm.mod != 3\n"); -+ } -+- /* intended fall through */ -++ fallthrough; -+ case OP_E: -+ decode_modrm_rm(u, operand, REGCLASS_GPR, size); -+ break; -+@@ -677,7 +678,7 @@ -+ if (MODRM_MOD(modrm(u)) != 3) { -+ UDERR(u, "expected modrm.mod == 3\n"); -+ } -+- /* intended fall through */ -++ fallthrough; -+ case OP_Q: -+ decode_modrm_rm(u, operand, REGCLASS_MMX, size); -+ break; -+@@ -688,7 +689,7 @@ -+ if (MODRM_MOD(modrm(u)) != 3) { -+ UDERR(u, "expected modrm.mod == 3\n"); -+ } -+- /* intended fall through */ -++ fallthrough; -+ case OP_W: -+ decode_modrm_rm(u, operand, REGCLASS_XMM, size); -+ break; -+diff -ur udis86-1.7.2/libudis86/decode.h udis86/decode.h -+--- udis86-1.7.2/libudis86/decode.h -++++ udis86/decode.h -+@@ -183,8 +183,8 @@ -+ return (primary_opcode & 0x02) != 0; -+ } -+ -+-extern struct ud_itab_entry ud_itab[]; -+-extern struct ud_lookup_table_list_entry ud_lookup_table_list[]; -++extern const struct ud_itab_entry ud_itab[]; -++extern const struct ud_lookup_table_list_entry ud_lookup_table_list[]; -+ -+ #endif /* UD_DECODE_H */ -+ -+diff -ur udis86-1.7.2/libudis86/extern.h udis86/extern.h -+--- udis86-1.7.2/libudis86/extern.h -++++ udis86/extern.h -+@@ -60,9 +60,11 @@ -+ -+ extern unsigned int ud_disassemble(struct ud*); -+ -++#ifndef __INSIDE_CYGWIN__ -+ extern void ud_translate_intel(struct ud*); -+ -+ extern void ud_translate_att(struct ud*); -++#endif /* __INSIDE_CYGWIN__ */ -+ -+ extern const char* ud_insn_asm(const struct ud* u); -+ -+@@ -82,7 +84,9 @@ -+ -+ extern enum ud_mnemonic_code ud_insn_mnemonic(const struct ud *u); -+ -++#ifndef __INSIDE_CYGWIN__ -+ extern const char* ud_lookup_mnemonic(enum ud_mnemonic_code c); -++#endif /* __INSIDE_CYGWIN__ */ -+ -+ extern void ud_set_user_opaque_data(struct ud*, void*); -+ -+diff -ur udis86-1.7.2/libudis86/itab.c udis86/itab.c -+--- udis86-1.7.2/libudis86/itab.c -++++ udis86/itab.c -+@@ -1,4 +1,5 @@ -+ /* itab.c -- generated by udis86:scripts/ud_itab.py, do no edit */ -++#include "winsup.h" -+ #include "decode.h" -+ -+ #define GROUP(n) (0x8000 | (n)) -+@@ -5028,7 +5029,7 @@ -+ }; -+ -+ -+-struct ud_lookup_table_list_entry ud_lookup_table_list[] = { -++const struct ud_lookup_table_list_entry ud_lookup_table_list[] = { -+ /* 000 */ { ud_itab__0, UD_TAB__OPC_TABLE, "table0" }, -+ /* 001 */ { ud_itab__1, UD_TAB__OPC_MODE, "/m" }, -+ /* 002 */ { ud_itab__2, UD_TAB__OPC_MODE, "/m" }, -+@@ -6294,7 +6295,7 @@ -+ #define O_sIv { OP_sI, SZ_V } -+ #define O_sIz { OP_sI, SZ_Z } -+ -+-struct ud_itab_entry ud_itab[] = { -++const struct ud_itab_entry ud_itab[] = { -+ /* 0000 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, -+ /* 0001 */ { UD_Iadd, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, -+ /* 0002 */ { UD_Iadd, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, -+@@ -7749,6 +7750,7 @@ -+ }; -+ -+ -++#ifndef __INSIDE_CYGWIN__ -+ const char * ud_mnemonics_str[] = { -+ "invalid", -+ "3dnow", -+@@ -8399,3 +8401,4 @@ -+ "movbe", -+ "crc32" -+ }; -++#endif /* __INSIDE_CYGWIN__ */ -+diff -ur udis86-1.7.2/libudis86/itab.h udis86/itab.h -+--- udis86-1.7.2/libudis86/itab.h -++++ udis86/itab.h -+@@ -673,6 +673,8 @@ -+ UD_MAX_MNEMONIC_CODE -+ } UD_ATTR_PACKED; -+ -++#ifndef __INSIDE_CYGWIN__ -+ extern const char * ud_mnemonics_str[]; -++#endif /* __INSIDE_CYGWIN__ */ -+ -+ #endif /* UD_ITAB_H */ -+Only in udis86-1.7.2/libudis86/: Makefile.am -+Only in udis86-1.7.2/libudis86/: Makefile.in -+Only in udis86-1.7.2/libudis86/: syn.c -+Only in udis86-1.7.2/libudis86/: syn.h -+Only in udis86-1.7.2/libudis86/: syn-att.c -+Only in udis86-1.7.2/libudis86/: syn-intel.c -+diff -ur udis86-1.7.2/libudis86/types.h udis86/types.h -+--- udis86-1.7.2/libudis86/types.h -++++ udis86/types.h -+@@ -36,6 +36,14 @@ -+ #endif -+ #endif /* __KERNEL__ */ -+ -++#ifdef __INSIDE_CYGWIN__ -++# include <inttypes.h> -++# ifndef __UD_STANDALONE__ -++# define __UD_STANDALONE__ 1 -++# endif -++#endif /* __INSIDE_CYGWIN__ */ -++ -++ -+ #if defined(_MSC_VER) || defined(__BORLANDC__) -+ # include <stdint.h> -+ # include <stdio.h> -+@@ -221,8 +229,8 @@ -+ uint8_t modrm; -+ uint8_t primary_opcode; -+ void * user_opaque_data; -+- struct ud_itab_entry * itab_entry; -+- struct ud_lookup_table_list_entry *le; -++ const struct ud_itab_entry * itab_entry; -++ const struct ud_lookup_table_list_entry *le; -+ }; -+ -+ /* ----------------------------------------------------------------------------- -+@@ -235,8 +243,10 @@ -+ typedef struct ud ud_t; -+ typedef struct ud_operand ud_operand_t; -+ -++#ifndef __INSIDE_CYGWIN__ -+ #define UD_SYN_INTEL ud_translate_intel -+ #define UD_SYN_ATT ud_translate_att -++#endif /* __INSIDE_CYGWIN__ */ -+ #define UD_EOI (-1) -+ #define UD_INP_CACHE_SZ 32 -+ #define UD_VENDOR_AMD 0 -+diff -ur udis86-1.7.2/libudis86/udint.h udis86/udint.h -+--- udis86-1.7.2/libudis86/udint.h -++++ udis86/udint.h -+@@ -26,9 +26,11 @@ -+ #ifndef _UDINT_H_ -+ #define _UDINT_H_ -+ -+-#ifdef HAVE_CONFIG_H -+-# include <config.h> -+-#endif /* HAVE_CONFIG_H */ -++#ifndef __INSIDE_CYGWIN__ -++# ifdef HAVE_CONFIG_H -++# include <config.h> -++# endif /* HAVE_CONFIG_H */ -++#endif /* __INSIDE_CYGWIN__ */ -+ -+ #if defined(UD_DEBUG) && HAVE_ASSERT_H -+ # include <assert.h> -+diff -ur udis86-1.7.2/libudis86/udis86.c udis86/udis86.c -+--- udis86-1.7.2/libudis86/udis86.c -++++ udis86/udis86.c -+@@ -24,8 +24,9 @@ -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+-#include "udint.h" -++#include "winsup.h" -+ #include "extern.h" -++#include "udint.h" -+ #include "decode.h" -+ -+ #if !defined(__UD_STANDALONE__) -+@@ -34,6 +35,10 @@ -+ # endif -+ #endif /* !__UD_STANDALONE__ */ -+ -++#ifdef __INSIDE_CYGWIN__ -++#define sprintf __small_sprintf -++#endif /* __INSIDE_CYGWIN__ */ -++ -+ static void ud_inp_init(struct ud *u); -+ -+ /* ============================================================================= -+@@ -324,6 +329,7 @@ -+ } -+ -+ -++#ifndef __INSIDE_CYGWIN__ -+ /* ============================================================================= -+ * ud_lookup_mnemonic -+ * Looks up mnemonic code in the mnemonic string table. -+@@ -339,6 +345,7 @@ -+ return NULL; -+ } -+ } -++#endif /* __INSIDE_CYGWIN__ */ -+ -+ -+ /* - ## winsup/cygwin/udis86/udis86.c (new) ## @@ +/* udis86 - libudis86/udis86.c @@ winsup/cygwin/udis86/udis86.c (new) + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + -+#include "winsup.h" -+#include "extern.h" +#include "udint.h" ++#include "extern.h" +#include "decode.h" + +#if !defined(__UD_STANDALONE__) @@ winsup/cygwin/udis86/udis86.c (new) +# endif +#endif /* !__UD_STANDALONE__ */ + -+#ifdef __INSIDE_CYGWIN__ -+#define sprintf __small_sprintf -+#endif /* __INSIDE_CYGWIN__ */ -+ +static void ud_inp_init(struct ud *u); + +/* ============================================================================= @@ winsup/cygwin/udis86/udis86.c (new) +} + + -+#ifndef __INSIDE_CYGWIN__ +/* ============================================================================= + * ud_lookup_mnemonic + * Looks up mnemonic code in the mnemonic string table. @@ winsup/cygwin/udis86/udis86.c (new) + return NULL; + } +} -+#endif /* __INSIDE_CYGWIN__ */ + + +/* -: ---------- > 3: 04f7a44f59 Cygwin: patch libudis86 to build as part of Cygwin 3: 1c712acab4 ! 4: 0f06e96562 Cygwin: use udis86 to find fast cwd pointer on x64 @@ winsup/cygwin/x86_64/fastcwd_x86_64.cc -#define peek32(x) (*(int32_t *)(x)) +static inline const void * -+rip_rel_offset (const ud_t *ud_obj, const ud_operand_t *opr, int additional=0) ++rip_rel_offset (const ud_t *ud_obj, const ud_operand_t *opr, int sub_off=0) +{ + return (const void *) (ud_insn_off (ud_obj) + ud_insn_len (ud_obj) + -+ opr->lval.sdword + additional); ++ opr->lval.sdword - sub_off); +} /* This function scans the code in ntdll.dll to find the address of the @@ winsup/cygwin/x86_64/fastcwd_x86_64.cc: find_fast_cwd_pointer_x86_64 () + ud_set_input_buffer (&ud_obj, get_dir, 80); + ud_set_pc (&ud_obj, (const uint64_t) get_dir); + const ud_operand_t *opr; ++ ud_mnemonic_code_t insn; /* Search first relative call instruction in RtlGetCurrentDirectory_U. */ - const uint8_t *rcall = (const uint8_t *) memchr (get_dir, 0xe8, 80); - if (!rcall) + const uint8_t *use_cwd = NULL; -+ while (ud_disassemble (&ud_obj)) ++ while (ud_disassemble (&ud_obj) && ++ (insn = ud_insn_mnemonic (&ud_obj)) != UD_Iret && ++ insn != UD_Ijmp) + { -+ if (ud_insn_mnemonic (&ud_obj) == UD_Icall) ++ if (insn == UD_Icall) + { + opr = ud_insn_opr (&ud_obj, 0); + if (opr->type == UD_OP_JIMM && opr->size == 32) @@ winsup/cygwin/x86_64/fastcwd_x86_64.cc: find_fast_cwd_pointer_x86_64 () + PRTL_CRITICAL_SECTION lockaddr = NULL; + + /* both cases have an `lea rel(%rip)` on the lock */ -+ while (ud_disassemble (&ud_obj)) ++ while (ud_disassemble (&ud_obj) && ++ (insn = ud_insn_mnemonic (&ud_obj)) != UD_Iret && ++ insn != UD_Ijmp) { - /* The lock instruction tweaks the LockCount member, which is not at - the start of the PRTL_CRITICAL_SECTION structure. So we have to @@ winsup/cygwin/x86_64/fastcwd_x86_64.cc: find_fast_cwd_pointer_x86_64 () - near to the locking stuff. */ - movrbx = (const uint8_t *) memmem ((const char *) lock, 40, - "\x48\x8b\x1d", 3); -+ if (ud_insn_mnemonic (&ud_obj) == UD_Ilea) ++ if (insn == UD_Ilea) + { + /* this seems to follow intel syntax, in that operand 0 is the + dest and 1 is the src */ @@ winsup/cygwin/x86_64/fastcwd_x86_64.cc: find_fast_cwd_pointer_x86_64 () + + /* Next is either the `callq RtlEnterCriticalSection', or on Windows 8, + a `lock btr` */ -+ while (ud_disassemble (&ud_obj)) ++ bool found = false; ++ while (ud_disassemble (&ud_obj) && ++ (insn = ud_insn_mnemonic (&ud_obj)) != UD_Iret && ++ insn != UD_Ijmp) { - /* Usually the callq RtlEnterCriticalSection follows right after - fetching the lock address. */ @@ winsup/cygwin/x86_64/fastcwd_x86_64.cc: find_fast_cwd_pointer_x86_64 () - lock = (const uint8_t *) memmem ((const char *) use_cwd, 80, - "\x48\x8d\x0d", 3); - if (!lock) -+ ud_mnemonic_code_t insn = ud_insn_mnemonic (&ud_obj); + if (insn == UD_Icall) { - /* Windows 8.1 Preview calls `lea rel(rip),%r12' then some unrelated @@ winsup/cygwin/x86_64/fastcwd_x86_64.cc: find_fast_cwd_pointer_x86_64 () + { + if (ent_crit != rip_rel_offset (&ud_obj, opr)) + return NULL; ++ found = true; + break; + } } @@ winsup/cygwin/x86_64/fastcwd_x86_64.cc: find_fast_cwd_pointer_x86_64 () + opr->size == 32) + { + if (lockaddr != rip_rel_offset (&ud_obj, opr, -+ -(int) offsetof (RTL_CRITICAL_SECTION, LockCount))) ++ offsetof (RTL_CRITICAL_SECTION, LockCount))) + return NULL; -+ ++ found = true; + break; + } } + } ++ if (!found) ++ return NULL; - if (!lock) + fcwd_access_t **f_cwd_ptr = NULL; + ud_type_t reg = UD_NONE; + /* now we're looking for a movq rel(%rip) */ -+ while (ud_disassemble (&ud_obj)) ++ while (ud_disassemble (&ud_obj) && ++ (insn = ud_insn_mnemonic (&ud_obj)) != UD_Iret && ++ insn != UD_Ijmp) + { -+ if (ud_insn_mnemonic (&ud_obj) == UD_Imov) ++ if (insn == UD_Imov) { - return NULL; + const ud_operand_t *opr0 = ud_insn_opr (&ud_obj, 0); @@ winsup/cygwin/x86_64/fastcwd_x86_64.cc: find_fast_cwd_pointer_x86_64 () - const uint8_t *testrbx = (const uint8_t *) - memmem (movrbx + 7, 3, "\x48\x85\xdb", 3); - if (!testrbx) -+ if (!ud_disassemble (&ud_obj) || ud_insn_mnemonic (&ud_obj) != UD_Itest) ++ if (!f_cwd_ptr || !ud_disassemble (&ud_obj) || ++ ud_insn_mnemonic (&ud_obj) != UD_Itest) + return NULL; + + opr = ud_insn_opr (&ud_obj, 0); 4: 56d9b81dea ! 5: e3adc20c9f Cygwin: add find_fast_cwd_pointer_aarch64. @@ winsup/cygwin/fastcwd_aarch64.cc (new) +#endif +} + ++/* these ids and masks, as well as the names of the various other parts of ++ instructions used in this file, came from ++ https://developer.arm.com/documentation/ddi0602/2024-09/Index-by-Encoding ++ (Arm A-profile A64 Instruction Set Architecture) ++*/ +#define IS_INSN(pc, name) ((*(pc) & name##_mask) == name##_id) +static const uint32_t add_id = 0x11000000; +static const uint32_t add_mask = 0x7fc00000; +static const uint32_t adrp_id = 0x90000000; +static const uint32_t adrp_mask = 0x9f000000; ++static const uint32_t b_id = 0x14000000; ++static const uint32_t b_mask = 0xfc000000; +static const uint32_t bl_id = 0x94000000; +static const uint32_t bl_mask = 0xfc000000; +/* matches both cbz and cbnz */ @@ winsup/cygwin/fastcwd_aarch64.cc (new) +static const uint32_t cbz_mask = 0x7e000000; +static const uint32_t ldr_id = 0xb9400000; +static const uint32_t ldr_mask = 0xbfc00000; ++/* matches both ret and br (which are the same except ret is a 'hint' that ++ it's a subroutine return */ ++static const uint32_t ret_id = 0xd61f0000; ++static const uint32_t ret_mask = 0xffbffc1f; + ++/* this would work for either bl or b, but we only use it for bl */ +static inline LPCVOID +extract_bl_target (const uint32_t * pc) +{ -+ assert (IS_INSN (pc, bl)); ++ assert (IS_INSN (pc, bl) || IS_INSN (pc, b)); + int32_t offset = *pc & ~bl_mask; + /* sign extend */ + if (offset & (1 << 25)) @@ winsup/cygwin/fastcwd_aarch64.cc (new) +fcwd_access_t ** +find_fast_cwd_pointer_aarch64 () +{ -+ LPCVOID proc = GetArm64ProcAddress (GetModuleHandle ("ntdll"), -+ "RtlGetCurrentDirectory_U"); -+ const uint32_t *start = (uint32_t *) proc; ++ /* Fetch entry points of relevant functions in ntdll.dll. */ ++ HMODULE ntdll = GetModuleHandle ("ntdll.dll"); ++ if (!ntdll) ++ return NULL; ++ LPCVOID get_dir = GetArm64ProcAddress (ntdll, "RtlGetCurrentDirectory_U"); ++ LPCVOID ent_crit = GetArm64ProcAddress (ntdll, "RtlEnterCriticalSection"); ++ if (!get_dir || !ent_crit) ++ return NULL; ++ ++ LPCVOID use_cwd = NULL; ++ const uint32_t *start = (const uint32_t *) get_dir; + const uint32_t *pc = start; + /* find the call to RtlpReferenceCurrentDirectory, and get its address */ -+ for (; pc < start + 20; pc++) ++ for (; pc < start + 20 && !IS_INSN (pc, ret) && !IS_INSN (pc, b); pc++) + { + if (IS_INSN (pc, bl)) + { -+ proc = extract_bl_target (pc); ++ use_cwd = extract_bl_target (pc); + break; + } + } -+ if (proc == start) ++ if (!use_cwd) + return NULL; + -+ start = pc = (uint32_t *) proc; ++ start = pc = (const uint32_t *) use_cwd; + + const uint32_t *ldrpc = NULL; + uint32_t ldroffset, ldrsz; + uint32_t ldrrn, ldrrd; + + /* find the ldr (immediate unsigned offset) for RtlpCurDirRef */ -+ for (; pc < start + 20; pc++) ++ for (; pc < start + 20 && !IS_INSN (pc, ret) && !IS_INSN (pc, b); pc++) + { + if (IS_INSN (pc, ldr)) + { @@ winsup/cygwin/fastcwd_aarch64.cc (new) + /* work backwards, find a bl to RtlEnterCriticalSection whose argument + is the fast peb lock */ + -+ proc = GetArm64ProcAddress (GetModuleHandle ("ntdll"), -+ "RtlEnterCriticalSection"); + for (pc = ldrpc; pc >= start; pc--) + { -+ if (IS_INSN (pc, bl) && extract_bl_target (pc) == proc) ++ if (IS_INSN (pc, bl) && extract_bl_target (pc) == ent_crit) + break; + } + uint32_t addoffset; -- 2.48.1.windows.1