diff options
Diffstat (limited to 'gdb/arm-tdep.c')
-rw-r--r-- | gdb/arm-tdep.c | 153 |
1 files changed, 107 insertions, 46 deletions
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 71a000ab365..f10f66121ee 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -1,5 +1,5 @@ /* Common target dependent code for GDB on ARM systems. - Copyright 1988, 1989, 1991, 1992, 1993, 1995-1999 + Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. This file is part of GDB. @@ -45,33 +45,33 @@ extern void _initialize_arm_tdep (void); #define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1) /* Default register names as specified by APCS. */ -static char *apcs_register_names[] = +static char * atpcs_register_names[] = {"a1", "a2", "a3", "a4", /* 0 1 2 3 */ "v1", "v2", "v3", "v4", /* 4 5 6 7 */ - "v5", "v6", "sl", "fp", /* 8 9 10 11 */ - "ip", "sp", "lr", "pc", /* 12 13 14 15 */ + "v5", "v6", "v7", "v8", /* 8 9 10 11 */ + "IP", "SP", "LR", "PC", /* 12 13 14 15 */ "f0", "f1", "f2", "f3", /* 16 17 18 19 */ "f4", "f5", "f6", "f7", /* 20 21 22 23 */ - "fps", "ps"} /* 24 25 */ ; + "FPS", "PS" }; /* 24 25 */ /* Alternate set of registers names used by GCC. */ -static char *additional_register_names[] = -{"r0", "r1", "r2", "r3", /* 0 1 2 3 */ - "r4", "r5", "r6", "r7", /* 4 5 6 7 */ - "r8", "r9", "r10", "r11", /* 8 9 10 11 */ - "r12", "r13", "r14", "pc", /* 12 13 14 15 */ - "f0", "f1", "f2", "f3", /* 16 17 18 19 */ - "f4", "f5", "f6", "f7", /* 20 21 22 23 */ - "fps", "ps"} /* 24 25 */ ; +static char * additional_register_names[] = +{"r0", "r1", "r2", "r3", /* 0 1 2 3 */ + "r4", "r5", "r6", "r7", /* 4 5 6 7 */ + "r8", "r9", "r10", "r11", /* 8 9 10 11 */ + "r12", "sp", "lr", "pc", /* 12 13 14 15 */ + "f0", "f1", "f2", "f3", /* 16 17 18 19 */ + "f4", "f5", "f6", "f7", /* 20 21 22 23 */ + "fps", "ps" }; /* 24 25 */ /* This is the variable that is set with "set disassembly-flavor". By default use the APCS registers names. */ -char **arm_register_names = apcs_register_names; +char ** arm_register_names = atpcs_register_names; /* Valid register name flavours. */ static char apcs_flavor[] = "apcs"; static char r_prefix_flavor[] = "r-prefix"; -static char *valid_flavors[] = +static char * valid_flavors[] = { apcs_flavor, r_prefix_flavor, @@ -296,24 +296,65 @@ arm_frameless_function_invocation (struct frame_info *fi) add sp, sp, #-28 add r7, sp, #12 Sometimes the latter instruction may be replaced by: - mov r7, sp + mov r7, sp + + or like this: + push {r7, lr} + mov r7, sp + sub sp, #12 + + or, on tpcs, like this: + sub sp,#16 + push {r7, lr} + (many instructions) + mov r7, sp + sub sp, #12 + + There is always one instruction of three classes: + 1 - push + 2 - setting of r7 + 3 - adjusting of sp + + When we have found at least one of each class we are done with the prolog. + Note that the "sub sp, #NN" before the push does not count. */ static CORE_ADDR thumb_skip_prologue (CORE_ADDR pc) { CORE_ADDR current_pc; + int findmask = 0; /* findmask: + bit 0 - push { rlist } + bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7) + bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp) + */ - for (current_pc = pc; current_pc < pc + 20; current_pc += 2) + for (current_pc = pc; current_pc < pc + 40; current_pc += 2) { unsigned short insn = read_memory_unsigned_integer (current_pc, 2); - if ((insn & 0xfe00) != 0xb400 /* push {..., r7, lr} */ - && (insn & 0xff00) != 0xb000 /* add sp, #simm */ - && (insn & 0xff00) != 0xaf00 /* add r7, sp, #imm */ - && insn != 0x466f /* mov r7, sp */ - && (insn & 0xffc0) != 0x4640) /* mov r0-r7, r8-r15 */ - break; + if ((insn & 0xfe00) == 0xb400) /* push { rlist } */ + { + findmask |= 1; /* push found */ + } + else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR sub sp, #simm */ + { + if ((findmask & 1) == 0) /* before push ? */ + continue; + else + findmask |= 4; /* add/sub sp found */ + } + else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */ + { + findmask |= 2; /* setting of r7 found */ + } + else if (insn == 0x466f) /* mov r7, sp */ + { + findmask |= 2; /* setting of r7 found */ + } + else + continue; /* something in the prolog that we don't care about or some + instruction from outside the prolog scheduled here for optimization */ } return current_pc; @@ -408,18 +449,18 @@ arm_skip_prologue (CORE_ADDR pc) 4) the offset from the stack pointer to the frame pointer This information is stored in the "extra" fields of the frame_info. - A typical Thumb function prologue might look like this: - push {r7, lr} - sub sp, #28, - add r7, sp, #12 - Which would create this stack frame (offsets relative to FP) + A typical Thumb function prologue would create this stack frame + (offsets relative to FP) old SP -> 24 stack parameters 20 LR 16 R7 R7 -> 0 local variables (16 bytes) SP -> -12 additional stack space (12 bytes) The frame size would thus be 36 bytes, and the frame offset would be - 12 bytes. The frame register is R7. */ + 12 bytes. The frame register is R7. + + The comments for thumb_skip_prolog() describe the algorithm we use to detect + the end of the prolog */ /* *INDENT-ON* */ static void @@ -429,6 +470,11 @@ thumb_scan_prologue (struct frame_info *fi) CORE_ADDR prologue_end; CORE_ADDR current_pc; int saved_reg[16]; /* which register has been copied to register n? */ + int findmask = 0; /* findmask: + bit 0 - push { rlist } + bit 1 - mov r7, sp OR add r7, sp, #imm (setting of r7) + bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp) + */ int i; if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end)) @@ -452,10 +498,13 @@ thumb_scan_prologue (struct frame_info *fi) saved_reg[i] = i; /* Search the prologue looking for instructions that set up the - frame pointer, adjust the stack pointer, and save registers. */ + frame pointer, adjust the stack pointer, and save registers. + Do this until all basic prolog instructions are found. */ fi->framesize = 0; - for (current_pc = prologue_start; current_pc < prologue_end; current_pc += 2) + for (current_pc = prologue_start; + (current_pc < prologue_end) && ((findmask & 7) != 7); + current_pc += 2) { unsigned short insn; int regno; @@ -465,9 +514,11 @@ thumb_scan_prologue (struct frame_info *fi) if ((insn & 0xfe00) == 0xb400) /* push { rlist } */ { + int mask; + findmask |= 1; /* push found */ /* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says whether to save LR (R14). */ - int mask = (insn & 0xff) | ((insn & 0x100) << 6); + mask = (insn & 0xff) | ((insn & 0x100) << 6); /* Calculate offsets of saved R0-R7 and LR. */ for (regno = LR_REGNUM; regno >= 0; regno--) @@ -478,20 +529,30 @@ thumb_scan_prologue (struct frame_info *fi) saved_reg[regno] = regno; /* reset saved register map */ } } - else if ((insn & 0xff00) == 0xb000) /* add sp, #simm */ + else if ((insn & 0xff00) == 0xb000) /* add sp, #simm OR sub sp, #simm */ { + if ((findmask & 1) == 0) /* before push ? */ + continue; + else + findmask |= 4; /* add/sub sp found */ + offset = (insn & 0x7f) << 2; /* get scaled offset */ - if (insn & 0x80) /* is it signed? */ - offset = -offset; + if (insn & 0x80) /* is it signed? (==subtracting) */ + { + fi->frameoffset += offset; + offset = -offset; + } fi->framesize -= offset; } else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */ { + findmask |= 2; /* setting of r7 found */ fi->framereg = THUMB_FP_REGNUM; fi->frameoffset = (insn & 0xff) << 2; /* get scaled offset */ } - else if (insn == 0x466f) /* mov r7, sp */ + else if (insn == 0x466f) /* mov r7, sp */ { + findmask |= 2; /* setting of r7 found */ fi->framereg = THUMB_FP_REGNUM; fi->frameoffset = 0; saved_reg[THUMB_FP_REGNUM] = SP_REGNUM; @@ -503,7 +564,8 @@ thumb_scan_prologue (struct frame_info *fi) saved_reg[lo_reg] = hi_reg; /* remember hi reg was saved */ } else - break; /* anything else isn't prologue */ + continue; /* something in the prolog that we don't care about or some + instruction from outside the prolog scheduled here for optimization */ } } @@ -1170,7 +1232,10 @@ arm_push_arguments (int nargs, value_ptr * args, CORE_ADDR sp, val = (char *) &dbl_arg; len = sizeof (double); } -#if 0 +#if 1 + /* I don't know why this code was disable. The only logical use + for a function pointer is to call that function, so setting + the mode bit is perfectly fine. FN */ /* If the argument is a pointer to a function, and it is a Thumb function, set the low bit of the pointer. */ if (TYPE_CODE_PTR == typecode @@ -1278,14 +1343,12 @@ set_disassembly_flavor (void) { if (disassembly_flavor == apcs_flavor) { - if (arm_toggle_regnames () == 0) - arm_toggle_regnames (); - arm_register_names = apcs_register_names; + parse_arm_disassembler_option ("reg-names-atpcs"); + arm_register_names = atpcs_register_names; } else if (disassembly_flavor == r_prefix_flavor) { - if (arm_toggle_regnames () == 1) - arm_toggle_regnames (); + parse_arm_disassembler_option ("reg-names-std"); arm_register_names = additional_register_names; } } @@ -1917,9 +1980,7 @@ _initialize_arm_tdep (void) tm_print_insn = gdb_print_insn_arm; /* Sync the opcode insn printer with our register viewer: */ - - if (arm_toggle_regnames () != 1) - arm_toggle_regnames (); + parse_arm_disassembler_option ("reg-names-atpcs"); /* Add the deprecated "othernames" command */ |