2006-01-16 Paul Gilliam <pgilliam@us.ibm.com>

* ppc-tdep.h (PPC_MAX_EPILOGUE_INSTRUCTIONS): New define.
	* rs6000-tdep.c (insn_changes_sp_or_jumps)
	(rs6000_in_function_epilogue_p): New functions.
	(rs6000_gdbarch_init): Set in_function_epilogue_p.
This commit is contained in:
Paul Gilliam 2006-01-17 22:21:13 +00:00
parent fe1b8b76fd
commit 0d1243d9e6
3 changed files with 114 additions and 0 deletions

View File

@ -1,3 +1,10 @@
2006-01-16 Paul Gilliam <pgilliam@us.ibm.com>
* ppc-tdep.h (PPC_MAX_EPILOGUE_INSTRUCTIONS): New define.
* rs6000-tdep.c (insn_changes_sp_or_jumps)
(rs6000_in_function_epilogue_p): New functions.
(rs6000_gdbarch_init): Set in_function_epilogue_p.
2006-01-17 Jim Blandy <jimb@redhat.com>
* dwarf2read.c (struct dwarf2_per_objfile, struct comp_unit_head)

View File

@ -384,4 +384,7 @@ enum
/* Instruction size. */
#define PPC_INSN_SIZE 4
/* Estimate for the maximum number of instrctions in a function epilogue. */
#define PPC_MAX_EPILOGUE_INSTRUCTIONS 52
#endif /* ppc-tdep.h */

View File

@ -502,6 +502,108 @@ rs6000_skip_prologue (CORE_ADDR pc)
return pc;
}
static int
insn_changes_sp_or_jumps (unsigned long insn)
{
int opcode = (insn >> 26) & 0x03f;
int sd = (insn >> 21) & 0x01f;
int a = (insn >> 16) & 0x01f;
int subcode = (insn >> 1) & 0x3ff;
/* Changes the stack pointer. */
/* NOTE: There are many ways to change the value of a given register.
The ways below are those used when the register is R1, the SP,
in a funtion's epilogue. */
if (opcode == 31 && subcode == 444 && a == 1)
return 1; /* mr R1,Rn */
if (opcode == 14 && sd == 1)
return 1; /* addi R1,Rn,simm */
if (opcode == 58 && sd == 1)
return 1; /* ld R1,ds(Rn) */
/* Transfers control. */
if (opcode == 18)
return 1; /* b */
if (opcode == 16)
return 1; /* bc */
if (opcode == 19 && subcode == 16)
return 1; /* bclr */
if (opcode == 19 && subcode == 528)
return 1; /* bcctr */
return 0;
}
/* Return true if we are in the function's epilogue, i.e. after the
instruction that destroyed the function's stack frame.
1) scan forward from the point of execution:
a) If you find an instruction that modifies the stack pointer
or transfers control (except a return), execution is not in
an epilogue, return.
b) Stop scanning if you find a return instruction or reach the
end of the function or reach the hard limit for the size of
an epilogue.
2) scan backward from the point of execution:
a) If you find an instruction that modifies the stack pointer,
execution *is* in an epilogue, return.
b) Stop scanning if you reach an instruction that transfers
control or the beginning of the function or reach the hard
limit for the size of an epilogue. */
static int
rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
bfd_byte insn_buf[PPC_INSN_SIZE];
CORE_ADDR scan_pc, func_start, func_end, epilogue_start, epilogue_end;
unsigned long insn;
struct frame_info *curfrm;
/* Find the search limits based on function boundaries and hard limit. */
if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
return 0;
epilogue_start = pc - PPC_MAX_EPILOGUE_INSTRUCTIONS * PPC_INSN_SIZE;
if (epilogue_start < func_start) epilogue_start = func_start;
epilogue_end = pc + PPC_MAX_EPILOGUE_INSTRUCTIONS * PPC_INSN_SIZE;
if (epilogue_end > func_end) epilogue_end = func_end;
curfrm = get_current_frame ();
/* Scan forward until next 'blr'. */
for (scan_pc = pc; scan_pc < epilogue_end; scan_pc += PPC_INSN_SIZE)
{
if (!safe_frame_unwind_memory (curfrm, scan_pc, insn_buf, PPC_INSN_SIZE))
return 0;
insn = extract_signed_integer (insn_buf, PPC_INSN_SIZE);
if (insn == 0x4e800020)
break;
if (insn_changes_sp_or_jumps (insn))
return 0;
}
/* Scan backward until adjustment to stack pointer (R1). */
for (scan_pc = pc - PPC_INSN_SIZE;
scan_pc >= epilogue_start;
scan_pc -= PPC_INSN_SIZE)
{
if (!safe_frame_unwind_memory (curfrm, scan_pc, insn_buf, PPC_INSN_SIZE))
return 0;
insn = extract_signed_integer (insn_buf, PPC_INSN_SIZE);
if (insn_changes_sp_or_jumps (insn))
return 1;
}
return 0;
}
/* Fill in fi->saved_regs */
@ -3342,6 +3444,8 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_deprecated_extract_struct_value_address (gdbarch, rs6000_extract_struct_value_address);
set_gdbarch_skip_prologue (gdbarch, rs6000_skip_prologue);
set_gdbarch_in_function_epilogue_p (gdbarch, rs6000_in_function_epilogue_p);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, rs6000_breakpoint_from_pc);