+/* GCC 4.1 and later, can put code in the prologue to realign the
+ stack pointer. Check whether PC points to such code, and update
+ CACHE accordingly. Return the first instruction after the code
+ sequence or CURRENT_PC, whichever is smaller. If we don't
+ recognize the code, return PC. */
+
+static CORE_ADDR
+i386_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct i386_frame_cache *cache)
+{
+ /* There are 2 code sequences to re-align stack before the frame
+ gets set up:
+
+ 1. Use a caller-saved saved register:
+
+ leal 4(%esp), %reg
+ andl $-XXX, %esp
+ pushl -4(%reg)
+
+ 2. Use a callee-saved saved register:
+
+ pushl %reg
+ leal 8(%esp), %reg
+ andl $-XXX, %esp
+ pushl -4(%reg)
+
+ "andl $-XXX, %esp" can be either 3 bytes or 6 bytes:
+
+ 0x83 0xe4 0xf0 andl $-16, %esp
+ 0x81 0xe4 0x00 0xff 0xff 0xff andl $-256, %esp
+ */
+
+ gdb_byte buf[14];
+ int reg;
+ int offset, offset_and;
+ static int regnums[8] = {
+ I386_EAX_REGNUM, /* %eax */
+ I386_ECX_REGNUM, /* %ecx */
+ I386_EDX_REGNUM, /* %edx */
+ I386_EBX_REGNUM, /* %ebx */
+ I386_ESP_REGNUM, /* %esp */
+ I386_EBP_REGNUM, /* %ebp */
+ I386_ESI_REGNUM, /* %esi */
+ I386_EDI_REGNUM /* %edi */
+ };
+
+ if (target_read_memory (pc, buf, sizeof buf))
+ return pc;
+
+ /* Check caller-saved saved register. The first instruction has
+ to be "leal 4(%esp), %reg". */
+ if (buf[0] == 0x8d && buf[2] == 0x24 && buf[3] == 0x4)
+ {
+ /* MOD must be binary 10 and R/M must be binary 100. */
+ if ((buf[1] & 0xc7) != 0x44)
+ return pc;
+
+ /* REG has register number. */
+ reg = (buf[1] >> 3) & 7;
+ offset = 4;
+ }
+ else
+ {
+ /* Check callee-saved saved register. The first instruction
+ has to be "pushl %reg". */
+ if ((buf[0] & 0xf8) != 0x50)
+ return pc;
+
+ /* Get register. */
+ reg = buf[0] & 0x7;
+
+ /* The next instruction has to be "leal 8(%esp), %reg". */
+ if (buf[1] != 0x8d || buf[3] != 0x24 || buf[4] != 0x8)
+ return pc;
+
+ /* MOD must be binary 10 and R/M must be binary 100. */
+ if ((buf[2] & 0xc7) != 0x44)
+ return pc;
+
+ /* REG has register number. Registers in pushl and leal have to
+ be the same. */
+ if (reg != ((buf[2] >> 3) & 7))
+ return pc;
+
+ offset = 5;
+ }
+
+ /* Rigister can't be %esp nor %ebp. */
+ if (reg == 4 || reg == 5)
+ return pc;
+
+ /* The next instruction has to be "andl $-XXX, %esp". */
+ if (buf[offset + 1] != 0xe4
+ || (buf[offset] != 0x81 && buf[offset] != 0x83))
+ return pc;
+
+ offset_and = offset;
+ offset += buf[offset] == 0x81 ? 6 : 3;
+
+ /* The next instruction has to be "pushl -4(%reg)". 8bit -4 is
+ 0xfc. REG must be binary 110 and MOD must be binary 01. */
+ if (buf[offset] != 0xff
+ || buf[offset + 2] != 0xfc
+ || (buf[offset + 1] & 0xf8) != 0x70)
+ return pc;
+
+ /* R/M has register. Registers in leal and pushl have to be the
+ same. */
+ if (reg != (buf[offset + 1] & 7))
+ return pc;
+
+ if (current_pc > pc + offset_and)
+ cache->saved_sp_reg = regnums[reg];
+
+ return min (pc + offset + 3, current_pc);
+}
+
+/* Maximum instruction length we need to handle. */
+#define I386_MAX_MATCHED_INSN_LEN 6
+
+/* Instruction description. */
+struct i386_insn
+{
+ size_t len;
+ gdb_byte insn[I386_MAX_MATCHED_INSN_LEN];
+ gdb_byte mask[I386_MAX_MATCHED_INSN_LEN];
+};
+
+/* Search for the instruction at PC in the list SKIP_INSNS. Return
+ the first instruction description that matches. Otherwise, return
+ NULL. */
+
+static struct i386_insn *
+i386_match_insn (CORE_ADDR pc, struct i386_insn *skip_insns)
+{
+ struct i386_insn *insn;
+ gdb_byte op;
+
+ target_read_memory (pc, &op, 1);
+
+ for (insn = skip_insns; insn->len > 0; insn++)
+ {
+ if ((op & insn->mask[0]) == insn->insn[0])
+ {
+ gdb_byte buf[I386_MAX_MATCHED_INSN_LEN - 1];
+ int insn_matched = 1;
+ size_t i;
+
+ gdb_assert (insn->len > 1);
+ gdb_assert (insn->len <= I386_MAX_MATCHED_INSN_LEN);
+
+ target_read_memory (pc + 1, buf, insn->len - 1);
+ for (i = 1; i < insn->len; i++)
+ {
+ if ((buf[i - 1] & insn->mask[i]) != insn->insn[i])
+ insn_matched = 0;
+ }
+
+ if (insn_matched)
+ return insn;
+ }
+ }
+
+ return NULL;
+}
+
+/* Some special instructions that might be migrated by GCC into the
+ part of the prologue that sets up the new stack frame. Because the
+ stack frame hasn't been setup yet, no registers have been saved
+ yet, and only the scratch registers %eax, %ecx and %edx can be
+ touched. */
+
+struct i386_insn i386_frame_setup_skip_insns[] =
+{
+ /* Check for `movb imm8, r' and `movl imm32, r'.
+
+ ??? Should we handle 16-bit operand-sizes here? */
+
+ /* `movb imm8, %al' and `movb imm8, %ah' */
+ /* `movb imm8, %cl' and `movb imm8, %ch' */
+ { 2, { 0xb0, 0x00 }, { 0xfa, 0x00 } },
+ /* `movb imm8, %dl' and `movb imm8, %dh' */
+ { 2, { 0xb2, 0x00 }, { 0xfb, 0x00 } },
+ /* `movl imm32, %eax' and `movl imm32, %ecx' */
+ { 5, { 0xb8 }, { 0xfe } },
+ /* `movl imm32, %edx' */
+ { 5, { 0xba }, { 0xff } },
+
+ /* Check for `mov imm32, r32'. Note that there is an alternative
+ encoding for `mov m32, %eax'.
+
+ ??? Should we handle SIB adressing here?
+ ??? Should we handle 16-bit operand-sizes here? */
+
+ /* `movl m32, %eax' */
+ { 5, { 0xa1 }, { 0xff } },
+ /* `movl m32, %eax' and `mov; m32, %ecx' */
+ { 6, { 0x89, 0x05 }, {0xff, 0xf7 } },
+ /* `movl m32, %edx' */
+ { 6, { 0x89, 0x15 }, {0xff, 0xff } },
+
+ /* Check for `xorl r32, r32' and the equivalent `subl r32, r32'.
+ Because of the symmetry, there are actually two ways to encode
+ these instructions; opcode bytes 0x29 and 0x2b for `subl' and
+ opcode bytes 0x31 and 0x33 for `xorl'. */
+
+ /* `subl %eax, %eax' */
+ { 2, { 0x29, 0xc0 }, { 0xfd, 0xff } },
+ /* `subl %ecx, %ecx' */
+ { 2, { 0x29, 0xc9 }, { 0xfd, 0xff } },
+ /* `subl %edx, %edx' */
+ { 2, { 0x29, 0xd2 }, { 0xfd, 0xff } },
+ /* `xorl %eax, %eax' */
+ { 2, { 0x31, 0xc0 }, { 0xfd, 0xff } },
+ /* `xorl %ecx, %ecx' */
+ { 2, { 0x31, 0xc9 }, { 0xfd, 0xff } },
+ /* `xorl %edx, %edx' */
+ { 2, { 0x31, 0xd2 }, { 0xfd, 0xff } },
+ { 0 }
+};
+
+
+/* Check whether PC points to a no-op instruction. */
+static CORE_ADDR
+i386_skip_noop (CORE_ADDR pc)
+{
+ gdb_byte op;
+ int check = 1;
+
+ target_read_memory (pc, &op, 1);
+
+ while (check)
+ {
+ check = 0;
+ /* Ignore `nop' instruction. */
+ if (op == 0x90)
+ {
+ pc += 1;
+ target_read_memory (pc, &op, 1);
+ check = 1;
+ }
+ /* Ignore no-op instruction `mov %edi, %edi'.
+ Microsoft system dlls often start with
+ a `mov %edi,%edi' instruction.
+ The 5 bytes before the function start are
+ filled with `nop' instructions.
+ This pattern can be used for hot-patching:
+ The `mov %edi, %edi' instruction can be replaced by a
+ near jump to the location of the 5 `nop' instructions
+ which can be replaced by a 32-bit jump to anywhere
+ in the 32-bit address space. */
+
+ else if (op == 0x8b)
+ {
+ target_read_memory (pc + 1, &op, 1);
+ if (op == 0xff)
+ {
+ pc += 2;
+ target_read_memory (pc, &op, 1);
+ check = 1;
+ }
+ }
+ }
+ return pc;
+}
+