From: Paul Gilliam Date: Tue, 17 Jan 2006 22:21:13 +0000 (+0000) Subject: 2006-01-16 Paul Gilliam X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0d1243d9e6e71bccc2e8b0c995d28c403b1eac0d;p=binutils-gdb.git 2006-01-16 Paul Gilliam * 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. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0c666c0844c..1bba311a9af 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2006-01-16 Paul Gilliam + + * 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 * dwarf2read.c (struct dwarf2_per_objfile, struct comp_unit_head) diff --git a/gdb/ppc-tdep.h b/gdb/ppc-tdep.h index 460c3f0fc1e..1a25648c0f3 100644 --- a/gdb/ppc-tdep.h +++ b/gdb/ppc-tdep.h @@ -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 */ diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index 211bc333eb1..54b33b36da9 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -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);