Index: gdb/amd64-tdep.c |
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c |
index 8ae1142c47e35bde014af73938adc83aa6c12595..3d394dac702f85c9f8de927171c38a6c6a95b78c 100644 |
--- a/gdb/amd64-tdep.c |
+++ b/gdb/amd64-tdep.c |
@@ -2043,6 +2043,75 @@ amd64_x32_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc, |
return min (pc + offset + 2, current_pc); |
} |
+/* Check whether it is mov %ebp,%reg instruction. The function returns the |
+ size of instruction or zero if it is not recognized. Fills reg with the |
+ destination register number. */ |
+static int |
+amd64_is_mov_rbp_reg(gdb_byte* op, int* reg) |
+{ |
+ int cur = 0; |
+ *reg = 0; |
+ /* [0x40] 0x89 0xe8 mov %ebp, %eax */ |
+ if (op[cur] == 0x40 || op[cur] == 0x41) |
+ { |
+ cur++; |
+ *reg += (op[cur] & 1) * 8; |
+ } |
+ if (op[cur] == 0x89 && (op[cur + 1] & 0xf8) == 0xe8) |
+ { |
+ *reg += op[cur + 1] & 7; |
+ return cur + 2; |
+ } |
+ cur = 0; |
+ *reg = 0; |
+ /* [0x40] 0x8b 0xc5 mov %ebp, %eax */ |
+ if (op[cur] == 0x40 || op[cur] == 0x44) |
+ { |
+ *reg += (op[cur] & 4) * 2; |
+ cur++; |
+ } |
+ if (op[cur] == 0x8b && (op[cur + 1] & 0xc7) == 0xc5) |
+ { |
+ reg += (op[cur + 1] >> 3) & 7; |
+ return cur + 2; |
+ } |
+ *reg = 0; |
+ return 0; |
+} |
+ |
+/* Check whether it is push %rbp instruction or equivalent sequence |
+ mov %ebp, %reg // push %reg. Returns size of the instruction or zero |
+ if it is not recognized. */ |
+static int |
+amd64_is_push_rbp(CORE_ADDR pc) |
+{ |
+ gdb_byte op[5]; |
+ if (target_read_memory(pc, op, 5) != 0) |
+ return 0; |
+ /* 55 push %rbp */ |
+ if (op[0] == 0x55) |
+ return 1; |
+ int cur = 0; |
+ int reg = 0; |
+ cur = amd64_is_mov_rbp_reg(op, ®); |
+ if (cur == 0) |
+ return 0; |
+ /* Recognize push %reg instruction. */ |
+ int reg_push = 0; |
+ if (op[cur] == 0x40 || op[cur] == 0x41) |
+ { |
+ reg_push += (op[cur] & 1) * 8; |
+ cur++; |
+ } |
+ if ((op[cur] & 0xf8) == 0x50) |
+ { |
+ reg_push += op[cur] & 7; |
+ if (reg == reg_push) |
+ return cur + 1; |
+ } |
+ return 0; |
+} |
+ |
/* Do a limited analysis of the prologue at PC and update CACHE |
accordingly. Bail out early if CURRENT_PC is reached. Return the |
address where the analysis stopped. |
@@ -2075,7 +2144,7 @@ amd64_analyze_prologue (struct gdbarch *gdbarch, |
static const gdb_byte mov_esp_ebp_2[2] = { 0x8b, 0xec }; |
gdb_byte buf[3]; |
- gdb_byte op; |
+ int push_rbp_size; |
if (current_pc <= pc) |
return current_pc; |
@@ -2085,20 +2154,22 @@ amd64_analyze_prologue (struct gdbarch *gdbarch, |
else |
pc = amd64_analyze_stack_align (pc, current_pc, cache); |
- op = read_memory_unsigned_integer (pc, 1, byte_order); |
+ push_rbp_size = amd64_is_push_rbp(pc); |
- if (op == 0x55) /* pushq %rbp */ |
+ if (push_rbp_size) /* pushq %rbp */ |
{ |
/* Take into account that we've executed the `pushq %rbp' that |
starts this instruction sequence. */ |
cache->saved_regs[AMD64_RBP_REGNUM] = 0; |
cache->sp_offset += 8; |
+ pc += push_rbp_size; |
+ |
/* If that's all, return now. */ |
- if (current_pc <= pc + 1) |
+ if (current_pc <= pc) |
return current_pc; |
- read_memory (pc + 1, buf, 3); |
+ read_memory (pc, buf, 3); |
/* Check for `movq %rsp, %rbp'. */ |
if (memcmp (buf, mov_rsp_rbp_1, 3) == 0 |
@@ -2106,7 +2177,7 @@ amd64_analyze_prologue (struct gdbarch *gdbarch, |
{ |
/* OK, we actually have a frame. */ |
cache->frameless_p = 0; |
- return pc + 4; |
+ return pc + 3; |
} |
/* For X32, also check for `movq %esp, %ebp'. */ |
@@ -2117,11 +2188,11 @@ amd64_analyze_prologue (struct gdbarch *gdbarch, |
{ |
/* OK, we actually have a frame. */ |
cache->frameless_p = 0; |
- return pc + 3; |
+ return pc + 2; |
} |
} |
- return pc + 1; |
+ return pc; |
} |
return pc; |