Index: gdb/sparc-tdep.c |
diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c |
index 24d54b741723dd4d6aaaea00adceab840e157001..6da2297a3cb9547ab8c48f8e4e8947fd2cc13ad9 100644 |
--- a/gdb/sparc-tdep.c |
+++ b/gdb/sparc-tdep.c |
@@ -85,6 +85,7 @@ struct regset; |
/* Sign extension macros. */ |
#define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000) |
#define X_DISP19(i) ((((i) & 0x7ffff) ^ 0x40000) - 0x40000) |
+#define X_DISP10(i) ((((((i) >> 11) && 0x300) | (((i) >> 5) & 0xff)) ^ 0x200) - 0x200) |
#define X_SIMM13(i) ((((i) & 0x1fff) ^ 0x1000) - 0x1000) |
/* Fetch the instruction at PC. Instructions are always big-endian |
@@ -601,7 +602,6 @@ static struct sparc_frame_cache * |
sparc_alloc_frame_cache (void) |
{ |
struct sparc_frame_cache *cache; |
- int i; |
cache = FRAME_OBSTACK_ZALLOC (struct sparc_frame_cache); |
@@ -1353,7 +1353,7 @@ sparc32_store_return_value (struct type *type, struct regcache *regcache, |
} |
static enum return_value_convention |
-sparc32_return_value (struct gdbarch *gdbarch, struct type *func_type, |
+sparc32_return_value (struct gdbarch *gdbarch, struct value *function, |
struct type *type, struct regcache *regcache, |
gdb_byte *readbuf, const gdb_byte *writebuf) |
{ |
@@ -1451,14 +1451,24 @@ sparc_analyze_control_transfer (struct frame_info *frame, |
{ |
unsigned long insn = sparc_fetch_instruction (pc); |
int conditional_p = X_COND (insn) & 0x7; |
- int branch_p = 0; |
+ int branch_p = 0, fused_p = 0; |
long offset = 0; /* Must be signed for sign-extend. */ |
- if (X_OP (insn) == 0 && X_OP2 (insn) == 3 && (insn & 0x1000000) == 0) |
+ if (X_OP (insn) == 0 && X_OP2 (insn) == 3) |
{ |
- /* Branch on Integer Register with Prediction (BPr). */ |
- branch_p = 1; |
- conditional_p = 1; |
+ if ((insn & 0x10000000) == 0) |
+ { |
+ /* Branch on Integer Register with Prediction (BPr). */ |
+ branch_p = 1; |
+ conditional_p = 1; |
+ } |
+ else |
+ { |
+ /* Compare and Branch */ |
+ branch_p = 1; |
+ fused_p = 1; |
+ offset = 4 * X_DISP10 (insn); |
+ } |
} |
else if (X_OP (insn) == 0 && X_OP2 (insn) == 6) |
{ |
@@ -1495,7 +1505,16 @@ sparc_analyze_control_transfer (struct frame_info *frame, |
if (branch_p) |
{ |
- if (conditional_p) |
+ if (fused_p) |
+ { |
+ /* Fused compare-and-branch instructions are non-delayed, |
+ and do not have an annuling capability. So we need to |
+ always set a breakpoint on both the NPC and the branch |
+ target address. */ |
+ gdb_assert (offset != 0); |
+ return pc + offset; |
+ } |
+ else if (conditional_p) |
{ |
/* For conditional branches, return nPC + 4 iff the annul |
bit is 1. */ |