X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Farm-tdep.c;h=a4d16329402a3e4da6f78bab309cdbc8aa36f6d6;hb=c65ecaf37b02a936e0d8c4074da3b5da8017e464;hp=24f54667f2cbe430cc5007694f1973ea2f1614c5;hpb=bc90b915f7dc35a79754be7c858b57b73871bd1e;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 24f54667f2..a4d1632940 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -1,6 +1,6 @@ /* Common target dependent code for GDB on ARM systems. - Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000 - Free Software Foundation, Inc. + Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000, + 2001 Free Software Foundation, Inc. This file is part of GDB. @@ -27,18 +27,41 @@ #include "symfile.h" #include "gdb_string.h" #include "coff/internal.h" /* Internal format of COFF symbols in BFD */ +#include "dis-asm.h" /* For register flavors. */ +#include /* for isupper () */ +#include "regcache.h" -extern void _initialize_arm_tdep (void); +/* Each OS has a different mechanism for accessing the various + registers stored in the sigcontext structure. -/* From opcodes/arm-dis.c */ + SIGCONTEXT_REGISTER_ADDRESS should be defined to the name (or + function pointer) which may be used to determine the addresses + of the various saved registers in the sigcontext structure. -extern int get_arm_regname_num_options (void); + For the ARM target, there are three parameters to this function. + The first is the pc value of the frame under consideration, the + second the stack pointer of this frame, and the last is the + register number to fetch. -extern int set_arm_regname_option (int option); + If the tm.h file does not define this macro, then it's assumed that + no mechanism is needed and we define SIGCONTEXT_REGISTER_ADDRESS to + be 0. + + When it comes time to multi-arching this code, see the identically + named machinery in ia64-tdep.c for an example of how it could be + done. It should not be necessary to modify the code below where + this macro is used. */ + +#ifdef SIGCONTEXT_REGISTER_ADDRESS +#ifndef SIGCONTEXT_REGISTER_ADDRESS_P +#define SIGCONTEXT_REGISTER_ADDRESS_P() 1 +#endif +#else +#define SIGCONTEXT_REGISTER_ADDRESS(SP,PC,REG) 0 +#define SIGCONTEXT_REGISTER_ADDRESS_P() 0 +#endif -extern int get_arm_regnames (int option, const char **setname, - const char **setdescription, - const char ***regnames); +extern void _initialize_arm_tdep (void); /* Number of different reg name sets (options). */ static int num_flavor_options; @@ -60,10 +83,10 @@ static char * arm_register_name_strings[] = char **arm_register_names = arm_register_name_strings; /* Valid register name flavors. */ -static char **valid_flavors; +static const char **valid_flavors; /* Disassembly flavor to use. Default to "std" register names. */ -static char *disassembly_flavor; +static const char *disassembly_flavor; static int current_option; /* Index to that option in the opcodes table. */ /* This is used to keep the bfd arch_info in sync with the disassembly @@ -234,7 +257,7 @@ static int caller_is_thumb; function. */ int -arm_pc_is_thumb (bfd_vma memaddr) +arm_pc_is_thumb (CORE_ADDR memaddr) { struct minimal_symbol *sym; @@ -258,7 +281,7 @@ arm_pc_is_thumb (bfd_vma memaddr) dummy being called from a Thumb function. */ int -arm_pc_is_thumb_dummy (bfd_vma memaddr) +arm_pc_is_thumb_dummy (CORE_ADDR memaddr) { CORE_ADDR sp = read_sp (); @@ -336,7 +359,7 @@ arm_frameless_function_invocation (struct frame_info *fi) */ static CORE_ADDR -thumb_skip_prologue (CORE_ADDR pc) +thumb_skip_prologue (CORE_ADDR pc, CORE_ADDR func_end) { CORE_ADDR current_pc; int findmask = 0; /* findmask: @@ -345,7 +368,7 @@ thumb_skip_prologue (CORE_ADDR pc) bit 2 - sub sp, #simm OR add sp, #simm (adjusting of sp) */ - for (current_pc = pc; current_pc < pc + 40; current_pc += 2) + for (current_pc = pc; current_pc + 2 < func_end && current_pc < pc + 40; current_pc += 2) { unsigned short insn = read_memory_unsigned_integer (current_pc, 2); @@ -407,7 +430,7 @@ arm_skip_prologue (CORE_ADDR pc) /* Check if this is Thumb code. */ if (arm_pc_is_thumb (pc)) - return thumb_skip_prologue (pc); + return thumb_skip_prologue (pc, func_end); /* Can't find the prologue end in the symbol table, try it the hard way by disassembling the instructions. */ @@ -613,7 +636,7 @@ check_prologue_cache (struct frame_info *fi) fi->framereg = prologue_cache.framereg; fi->framesize = prologue_cache.framesize; fi->frameoffset = prologue_cache.frameoffset; - for (i = 0; i <= NUM_REGS; i++) + for (i = 0; i < NUM_REGS; i++) fi->fsr.regs[i] = prologue_cache.fsr.regs[i]; return 1; } @@ -634,7 +657,7 @@ save_prologue_cache (struct frame_info *fi) prologue_cache.framesize = fi->framesize; prologue_cache.frameoffset = fi->frameoffset; - for (i = 0; i <= NUM_REGS; i++) + for (i = 0; i < NUM_REGS; i++) prologue_cache.fsr.regs[i] = fi->fsr.regs[i]; } @@ -733,14 +756,42 @@ arm_scan_prologue (struct frame_info *fi) the symbol table, peek in the stack frame to find the PC. */ if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end)) { - /* Assume the prologue is everything between the first instruction - in the function and the first source line. */ - struct symtab_and_line sal = find_pc_line (prologue_start, 0); - - if (sal.line == 0) /* no line info, use current PC */ - prologue_end = fi->pc; - else if (sal.end < prologue_end) /* next line begins after fn end */ - prologue_end = sal.end; /* (probably means no prologue) */ + /* One way to find the end of the prologue (which works well + for unoptimized code) is to do the following: + + struct symtab_and_line sal = find_pc_line (prologue_start, 0); + + if (sal.line == 0) + prologue_end = fi->pc; + else if (sal.end < prologue_end) + prologue_end = sal.end; + + This mechanism is very accurate so long as the optimizer + doesn't move any instructions from the function body into the + prologue. If this happens, sal.end will be the last + instruction in the first hunk of prologue code just before + the first instruction that the scheduler has moved from + the body to the prologue. + + In order to make sure that we scan all of the prologue + instructions, we use a slightly less accurate mechanism which + may scan more than necessary. To help compensate for this + lack of accuracy, the prologue scanning loop below contains + several clauses which'll cause the loop to terminate early if + an implausible prologue instruction is encountered. + + The expression + + prologue_start + 64 + + is a suitable endpoint since it accounts for the largest + possible prologue plus up to five instructions inserted by + the scheduler. */ + + if (prologue_end > prologue_start + 64) + { + prologue_end = prologue_start + 64; /* See above. */ + } } else { @@ -748,10 +799,7 @@ arm_scan_prologue (struct frame_info *fi) PC is the address of the stmfd + 8. */ prologue_start = ADDR_BITS_REMOVE (read_memory_integer (fi->frame, 4)) - 8; - prologue_end = prologue_start + 64; /* This is all the insn's - that could be in the prologue, - plus room for 5 insn's inserted - by the scheduler. */ + prologue_end = prologue_start + 64; /* See above. */ } /* Now search the prologue looking for instructions that set up the @@ -841,6 +889,10 @@ arm_scan_prologue (struct frame_info *fi) fi->fsr.regs[fp_start_reg++] = sp_offset; } } + else if ((insn & 0xf0000000) != 0xe0000000) + break; /* Condition not true, exit early */ + else if ((insn & 0xfe200000) == 0xe8200000) /* ldm? */ + break; /* Don't scan past a block load */ else /* The optimizer might shove anything into the prologue, so we just skip what we don't recognize. */ @@ -981,6 +1033,40 @@ arm_init_extra_frame_info (int fromleaf, struct frame_info *fi) } else #endif + + /* Determine whether or not we're in a sigtramp frame. + Unfortunately, it isn't sufficient to test + fi->signal_handler_caller because this value is sometimes set + after invoking INIT_EXTRA_FRAME_INFO. So we test *both* + fi->signal_handler_caller and IN_SIGTRAMP to determine if we need + to use the sigcontext addresses for the saved registers. + + Note: If an ARM IN_SIGTRAMP method ever needs to compare against + the name of the function, the code below will have to be changed + to first fetch the name of the function and then pass this name + to IN_SIGTRAMP. */ + + if (SIGCONTEXT_REGISTER_ADDRESS_P () + && (fi->signal_handler_caller || IN_SIGTRAMP (fi->pc, 0))) + { + CORE_ADDR sp; + + if (!fi->next) + sp = read_sp(); + else + sp = fi->next->frame - fi->next->frameoffset + fi->next->framesize; + + for (reg = 0; reg < NUM_REGS; reg++) + fi->fsr.regs[reg] = SIGCONTEXT_REGISTER_ADDRESS (sp, fi->pc, reg); + + /* FIXME: What about thumb mode? */ + fi->framereg = SP_REGNUM; + fi->frame = read_memory_integer (fi->fsr.regs[fi->framereg], 4); + fi->framesize = 0; + fi->frameoffset = 0; + + } + else { arm_scan_prologue (fi); @@ -2045,7 +2131,9 @@ _initialize_arm_tdep (void) struct ui_file *stb; long length; struct cmd_list_element *new_cmd; - const char *setname, *setdesc, **regnames; + const char *setname; + const char *setdesc; + const char **regnames; int numregs, i, j; static char *helptext; @@ -2067,13 +2155,13 @@ The valid values are:\n"); for (i = 0; i < num_flavor_options; i++) { numregs = get_arm_regnames (i, &setname, &setdesc, ®names); - valid_flavors[i] = (char *) setname; + valid_flavors[i] = setname; fprintf_unfiltered (stb, "%s - %s\n", setname, setdesc); /* Copy the default names (if found) and synchronize disassembler. */ if (!strcmp (setname, "std")) { - disassembly_flavor = (char *) setname; + disassembly_flavor = setname; current_option = i; for (j = 0; j < numregs; j++) arm_register_names[j] = (char *) regnames[j]; @@ -2091,7 +2179,7 @@ The valid values are:\n"); /* Add the disassembly-flavor command */ new_cmd = add_set_enum_cmd ("disassembly-flavor", no_class, valid_flavors, - (char *) &disassembly_flavor, + &disassembly_flavor, helptext, &setlist); new_cmd->function.sfunc = set_disassembly_flavor_sfunc;