X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;ds=inline;f=gdb%2Farm-tdep.c;h=12e4371d3b24305ac9dd26bff2df485b744c822e;hb=8d4ce20aa3ed34265884df3a9b426028e26b9ab5;hp=4b1740aab1ab996e64f29f4b715701cdd2348f9c;hpb=a5afb99fc1bc3708dafc1201ff30bd263ec2b266;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 4b1740aab1..12e4371d3b 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, 1998, 1999, 2000, - 2001, 2002 Free Software Foundation, Inc. + 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GDB. @@ -28,12 +28,15 @@ #include "gdbcore.h" #include "symfile.h" #include "gdb_string.h" -#include "dis-asm.h" /* For register flavors. */ +#include "dis-asm.h" /* For register styles. */ #include "regcache.h" #include "doublest.h" #include "value.h" #include "arch-utils.h" -#include "solib-svr4.h" +#include "osabi.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "trad-frame.h" #include "arm-tdep.h" #include "gdb/sim-arm.h" @@ -98,8 +101,27 @@ static int arm_debug; #define MSYMBOL_SIZE(msym) \ ((long) MSYMBOL_INFO (msym) & 0x7fffffff) +/* The list of available "set arm ..." and "show arm ..." commands. */ +static struct cmd_list_element *setarmcmdlist = NULL; +static struct cmd_list_element *showarmcmdlist = NULL; + +/* The type of floating-point to use. Keep this in sync with enum + arm_float_model, and the help string in _initialize_arm_tdep. */ +static const char *fp_model_strings[] = +{ + "auto", + "softfpa", + "fpa", + "softvfp", + "vfp" +}; + +/* A variable that can be configured by the user. */ +static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO; +static const char *current_fp_model = "auto"; + /* Number of different reg name sets (options). */ -static int num_flavor_options; +static int num_disassembly_options; /* We have more registers than the disassembler as gdb can print the value of special registers as well. @@ -117,33 +139,45 @@ static char * arm_register_name_strings[] = "fps", "cpsr" }; /* 24 25 */ static char **arm_register_names = arm_register_name_strings; -/* Valid register name flavors. */ -static const char **valid_flavors; +/* Valid register name styles. */ +static const char **valid_disassembly_styles; -/* Disassembly flavor to use. Default to "std" register names. */ -static const char *disassembly_flavor; +/* Disassembly style to use. Default to "std" register names. */ +static const char *disassembly_style; /* Index to that option in the opcodes table. */ static int current_option; /* This is used to keep the bfd arch_info in sync with the disassembly - flavor. */ -static void set_disassembly_flavor_sfunc(char *, int, + style. */ +static void set_disassembly_style_sfunc(char *, int, struct cmd_list_element *); -static void set_disassembly_flavor (void); - -static void convert_from_extended (void *ptr, void *dbl); +static void set_disassembly_style (void); -/* Define other aspects of the stack frame. We keep the offsets of - all saved registers, 'cause we need 'em a lot! We also keep the - current size of the stack frame, and the offset of the frame - pointer from the stack pointer (for frameless functions, and when - we're still in the prologue of a function with a frame). */ +static void convert_from_extended (const struct floatformat *, const void *, + void *); +static void convert_to_extended (const struct floatformat *, void *, + const void *); -struct frame_extra_info +struct arm_prologue_cache { + /* The stack pointer at the time this frame was created; i.e. the + caller's stack pointer when this function was called. It is used + to identify this frame. */ + CORE_ADDR prev_sp; + + /* The frame base for this frame is just prev_sp + frame offset - + frame size. FRAMESIZE is the size of this stack frame, and + FRAMEOFFSET if the initial offset from the stack pointer (this + frame's stack pointer, not PREV_SP) to the frame base. */ + int framesize; int frameoffset; + + /* The register used to hold the frame pointer for this frame. */ int framereg; + + /* Saved register offsets. */ + struct trad_frame_saved_reg *saved_regs; }; /* Addresses for calling Thumb functions have the bit 0 set. @@ -152,12 +186,6 @@ struct frame_extra_info #define MAKE_THUMB_ADDR(addr) ((addr) | 1) #define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1) -static int -arm_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe) -{ - return (chain != 0 && (FRAME_SAVED_PC (thisframe) >= LOWEST_PC)); -} - /* Set to true if the 32-bit mode is in use. */ int arm_apcs_32 = 1; @@ -272,7 +300,7 @@ arm_frameless_function_invocation (struct frame_info *fi) stmdb sp!, {} sub sp, ip, #4. */ - func_start = (get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET); + func_start = (get_frame_func (fi) + FUNCTION_START_OFFSET); after_prologue = SKIP_PROLOGUE (func_start); /* There are some frameless functions whose first two instructions @@ -283,28 +311,6 @@ arm_frameless_function_invocation (struct frame_info *fi) return frameless; } -/* The address of the arguments in the frame. */ -static CORE_ADDR -arm_frame_args_address (struct frame_info *fi) -{ - return fi->frame; -} - -/* The address of the local variables in the frame. */ -static CORE_ADDR -arm_frame_locals_address (struct frame_info *fi) -{ - return fi->frame; -} - -/* The number of arguments being passed in the frame. */ -static int -arm_frame_num_args (struct frame_info *fi) -{ - /* We have no way of knowing. */ - return -1; -} - /* A typical Thumb prologue looks like this: push {r7, lr} add sp, sp, #-28 @@ -420,7 +426,7 @@ arm_skip_prologue (CORE_ADDR pc) struct symbol *sym; /* Found a function. */ - sym = lookup_symbol (func_name, NULL, VAR_NAMESPACE, NULL, NULL); + sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL, NULL); if (sym && SYMBOL_LANGUAGE (sym) != language_asm) { /* Don't use this trick for assembly source files. */ @@ -449,6 +455,12 @@ arm_skip_prologue (CORE_ADDR pc) if (inst == 0xe1a0c00d) /* mov ip, sp */ continue; + if ((inst & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */ + continue; + + if ((inst & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */ + continue; + /* Some prologues begin with "str lr, [sp, #-4]!". */ if (inst == 0xe52de004) /* str lr, [sp, #-4]! */ continue; @@ -502,7 +514,6 @@ arm_skip_prologue (CORE_ADDR pc) 2) which registers are saved on it 3) the offsets of saved regs 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 would create this stack frame (offsets relative to FP) @@ -519,7 +530,7 @@ arm_skip_prologue (CORE_ADDR pc) /* *INDENT-ON* */ static void -thumb_scan_prologue (struct frame_info *fi) +thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache) { CORE_ADDR prologue_start; CORE_ADDR prologue_end; @@ -534,17 +545,12 @@ thumb_scan_prologue (struct frame_info *fi) int findmask = 0; int i; - /* Don't try to scan dummy frames. */ - if (fi != NULL - && DEPRECATED_PC_IN_CALL_DUMMY (fi->pc, 0, 0)) - return; - - if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end)) + if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end)) { 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; + prologue_end = prev_pc; else if (sal.end < prologue_end) /* next line begins after fn end */ prologue_end = sal.end; /* (probably means no prologue) */ } @@ -553,7 +559,7 @@ thumb_scan_prologue (struct frame_info *fi) 16 pushes, an add, and "mv fp,sp". */ prologue_end = prologue_start + 40; - prologue_end = min (prologue_end, fi->pc); + prologue_end = min (prologue_end, prev_pc); /* Initialize the saved register map. When register H is copied to register L, we will put H in saved_reg[L]. */ @@ -564,7 +570,7 @@ thumb_scan_prologue (struct frame_info *fi) frame pointer, adjust the stack pointer, and save registers. Do this until all basic prolog instructions are found. */ - fi->extra_info->framesize = 0; + cache->framesize = 0; for (current_pc = prologue_start; (current_pc < prologue_end) && ((findmask & 7) != 7); current_pc += 2) @@ -587,9 +593,8 @@ thumb_scan_prologue (struct frame_info *fi) for (regno = ARM_LR_REGNUM; regno >= 0; regno--) if (mask & (1 << regno)) { - fi->extra_info->framesize += 4; - fi->saved_regs[saved_reg[regno]] = - -(fi->extra_info->framesize); + cache->framesize += 4; + cache->saved_regs[saved_reg[regno]].addr = -cache->framesize; /* Reset saved register map. */ saved_reg[regno] = regno; } @@ -605,23 +610,23 @@ thumb_scan_prologue (struct frame_info *fi) offset = (insn & 0x7f) << 2; /* get scaled offset */ if (insn & 0x80) /* is it signed? (==subtracting) */ { - fi->extra_info->frameoffset += offset; + cache->frameoffset += offset; offset = -offset; } - fi->extra_info->framesize -= offset; + cache->framesize -= offset; } else if ((insn & 0xff00) == 0xaf00) /* add r7, sp, #imm */ { findmask |= 2; /* setting of r7 found */ - fi->extra_info->framereg = THUMB_FP_REGNUM; + cache->framereg = THUMB_FP_REGNUM; /* get scaled offset */ - fi->extra_info->frameoffset = (insn & 0xff) << 2; + cache->frameoffset = (insn & 0xff) << 2; } else if (insn == 0x466f) /* mov r7, sp */ { findmask |= 2; /* setting of r7 found */ - fi->extra_info->framereg = THUMB_FP_REGNUM; - fi->extra_info->frameoffset = 0; + cache->framereg = THUMB_FP_REGNUM; + cache->frameoffset = 0; saved_reg[THUMB_FP_REGNUM] = ARM_SP_REGNUM; } else if ((insn & 0xffc0) == 0x4640) /* mov r0-r7, r8-r15 */ @@ -638,60 +643,6 @@ thumb_scan_prologue (struct frame_info *fi) } } -/* Check if prologue for this frame's PC has already been scanned. If - it has, copy the relevant information about that prologue and - return non-zero. Otherwise do not copy anything and return zero. - - The information saved in the cache includes: - * the frame register number; - * the size of the stack frame; - * the offsets of saved regs (relative to the old SP); and - * the offset from the stack pointer to the frame pointer - - The cache contains only one entry, since this is adequate for the - typical sequence of prologue scan requests we get. When performing - a backtrace, GDB will usually ask to scan the same function twice - in a row (once to get the frame chain, and once to fill in the - extra frame information). */ - -static struct frame_info prologue_cache; - -static int -check_prologue_cache (struct frame_info *fi) -{ - int i; - - if (fi->pc == prologue_cache.pc) - { - fi->extra_info->framereg = prologue_cache.extra_info->framereg; - fi->extra_info->framesize = prologue_cache.extra_info->framesize; - fi->extra_info->frameoffset = prologue_cache.extra_info->frameoffset; - for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++) - fi->saved_regs[i] = prologue_cache.saved_regs[i]; - return 1; - } - else - return 0; -} - - -/* Copy the prologue information from fi to the prologue cache. */ - -static void -save_prologue_cache (struct frame_info *fi) -{ - int i; - - prologue_cache.pc = fi->pc; - prologue_cache.extra_info->framereg = fi->extra_info->framereg; - prologue_cache.extra_info->framesize = fi->extra_info->framesize; - prologue_cache.extra_info->frameoffset = fi->extra_info->frameoffset; - - for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++) - prologue_cache.saved_regs[i] = fi->saved_regs[i]; -} - - /* This function decodes an ARM function prologue to determine: 1) the size of the stack frame 2) which registers are saved on it @@ -760,32 +711,27 @@ save_prologue_cache (struct frame_info *fi) */ static void -arm_scan_prologue (struct frame_info *fi) +arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cache) { - int regno, sp_offset, fp_offset; - LONGEST return_value; + int regno, sp_offset, fp_offset, ip_offset; CORE_ADDR prologue_start, prologue_end, current_pc; - - /* Check if this function is already in the cache of frame information. */ - if (check_prologue_cache (fi)) - return; + CORE_ADDR prev_pc = frame_pc_unwind (next_frame); /* Assume there is no frame until proven otherwise. */ - fi->extra_info->framereg = ARM_SP_REGNUM; - fi->extra_info->framesize = 0; - fi->extra_info->frameoffset = 0; + cache->framereg = ARM_SP_REGNUM; + cache->framesize = 0; + cache->frameoffset = 0; /* Check for Thumb prologue. */ - if (arm_pc_is_thumb (fi->pc)) + if (arm_pc_is_thumb (prev_pc)) { - thumb_scan_prologue (fi); - save_prologue_cache (fi); + thumb_scan_prologue (prev_pc, cache); return; } /* Find the function prologue. If we can't find the function in the symbol table, peek in the stack frame to find the PC. */ - if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end)) + if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end)) { /* One way to find the end of the prologue (which works well for unoptimized code) is to do the following: @@ -793,7 +739,7 @@ arm_scan_prologue (struct frame_info *fi) struct symtab_and_line sal = find_pc_line (prologue_start, 0); if (sal.line == 0) - prologue_end = fi->pc; + prologue_end = prev_pc; else if (sal.end < prologue_end) prologue_end = sal.end; @@ -826,9 +772,16 @@ arm_scan_prologue (struct frame_info *fi) } else { - /* Get address of the stmfd in the prologue of the callee; - the saved PC is the address of the stmfd + 8. */ - if (!safe_read_memory_integer (fi->frame, 4, &return_value)) + /* We have no symbol information. Our only option is to assume this + function has a standard stack frame and the normal frame register. + Then, we can find the value of our frame pointer on entrance to + the callee (or at the present moment if this is the innermost frame). + The value stored there should be the address of the stmfd + 8. */ + CORE_ADDR frame_loc; + LONGEST return_value; + + frame_loc = frame_unwind_register_unsigned (next_frame, ARM_FP_REGNUM); + if (!safe_read_memory_integer (frame_loc, 4, &return_value)) return; else { @@ -837,6 +790,9 @@ arm_scan_prologue (struct frame_info *fi) } } + if (prev_pc < prologue_end) + prologue_end = prev_pc; + /* Now search the prologue looking for instructions that set up the frame pointer, adjust the stack pointer, and save registers. @@ -858,7 +814,7 @@ arm_scan_prologue (struct frame_info *fi) in which case it is often (but not always) replaced by "str lr, [sp, #-4]!". - Michael Snyder, 2002-04-23] */ - sp_offset = fp_offset = 0; + sp_offset = fp_offset = ip_offset = 0; for (current_pc = prologue_start; current_pc < prologue_end; @@ -868,11 +824,29 @@ arm_scan_prologue (struct frame_info *fi) if (insn == 0xe1a0c00d) /* mov ip, sp */ { + ip_offset = 0; + continue; + } + else if ((insn & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */ + { + unsigned imm = insn & 0xff; /* immediate value */ + unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */ + imm = (imm >> rot) | (imm << (32 - rot)); + ip_offset = imm; + continue; + } + else if ((insn & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */ + { + unsigned imm = insn & 0xff; /* immediate value */ + unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */ + imm = (imm >> rot) | (imm << (32 - rot)); + ip_offset = -imm; continue; } else if (insn == 0xe52de004) /* str lr, [sp, #-4]! */ { - /* Function is frameless: extra_info defaults OK? */ + sp_offset -= 4; + cache->saved_regs[ARM_LR_REGNUM].addr = sp_offset; continue; } else if ((insn & 0xffff0000) == 0xe92d0000) @@ -887,7 +861,7 @@ arm_scan_prologue (struct frame_info *fi) if (mask & (1 << regno)) { sp_offset -= 4; - fi->saved_regs[regno] = sp_offset; + cache->saved_regs[regno].addr = sp_offset; } } else if ((insn & 0xffffc000) == 0xe54b0000 || /* strb rx,[r11,#-n] */ @@ -909,8 +883,8 @@ arm_scan_prologue (struct frame_info *fi) unsigned imm = insn & 0xff; /* immediate value */ unsigned rot = (insn & 0xf00) >> 7; /* rotate amount */ imm = (imm >> rot) | (imm << (32 - rot)); - fp_offset = -imm; - fi->extra_info->framereg = ARM_FP_REGNUM; + fp_offset = -imm + ip_offset; + cache->framereg = ARM_FP_REGNUM; } else if ((insn & 0xfffff000) == 0xe24dd000) /* sub sp, sp #n */ { @@ -923,7 +897,7 @@ arm_scan_prologue (struct frame_info *fi) { sp_offset -= 12; regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07); - fi->saved_regs[regno] = sp_offset; + cache->saved_regs[regno].addr = sp_offset; } else if ((insn & 0xffbf0fff) == 0xec2d0200) /* sfmfd f0, 4, [sp!] */ { @@ -950,7 +924,7 @@ arm_scan_prologue (struct frame_info *fi) for (; fp_start_reg < fp_bound_reg; fp_start_reg++) { sp_offset -= 12; - fi->saved_regs[fp_start_reg++] = sp_offset; + cache->saved_regs[fp_start_reg++].addr = sp_offset; } } else if ((insn & 0xf0000000) != 0xe0000000) @@ -966,273 +940,260 @@ arm_scan_prologue (struct frame_info *fi) /* The frame size is just the negative of the offset (from the original SP) of the last thing thing we pushed on the stack. The frame offset is [new FP] - [new SP]. */ - fi->extra_info->framesize = -sp_offset; - if (fi->extra_info->framereg == ARM_FP_REGNUM) - fi->extra_info->frameoffset = fp_offset - sp_offset; + cache->framesize = -sp_offset; + if (cache->framereg == ARM_FP_REGNUM) + cache->frameoffset = fp_offset - sp_offset; else - fi->extra_info->frameoffset = 0; - - save_prologue_cache (fi); + cache->frameoffset = 0; } -/* Find REGNUM on the stack. Otherwise, it's in an active register. - One thing we might want to do here is to check REGNUM against the - clobber mask, and somehow flag it as invalid if it isn't saved on - the stack somewhere. This would provide a graceful failure mode - when trying to get the value of caller-saves registers for an inner - frame. */ - -static CORE_ADDR -arm_find_callers_reg (struct frame_info *fi, int regnum) +static struct arm_prologue_cache * +arm_make_prologue_cache (struct frame_info *next_frame) { - /* NOTE: cagney/2002-05-03: This function really shouldn't be - needed. Instead the (still being written) register unwind - function could be called directly. */ - for (; fi; fi = fi->next) - { - if (DEPRECATED_PC_IN_CALL_DUMMY (fi->pc, 0, 0)) - { - return deprecated_read_register_dummy (fi->pc, fi->frame, regnum); - } - else if (fi->saved_regs[regnum] != 0) - { - /* NOTE: cagney/2002-05-03: This would normally need to - handle ARM_SP_REGNUM as a special case as, according to - the frame.h comments, saved_regs[SP_REGNUM] contains the - SP value not its address. It appears that the ARM isn't - doing this though. */ - return read_memory_integer (fi->saved_regs[regnum], - REGISTER_RAW_SIZE (regnum)); - } - } - return read_register (regnum); + int reg; + struct arm_prologue_cache *cache; + CORE_ADDR unwound_fp; + + cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache)); + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + + arm_scan_prologue (next_frame, cache); + + unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg); + if (unwound_fp == 0) + return cache; + + cache->prev_sp = unwound_fp + cache->framesize - cache->frameoffset; + + /* Calculate actual addresses of saved registers using offsets + determined by arm_scan_prologue. */ + for (reg = 0; reg < NUM_REGS; reg++) + if (trad_frame_addr_p (cache->saved_regs, reg)) + cache->saved_regs[reg].addr += cache->prev_sp; + + return cache; } -/* Function: frame_chain Given a GDB frame, determine the address of - the calling function's frame. This will be used to create a new - GDB frame struct, and then INIT_EXTRA_FRAME_INFO and - DEPRECATED_INIT_FRAME_PC will be called for the new frame. For - ARM, we save the frame size when we initialize the frame_info. */ -static CORE_ADDR -arm_frame_chain (struct frame_info *fi) +/* Our frame ID for a normal frame is the current function's starting PC + and the caller's SP when we were called. */ + +static void +arm_prologue_this_id (struct frame_info *next_frame, + void **this_cache, + struct frame_id *this_id) { - CORE_ADDR caller_pc; - int framereg = fi->extra_info->framereg; + struct arm_prologue_cache *cache; + struct frame_id id; + CORE_ADDR func; - if (DEPRECATED_PC_IN_CALL_DUMMY (fi->pc, 0, 0)) - /* A generic call dummy's frame is the same as caller's. */ - return fi->frame; + if (*this_cache == NULL) + *this_cache = arm_make_prologue_cache (next_frame); + cache = *this_cache; - if (fi->pc < LOWEST_PC) - return 0; + func = frame_func_unwind (next_frame); - /* If the caller is the startup code, we're at the end of the chain. */ - caller_pc = FRAME_SAVED_PC (fi); + /* This is meant to halt the backtrace at "_start". Make sure we + don't halt it at a generic dummy frame. */ + if (func <= LOWEST_PC || deprecated_inside_entry_file (func)) + return; + + /* If we've hit a wall, stop. */ + if (cache->prev_sp == 0) + return; - /* If the caller is Thumb and the caller is ARM, or vice versa, - the frame register of the caller is different from ours. - So we must scan the prologue of the caller to determine its - frame register number. */ - /* XXX Fixme, we should try to do this without creating a temporary - caller_fi. */ - if (arm_pc_is_thumb (caller_pc) != arm_pc_is_thumb (fi->pc)) + id = frame_id_build (cache->prev_sp, func); + + /* Check that we're not going round in circles with the same frame + ID (but avoid applying the test to sentinel frames which do go + round in circles). */ + if (frame_relative_level (next_frame) >= 0 + && get_frame_type (next_frame) == NORMAL_FRAME + && frame_id_eq (get_frame_id (next_frame), id)) + return; + + *this_id = id; +} + +static void +arm_prologue_prev_register (struct frame_info *next_frame, + void **this_cache, + int prev_regnum, + int *optimized, + enum lval_type *lvalp, + CORE_ADDR *addrp, + int *realnump, + void *valuep) +{ + struct arm_prologue_cache *cache; + + if (*this_cache == NULL) + *this_cache = arm_make_prologue_cache (next_frame); + cache = *this_cache; + + /* If we are asked to unwind the PC, then we need to return the LR + instead. The saved value of PC points into this frame's + prologue, not the next frame's resume location. */ + if (prev_regnum == ARM_PC_REGNUM) + prev_regnum = ARM_LR_REGNUM; + + /* SP is generally not saved to the stack, but this frame is + identified by NEXT_FRAME's stack pointer at the time of the call. + The value was already reconstructed into PREV_SP. */ + if (prev_regnum == ARM_SP_REGNUM) { - struct frame_info caller_fi; - struct cleanup *old_chain; - - /* Create a temporary frame suitable for scanning the caller's - prologue. (Ugh.) */ - memset (&caller_fi, 0, sizeof (caller_fi)); - caller_fi.extra_info = (struct frame_extra_info *) - xcalloc (1, sizeof (struct frame_extra_info)); - old_chain = make_cleanup (xfree, caller_fi.extra_info); - caller_fi.saved_regs = (CORE_ADDR *) - xcalloc (1, SIZEOF_FRAME_SAVED_REGS); - make_cleanup (xfree, caller_fi.saved_regs); - - /* Now, scan the prologue and obtain the frame register. */ - caller_fi.pc = caller_pc; - arm_scan_prologue (&caller_fi); - framereg = caller_fi.extra_info->framereg; - - /* Deallocate the storage associated with the temporary frame - created above. */ - do_cleanups (old_chain); + *lvalp = not_lval; + if (valuep) + store_unsigned_integer (valuep, 4, cache->prev_sp); + return; } - /* If the caller used a frame register, return its value. - Otherwise, return the caller's stack pointer. */ - if (framereg == ARM_FP_REGNUM || framereg == THUMB_FP_REGNUM) - return arm_find_callers_reg (fi, framereg); - else - return fi->frame + fi->extra_info->framesize; + trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum, + optimized, lvalp, addrp, realnump, valuep); } -/* This function actually figures out the frame address for a given pc - and sp. This is tricky because we sometimes don't use an explicit - frame pointer, and the previous stack pointer isn't necessarily - recorded on the stack. The only reliable way to get this info is - to examine the prologue. FROMLEAF is a little confusing, it means - this is the next frame up the chain AFTER a frameless function. If - this is true, then the frame value for this frame is still in the - fp register. */ +struct frame_unwind arm_prologue_unwind = { + NORMAL_FRAME, + arm_prologue_this_id, + arm_prologue_prev_register +}; -static void -arm_init_extra_frame_info (int fromleaf, struct frame_info *fi) +static const struct frame_unwind * +arm_prologue_unwind_sniffer (struct frame_info *next_frame) { - int reg; - CORE_ADDR sp; + return &arm_prologue_unwind; +} - if (fi->saved_regs == NULL) - frame_saved_regs_zalloc (fi); +static CORE_ADDR +arm_normal_frame_base (struct frame_info *next_frame, void **this_cache) +{ + struct arm_prologue_cache *cache; - fi->extra_info = (struct frame_extra_info *) - frame_obstack_alloc (sizeof (struct frame_extra_info)); + if (*this_cache == NULL) + *this_cache = arm_make_prologue_cache (next_frame); + cache = *this_cache; - fi->extra_info->framesize = 0; - fi->extra_info->frameoffset = 0; - fi->extra_info->framereg = 0; + return cache->prev_sp + cache->frameoffset - cache->framesize; +} - if (fi->next) - fi->pc = FRAME_SAVED_PC (fi->next); +struct frame_base arm_normal_base = { + &arm_prologue_unwind, + arm_normal_frame_base, + arm_normal_frame_base, + arm_normal_frame_base +}; - memset (fi->saved_regs, '\000', sizeof fi->saved_regs); +static struct arm_prologue_cache * +arm_make_sigtramp_cache (struct frame_info *next_frame) +{ + struct arm_prologue_cache *cache; + int reg; - /* Compute stack pointer for this frame. We use this value for both - the sigtramp and call dummy cases. */ - if (!fi->next) - sp = read_sp(); - else if (DEPRECATED_PC_IN_CALL_DUMMY (fi->next->pc, 0, 0)) - /* For generic dummy frames, pull the value direct from the frame. - Having an unwind function to do this would be nice. */ - sp = deprecated_read_register_dummy (fi->next->pc, fi->next->frame, - ARM_SP_REGNUM); - else - sp = (fi->next->frame - fi->next->extra_info->frameoffset - + fi->next->extra_info->framesize); - - /* Determine whether or not we're in a sigtramp frame. - Unfortunately, it isn't sufficient to test (get_frame_type (fi) - == SIGTRAMP_FRAME) because this value is sometimes set after - invoking INIT_EXTRA_FRAME_INFO. So we test *both* - (get_frame_type (fi) == SIGTRAMP_FRAME) and PC_IN_SIGTRAMP to - determine if we need to use the sigcontext addresses for the - saved registers. - - Note: If an ARM PC_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 PC_IN_SIGTRAMP. */ + cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache)); - /* FIXME: cagney/2002-11-18: This problem will go away once - frame.c:get_prev_frame() is modified to set the frame's type - before calling functions like this. */ + cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM); - if (SIGCONTEXT_REGISTER_ADDRESS_P () - && ((get_frame_type (fi) == SIGTRAMP_FRAME) || PC_IN_SIGTRAMP (fi->pc, (char *)0))) - { - for (reg = 0; reg < NUM_REGS; reg++) - fi->saved_regs[reg] = SIGCONTEXT_REGISTER_ADDRESS (sp, fi->pc, reg); + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); - /* FIXME: What about thumb mode? */ - fi->extra_info->framereg = ARM_SP_REGNUM; - fi->frame = - read_memory_integer (fi->saved_regs[fi->extra_info->framereg], - REGISTER_RAW_SIZE (fi->extra_info->framereg)); - fi->extra_info->framesize = 0; - fi->extra_info->frameoffset = 0; + for (reg = 0; reg < NUM_REGS; reg++) + cache->saved_regs[reg].addr + = SIGCONTEXT_REGISTER_ADDRESS (cache->prev_sp, + frame_pc_unwind (next_frame), reg); - } - else - { - arm_scan_prologue (fi); - - if (!fi->next) - /* This is the innermost frame? */ - fi->frame = read_register (fi->extra_info->framereg); - else if (DEPRECATED_PC_IN_CALL_DUMMY (fi->next->pc, 0, 0)) - /* Next inner most frame is a dummy, just grab its frame. - Dummy frames always have the same FP as their caller. */ - fi->frame = fi->next->frame; - else if (fi->extra_info->framereg == ARM_FP_REGNUM - || fi->extra_info->framereg == THUMB_FP_REGNUM) - { - /* not the innermost frame */ - /* If we have an FP, the callee saved it. */ - if (fi->next->saved_regs[fi->extra_info->framereg] != 0) - fi->frame = - read_memory_integer (fi->next - ->saved_regs[fi->extra_info->framereg], 4); - else if (fromleaf) - /* If we were called by a frameless fn. then our frame is - still in the frame pointer register on the board... */ - fi->frame = read_fp (); - } + /* FIXME: What about thumb mode? */ + cache->framereg = ARM_SP_REGNUM; + cache->prev_sp + = read_memory_integer (cache->saved_regs[cache->framereg].addr, + DEPRECATED_REGISTER_RAW_SIZE (cache->framereg)); - /* Calculate actual addresses of saved registers using offsets - determined by arm_scan_prologue. */ - for (reg = 0; reg < NUM_REGS; reg++) - if (fi->saved_regs[reg] != 0) - fi->saved_regs[reg] += (fi->frame + fi->extra_info->framesize - - fi->extra_info->frameoffset); - } + return cache; } +static void +arm_sigtramp_this_id (struct frame_info *next_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct arm_prologue_cache *cache; -/* Find the caller of this frame. We do this by seeing if ARM_LR_REGNUM - is saved in the stack anywhere, otherwise we get it from the - registers. + if (*this_cache == NULL) + *this_cache = arm_make_sigtramp_cache (next_frame); + cache = *this_cache; - The old definition of this function was a macro: - #define FRAME_SAVED_PC(FRAME) \ - ADDR_BITS_REMOVE (read_memory_integer ((FRAME)->frame - 4, 4)) */ + /* FIXME drow/2003-07-07: This isn't right if we single-step within + the sigtramp frame; the PC should be the beginning of the trampoline. */ + *this_id = frame_id_build (cache->prev_sp, frame_pc_unwind (next_frame)); +} -static CORE_ADDR -arm_frame_saved_pc (struct frame_info *fi) +static void +arm_sigtramp_prev_register (struct frame_info *next_frame, + void **this_cache, + int prev_regnum, + int *optimized, + enum lval_type *lvalp, + CORE_ADDR *addrp, + int *realnump, + void *valuep) { - /* If a dummy frame, pull the PC out of the frame's register buffer. */ - if (DEPRECATED_PC_IN_CALL_DUMMY (fi->pc, 0, 0)) - return deprecated_read_register_dummy (fi->pc, fi->frame, ARM_PC_REGNUM); + struct arm_prologue_cache *cache; - if (DEPRECATED_PC_IN_CALL_DUMMY (fi->pc, fi->frame - fi->extra_info->frameoffset, - fi->frame)) - { - return read_memory_integer (fi->saved_regs[ARM_PC_REGNUM], - REGISTER_RAW_SIZE (ARM_PC_REGNUM)); - } - else - { - CORE_ADDR pc = arm_find_callers_reg (fi, ARM_LR_REGNUM); - return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc; - } + if (*this_cache == NULL) + *this_cache = arm_make_sigtramp_cache (next_frame); + cache = *this_cache; + + trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum, + optimized, lvalp, addrp, realnump, valuep); } -/* Return the frame address. On ARM, it is R11; on Thumb it is R7. - Examine the Program Status Register to decide which state we're in. */ +struct frame_unwind arm_sigtramp_unwind = { + SIGTRAMP_FRAME, + arm_sigtramp_this_id, + arm_sigtramp_prev_register +}; -static CORE_ADDR -arm_read_fp (void) +static const struct frame_unwind * +arm_sigtramp_unwind_sniffer (struct frame_info *next_frame) { - if (read_register (ARM_PS_REGNUM) & 0x20) /* Bit 5 is Thumb state bit */ - return read_register (THUMB_FP_REGNUM); /* R7 if Thumb */ - else - return read_register (ARM_FP_REGNUM); /* R11 if ARM */ + /* Note: If an ARM PC_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 PC_IN_SIGTRAMP. */ + + if (SIGCONTEXT_REGISTER_ADDRESS_P () + && PC_IN_SIGTRAMP (frame_pc_unwind (next_frame), (char *) 0)) + return &arm_sigtramp_unwind; + + return NULL; } -/* Store into a struct frame_saved_regs the addresses of the saved - registers of frame described by FRAME_INFO. This includes special - registers such as PC and FP saved in special ways in the stack - frame. SP is even more special: the address we return for it IS - the sp for the next frame. */ +/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that + dummy frame. The frame ID's base needs to match the TOS value + saved by save_dummy_frame_tos() and returned from + arm_push_dummy_call, and the PC needs to match the dummy frame's + breakpoint. */ -static void -arm_frame_init_saved_regs (struct frame_info *fip) +static struct frame_id +arm_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) { + return frame_id_build (frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM), + frame_pc_unwind (next_frame)); +} - if (fip->saved_regs) - return; +/* Given THIS_FRAME, find the previous frame's resume PC (which will + be used to construct the previous frame's ID, after looking up the + containing function). */ + +static CORE_ADDR +arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + CORE_ADDR pc; + pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM); + return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc; +} - arm_init_extra_frame_info (0, fip); +static CORE_ADDR +arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM); } /* Set the return address for a generic dummy frame. ARM uses the @@ -1241,7 +1202,7 @@ arm_frame_init_saved_regs (struct frame_info *fip) static CORE_ADDR arm_push_return_address (CORE_ADDR pc, CORE_ADDR sp) { - write_register (ARM_LR_REGNUM, CALL_DUMMY_ADDRESS ()); + write_register (ARM_LR_REGNUM, entry_point_address ()); return sp; } @@ -1280,7 +1241,7 @@ arm_push_dummy_frame (void) write_register (ARM_SP_REGNUM, sp); } -/* CALL_DUMMY_WORDS: +/* DEPRECATED_CALL_DUMMY_WORDS: This sequence of words is the instructions mov lr,pc @@ -1300,17 +1261,17 @@ static LONGEST arm_call_dummy_words[] = FIXME rearnsha 2002-02018: Tweeking current_gdbarch is not an optimal solution, but the call to arm_fix_call_dummy is immediately - followed by a call to run_stack_dummy, which is the only function - where call_dummy_breakpoint_offset is actually used. */ + followed by a call to call_function_by_hand, which is the only + function where call_dummy_breakpoint_offset is actually used. */ static void arm_set_call_dummy_breakpoint_offset (void) { if (caller_is_thumb) - set_gdbarch_call_dummy_breakpoint_offset (current_gdbarch, 4); + set_gdbarch_deprecated_call_dummy_breakpoint_offset (current_gdbarch, 4); else - set_gdbarch_call_dummy_breakpoint_offset (current_gdbarch, 8); + set_gdbarch_deprecated_call_dummy_breakpoint_offset (current_gdbarch, 8); } /* Fix up the call dummy, based on whether the processor is currently @@ -1377,166 +1338,160 @@ arm_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, write_register (4, fun); } -/* Note: ScottB +/* When arguments must be pushed onto the stack, they go on in reverse + order. The code below implements a FILO (stack) to do this. */ + +struct stack_item +{ + int len; + struct stack_item *prev; + void *data; +}; + +static struct stack_item * +push_stack_item (struct stack_item *prev, void *contents, int len) +{ + struct stack_item *si; + si = xmalloc (sizeof (struct stack_item)); + si->data = xmalloc (len); + si->len = len; + si->prev = prev; + memcpy (si->data, contents, len); + return si; +} + +static struct stack_item * +pop_stack_item (struct stack_item *si) +{ + struct stack_item *dead = si; + si = si->prev; + xfree (dead->data); + xfree (dead); + return si; +} - This function does not support passing parameters using the FPA - variant of the APCS. It passes any floating point arguments in the - general registers and/or on the stack. */ +/* We currently only support passing parameters in integer registers. This + conforms with GCC's default model. Several other variants exist and + we should probably support some of them based on the selected ABI. */ static CORE_ADDR -arm_push_arguments (int nargs, struct value **args, CORE_ADDR sp, - int struct_return, CORE_ADDR struct_addr) +arm_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, + struct regcache *regcache, CORE_ADDR bp_addr, int nargs, + struct value **args, CORE_ADDR sp, int struct_return, + CORE_ADDR struct_addr) { - CORE_ADDR fp; int argnum; int argreg; int nstack; - int simd_argreg; - int second_pass; - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + struct stack_item *si = NULL; + + /* Set the return address. For the ARM, the return breakpoint is + always at BP_ADDR. */ + /* XXX Fix for Thumb. */ + regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr); /* Walk through the list of args and determine how large a temporary stack is required. Need to take care here as structs may be - passed on the stack, and we have to to push them. On the second - pass, do the store. */ + passed on the stack, and we have to to push them. */ + nstack = 0; + + argreg = ARM_A1_REGNUM; nstack = 0; - fp = sp; - for (second_pass = 0; second_pass < 2; second_pass++) + + /* Some platforms require a double-word aligned stack. Make sure sp + is correctly aligned before we start. We always do this even if + it isn't really needed -- it can never hurt things. */ + sp &= ~(CORE_ADDR)(2 * DEPRECATED_REGISTER_SIZE - 1); + + /* The struct_return pointer occupies the first parameter + passing register. */ + if (struct_return) + { + if (arm_debug) + fprintf_unfiltered (gdb_stdlog, "struct return in %s = 0x%s\n", + REGISTER_NAME (argreg), paddr (struct_addr)); + regcache_cooked_write_unsigned (regcache, argreg, struct_addr); + argreg++; + } + + for (argnum = 0; argnum < nargs; argnum++) { - /* Compute the FP using the information computed during the - first pass. */ - if (second_pass) - fp = sp - nstack; - - simd_argreg = 0; - argreg = ARM_A1_REGNUM; - nstack = 0; - - /* The struct_return pointer occupies the first parameter - passing register. */ - if (struct_return) + int len; + struct type *arg_type; + struct type *target_type; + enum type_code typecode; + char *val; + + arg_type = check_typedef (VALUE_TYPE (args[argnum])); + len = TYPE_LENGTH (arg_type); + target_type = TYPE_TARGET_TYPE (arg_type); + typecode = TYPE_CODE (arg_type); + val = VALUE_CONTENTS (args[argnum]); + + /* If the argument is a pointer to a function, and it is a + Thumb function, create a LOCAL copy of the value and set + the THUMB bit in it. */ + if (TYPE_CODE_PTR == typecode + && target_type != NULL + && TYPE_CODE_FUNC == TYPE_CODE (target_type)) { - if (second_pass) + CORE_ADDR regval = extract_unsigned_integer (val, len); + if (arm_pc_is_thumb (regval)) { - if (arm_debug) - fprintf_unfiltered (gdb_stdlog, - "struct return in %s = 0x%s\n", - REGISTER_NAME (argreg), - paddr (struct_addr)); - write_register (argreg, struct_addr); + val = alloca (len); + store_unsigned_integer (val, len, MAKE_THUMB_ADDR (regval)); } - argreg++; } - for (argnum = 0; argnum < nargs; argnum++) + /* Copy the argument to general registers or the stack in + register-sized pieces. Large arguments are split between + registers and stack. */ + while (len > 0) { - int len; - struct type *arg_type; - struct type *target_type; - enum type_code typecode; - char *val; - - arg_type = check_typedef (VALUE_TYPE (args[argnum])); - len = TYPE_LENGTH (arg_type); - target_type = TYPE_TARGET_TYPE (arg_type); - typecode = TYPE_CODE (arg_type); - val = VALUE_CONTENTS (args[argnum]); - - /* If the argument is a pointer to a function, and it is a - Thumb function, create a LOCAL copy of the value and set - the THUMB bit in it. */ - if (second_pass - && TYPE_CODE_PTR == typecode - && target_type != NULL - && TYPE_CODE_FUNC == TYPE_CODE (target_type)) + int partial_len = len < DEPRECATED_REGISTER_SIZE ? len : DEPRECATED_REGISTER_SIZE; + + if (argreg <= ARM_LAST_ARG_REGNUM) { - CORE_ADDR regval = extract_address (val, len); - if (arm_pc_is_thumb (regval)) - { - val = alloca (len); - store_address (val, len, MAKE_THUMB_ADDR (regval)); - } + /* The argument is being passed in a general purpose + register. */ + CORE_ADDR regval = extract_unsigned_integer (val, partial_len); + if (arm_debug) + fprintf_unfiltered (gdb_stdlog, "arg %d in %s = 0x%s\n", + argnum, REGISTER_NAME (argreg), + phex (regval, DEPRECATED_REGISTER_SIZE)); + regcache_cooked_write_unsigned (regcache, argreg, regval); + argreg++; } - - /* Copy the argument to general registers or the stack in - register-sized pieces. Large arguments are split between - registers and stack. */ - while (len > 0) + else { - int partial_len = len < REGISTER_SIZE ? len : REGISTER_SIZE; - - if (argreg <= ARM_LAST_ARG_REGNUM) - { - /* The argument is being passed in a general purpose - register. */ - if (second_pass) - { - CORE_ADDR regval = extract_address (val, - partial_len); - if (arm_debug) - fprintf_unfiltered (gdb_stdlog, - "arg %d in %s = 0x%s\n", - argnum, - REGISTER_NAME (argreg), - phex (regval, REGISTER_SIZE)); - write_register (argreg, regval); - } - argreg++; - } - else - { - if (second_pass) - { - /* Push the arguments onto the stack. */ - if (arm_debug) - fprintf_unfiltered (gdb_stdlog, - "arg %d @ 0x%s + %d\n", - argnum, paddr (fp), nstack); - write_memory (fp + nstack, val, REGISTER_SIZE); - } - nstack += REGISTER_SIZE; - } - - len -= partial_len; - val += partial_len; + /* Push the arguments onto the stack. */ + if (arm_debug) + fprintf_unfiltered (gdb_stdlog, "arg %d @ sp + %d\n", + argnum, nstack); + si = push_stack_item (si, val, DEPRECATED_REGISTER_SIZE); + nstack += DEPRECATED_REGISTER_SIZE; } - + + len -= partial_len; + val += partial_len; } } + /* If we have an odd number of words to push, then decrement the stack + by one word now, so first stack argument will be dword aligned. */ + if (nstack & 4) + sp -= 4; - /* Return the botom of the argument list (pointed to by fp). */ - return fp; -} - -/* Pop the current frame. So long as the frame info has been - initialized properly (see arm_init_extra_frame_info), this code - works for dummy frames as well as regular frames. I.e, there's no - need to have a special case for dummy frames. */ -static void -arm_pop_frame (void) -{ - int regnum; - struct frame_info *frame = get_current_frame (); - CORE_ADDR old_SP = (frame->frame - frame->extra_info->frameoffset - + frame->extra_info->framesize); - - if (DEPRECATED_PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)) + while (si) { - generic_pop_dummy_frame (); - flush_cached_frames (); - return; + sp -= si->len; + write_memory (sp, si->data, si->len); + si = pop_stack_item (si); } - for (regnum = 0; regnum < NUM_REGS; regnum++) - if (frame->saved_regs[regnum] != 0) - write_register (regnum, - read_memory_integer (frame->saved_regs[regnum], - REGISTER_RAW_SIZE (regnum))); + /* Finally, update teh SP register. */ + regcache_cooked_write_unsigned (regcache, ARM_SP_REGNUM, sp); - write_register (ARM_PC_REGNUM, FRAME_SAVED_PC (frame)); - write_register (ARM_SP_REGNUM, old_SP); - - flush_cached_frames (); + return sp; } static void @@ -1561,7 +1516,7 @@ static void arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, const char *args) { - register unsigned long status = read_register (ARM_FPS_REGNUM); + unsigned long status = read_register (ARM_FPS_REGNUM); int type; type = (status >> 24) & 127; @@ -1664,7 +1619,8 @@ arm_register_sim_regno (int regnum) little-endian systems. */ static void -convert_from_extended (void *ptr, void *dbl) +convert_from_extended (const struct floatformat *fmt, const void *ptr, + void *dbl) { DOUBLEST d; if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) @@ -1672,14 +1628,14 @@ convert_from_extended (void *ptr, void *dbl) else floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword, ptr, &d); - floatformat_from_doublest (TARGET_DOUBLE_FORMAT, &d, dbl); + floatformat_from_doublest (fmt, &d, dbl); } static void -convert_to_extended (void *dbl, void *ptr) +convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr) { DOUBLEST d; - floatformat_to_doublest (TARGET_DOUBLE_FORMAT, ptr, &d); + floatformat_to_doublest (fmt, ptr, &d); if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl); else @@ -1814,7 +1770,7 @@ thumb_get_next_pc (CORE_ADDR pc) /* Fetch the saved PC from the stack. It's stored above all of the other registers. */ - offset = bitcount (bits (inst1, 0, 7)) * REGISTER_SIZE; + offset = bitcount (bits (inst1, 0, 7)) * DEPRECATED_REGISTER_SIZE; sp = read_register (ARM_SP_REGNUM); nextpc = (CORE_ADDR) read_memory_integer (sp + offset, 4); nextpc = ADDR_BITS_REMOVE (nextpc); @@ -2098,7 +2054,7 @@ gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info) static asymbol *asym; static combined_entry_type ce; static struct coff_symbol_struct csym; - static struct _bfd fake_bfd; + static struct bfd fake_bfd; static bfd_target fake_target; if (csym.native == NULL) @@ -2217,24 +2173,34 @@ arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr) static void arm_extract_return_value (struct type *type, - char regbuf[REGISTER_BYTES], - char *valbuf) + struct regcache *regs, + void *dst) { + bfd_byte *valbuf = dst; + if (TYPE_CODE_FLT == TYPE_CODE (type)) { - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - switch (tdep->fp_model) + switch (arm_get_fp_model (current_gdbarch)) { case ARM_FLOAT_FPA: - convert_from_extended (®buf[REGISTER_BYTE (ARM_F0_REGNUM)], - valbuf); + { + /* The value is in register F0 in internal format. We need to + extract the raw value and then convert it to the desired + internal type. */ + bfd_byte tmpbuf[FP_REGISTER_RAW_SIZE]; + + regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf); + convert_from_extended (floatformat_from_type (type), tmpbuf, + valbuf); + } break; - case ARM_FLOAT_SOFT: + case ARM_FLOAT_SOFT_FPA: case ARM_FLOAT_SOFT_VFP: - memcpy (valbuf, ®buf[REGISTER_BYTE (ARM_A1_REGNUM)], - TYPE_LENGTH (type)); + regcache_cooked_read (regs, ARM_A1_REGNUM, valbuf); + if (TYPE_LENGTH (type) > 4) + regcache_cooked_read (regs, ARM_A1_REGNUM + 1, + valbuf + INT_REGISTER_RAW_SIZE); break; default: @@ -2244,9 +2210,50 @@ arm_extract_return_value (struct type *type, break; } } + else if (TYPE_CODE (type) == TYPE_CODE_INT + || TYPE_CODE (type) == TYPE_CODE_CHAR + || TYPE_CODE (type) == TYPE_CODE_BOOL + || TYPE_CODE (type) == TYPE_CODE_PTR + || TYPE_CODE (type) == TYPE_CODE_REF + || TYPE_CODE (type) == TYPE_CODE_ENUM) + { + /* If the the type is a plain integer, then the access is + straight-forward. Otherwise we have to play around a bit more. */ + int len = TYPE_LENGTH (type); + int regno = ARM_A1_REGNUM; + ULONGEST tmp; + + while (len > 0) + { + /* By using store_unsigned_integer we avoid having to do + anything special for small big-endian values. */ + regcache_cooked_read_unsigned (regs, regno++, &tmp); + store_unsigned_integer (valbuf, + (len > INT_REGISTER_RAW_SIZE + ? INT_REGISTER_RAW_SIZE : len), + tmp); + len -= INT_REGISTER_RAW_SIZE; + valbuf += INT_REGISTER_RAW_SIZE; + } + } else - memcpy (valbuf, ®buf[REGISTER_BYTE (ARM_A1_REGNUM)], - TYPE_LENGTH (type)); + { + /* For a structure or union the behaviour is as if the value had + been stored to word-aligned memory and then loaded into + registers with 32-bit load instruction(s). */ + int len = TYPE_LENGTH (type); + int regno = ARM_A1_REGNUM; + bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE]; + + while (len > 0) + { + regcache_cooked_read (regs, regno++, tmpbuf); + memcpy (valbuf, tmpbuf, + len > INT_REGISTER_RAW_SIZE ? INT_REGISTER_RAW_SIZE : len); + len -= INT_REGISTER_RAW_SIZE; + valbuf += INT_REGISTER_RAW_SIZE; + } + } } /* Extract from an array REGBUF containing the (raw) register state @@ -2269,14 +2276,14 @@ static int arm_use_struct_convention (int gcc_p, struct type *type) { int nRc; - register enum type_code code; + enum type_code code; /* In the ARM ABI, "integer" like aggregate types are returned in registers. For an aggregate type to be integer like, its size - must be less than or equal to REGISTER_SIZE and the offset of - each addressable subfield must be zero. Note that bit fields are - not addressable, and all addressable subfields of unions always - start at offset zero. + must be less than or equal to DEPRECATED_REGISTER_SIZE and the + offset of each addressable subfield must be zero. Note that bit + fields are not addressable, and all addressable subfields of + unions always start at offset zero. This function is based on the behaviour of GCC 2.95.1. See: gcc/arm.c: arm_return_in_memory() for details. @@ -2290,7 +2297,7 @@ arm_use_struct_convention (int gcc_p, struct type *type) /* All aggregate types that won't fit in a register must be returned in memory. */ - if (TYPE_LENGTH (type) > REGISTER_SIZE) + if (TYPE_LENGTH (type) > DEPRECATED_REGISTER_SIZE) { return 1; } @@ -2312,11 +2319,11 @@ arm_use_struct_convention (int gcc_p, struct type *type) int i; /* Need to check if this struct/union is "integer" like. For this to be true, its size must be less than or equal to - REGISTER_SIZE and the offset of each addressable subfield - must be zero. Note that bit fields are not addressable, and - unions always start at offset zero. If any of the subfields - is a floating point type, the struct/union cannot be an - integer type. */ + DEPRECATED_REGISTER_SIZE and the offset of each addressable + subfield must be zero. Note that bit fields are not + addressable, and unions always start at offset zero. If any + of the subfields is a floating point type, the struct/union + cannot be an integer type. */ /* For each field in the object, check: 1) Is it FP? --> yes, nRc = 1; @@ -2359,26 +2366,29 @@ arm_use_struct_convention (int gcc_p, struct type *type) TYPE, given in virtual format. */ static void -arm_store_return_value (struct type *type, char *valbuf) +arm_store_return_value (struct type *type, struct regcache *regs, + const void *src) { + const bfd_byte *valbuf = src; + if (TYPE_CODE (type) == TYPE_CODE_FLT) { - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); char buf[ARM_MAX_REGISTER_RAW_SIZE]; - switch (tdep->fp_model) + switch (arm_get_fp_model (current_gdbarch)) { case ARM_FLOAT_FPA: - convert_to_extended (valbuf, buf); - deprecated_write_register_bytes (REGISTER_BYTE (ARM_F0_REGNUM), buf, - FP_REGISTER_RAW_SIZE); + convert_to_extended (floatformat_from_type (type), buf, valbuf); + regcache_cooked_write (regs, ARM_F0_REGNUM, buf); break; - case ARM_FLOAT_SOFT: + case ARM_FLOAT_SOFT_FPA: case ARM_FLOAT_SOFT_VFP: - deprecated_write_register_bytes (ARM_A1_REGNUM, valbuf, - TYPE_LENGTH (type)); + regcache_cooked_write (regs, ARM_A1_REGNUM, valbuf); + if (TYPE_LENGTH (type) > 4) + regcache_cooked_write (regs, ARM_A1_REGNUM + 1, + valbuf + INT_REGISTER_RAW_SIZE); break; default: @@ -2388,18 +2398,57 @@ arm_store_return_value (struct type *type, char *valbuf) break; } } - else - deprecated_write_register_bytes (ARM_A1_REGNUM, valbuf, - TYPE_LENGTH (type)); -} + else if (TYPE_CODE (type) == TYPE_CODE_INT + || TYPE_CODE (type) == TYPE_CODE_CHAR + || TYPE_CODE (type) == TYPE_CODE_BOOL + || TYPE_CODE (type) == TYPE_CODE_PTR + || TYPE_CODE (type) == TYPE_CODE_REF + || TYPE_CODE (type) == TYPE_CODE_ENUM) + { + if (TYPE_LENGTH (type) <= 4) + { + /* Values of one word or less are zero/sign-extended and + returned in r0. */ + bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE]; + LONGEST val = unpack_long (type, valbuf); -/* Store the address of the place in which to copy the structure the - subroutine will return. This is called from call_function. */ + store_signed_integer (tmpbuf, INT_REGISTER_RAW_SIZE, val); + regcache_cooked_write (regs, ARM_A1_REGNUM, tmpbuf); + } + else + { + /* Integral values greater than one word are stored in consecutive + registers starting with r0. This will always be a multiple of + the regiser size. */ + int len = TYPE_LENGTH (type); + int regno = ARM_A1_REGNUM; -static void -arm_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) -{ - write_register (ARM_A1_REGNUM, addr); + while (len > 0) + { + regcache_cooked_write (regs, regno++, valbuf); + len -= INT_REGISTER_RAW_SIZE; + valbuf += INT_REGISTER_RAW_SIZE; + } + } + } + else + { + /* For a structure or union the behaviour is as if the value had + been stored to word-aligned memory and then loaded into + registers with 32-bit load instruction(s). */ + int len = TYPE_LENGTH (type); + int regno = ARM_A1_REGNUM; + bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE]; + + while (len > 0) + { + memcpy (tmpbuf, valbuf, + len > INT_REGISTER_RAW_SIZE ? INT_REGISTER_RAW_SIZE : len); + regcache_cooked_write (regs, regno++, tmpbuf); + len -= INT_REGISTER_RAW_SIZE; + valbuf += INT_REGISTER_RAW_SIZE; + } + } } static int @@ -2415,7 +2464,7 @@ arm_get_longjmp_target (CORE_ADDR *pc) INT_REGISTER_RAW_SIZE)) return 0; - *pc = extract_address (buf, INT_REGISTER_RAW_SIZE); + *pc = extract_unsigned_integer (buf, INT_REGISTER_RAW_SIZE); return 1; } @@ -2469,16 +2518,92 @@ arm_skip_stub (CORE_ADDR pc) return 0; /* not a stub */ } -/* If the user changes the register disassembly flavor used for info - register and other commands, we have to also switch the flavor used - in opcodes for disassembly output. This function is run in the set - disassembly_flavor command, and does that. */ +static void +set_arm_command (char *args, int from_tty) +{ + printf_unfiltered ("\"set arm\" must be followed by an apporpriate subcommand.\n"); + help_list (setarmcmdlist, "set arm ", all_commands, gdb_stdout); +} static void -set_disassembly_flavor_sfunc (char *args, int from_tty, +show_arm_command (char *args, int from_tty) +{ + cmd_show_list (showarmcmdlist, from_tty, ""); +} + +enum arm_float_model +arm_get_fp_model (struct gdbarch *gdbarch) +{ + if (arm_fp_model == ARM_FLOAT_AUTO) + return gdbarch_tdep (gdbarch)->fp_model; + + return arm_fp_model; +} + +static void +arm_set_fp (struct gdbarch *gdbarch) +{ + enum arm_float_model fp_model = arm_get_fp_model (gdbarch); + + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE + && (fp_model == ARM_FLOAT_SOFT_FPA || fp_model == ARM_FLOAT_FPA)) + { + set_gdbarch_double_format (gdbarch, + &floatformat_ieee_double_littlebyte_bigword); + set_gdbarch_long_double_format + (gdbarch, &floatformat_ieee_double_littlebyte_bigword); + } + else + { + set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little); + set_gdbarch_long_double_format (gdbarch, + &floatformat_ieee_double_little); + } +} + +static void +set_fp_model_sfunc (char *args, int from_tty, + struct cmd_list_element *c) +{ + enum arm_float_model fp_model; + + for (fp_model = ARM_FLOAT_AUTO; fp_model != ARM_FLOAT_LAST; fp_model++) + if (strcmp (current_fp_model, fp_model_strings[fp_model]) == 0) + { + arm_fp_model = fp_model; + break; + } + + if (fp_model == ARM_FLOAT_LAST) + internal_error (__FILE__, __LINE__, "Invalid fp model accepted: %s.", + current_fp_model); + + if (gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm) + arm_set_fp (current_gdbarch); +} + +static void +show_fp_model (char *args, int from_tty, + struct cmd_list_element *c) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + + if (arm_fp_model == ARM_FLOAT_AUTO + && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm) + printf_filtered (" - the default for the current ABI is \"%s\".\n", + fp_model_strings[tdep->fp_model]); +} + +/* If the user changes the register disassembly style used for info + register and other commands, we have to also switch the style used + in opcodes for disassembly output. This function is run in the "set + arm disassembly" command, and does that. */ + +static void +set_disassembly_style_sfunc (char *args, int from_tty, struct cmd_list_element *c) { - set_disassembly_flavor (); + set_disassembly_style (); } /* Return the ARM register name corresponding to register I. */ @@ -2489,16 +2614,16 @@ arm_register_name (int i) } static void -set_disassembly_flavor (void) +set_disassembly_style (void) { const char *setname, *setdesc, **regnames; int numregs, j; - /* Find the flavor that the user wants in the opcodes table. */ + /* Find the style that the user wants in the opcodes table. */ int current = 0; numregs = get_arm_regnames (current, &setname, &setdesc, ®names); - while ((disassembly_flavor != setname) - && (current < num_flavor_options)) + while ((disassembly_style != setname) + && (current < num_disassembly_options)) get_arm_regnames (++current, &setname, &setdesc, ®names); current_option = current; @@ -2522,62 +2647,17 @@ set_disassembly_flavor (void) set_arm_regname_option (current); } -/* arm_othernames implements the "othernames" command. This is kind - of hacky, and I prefer the set-show disassembly-flavor which is - also used for the x86 gdb. I will keep this around, however, in - case anyone is actually using it. */ +/* arm_othernames implements the "othernames" command. This is deprecated + by the "set arm disassembly" command. */ static void arm_othernames (char *names, int n) { /* Circle through the various flavors. */ - current_option = (current_option + 1) % num_flavor_options; - - disassembly_flavor = valid_flavors[current_option]; - set_disassembly_flavor (); -} - -/* Fetch, and possibly build, an appropriate link_map_offsets structure - for ARM linux targets using the struct offsets defined in . - Note, however, that link.h is not actually referred to in this file. - Instead, the relevant structs offsets were obtained from examining - link.h. (We can't refer to link.h from this file because the host - system won't necessarily have it, or if it does, the structs which - it defines will refer to the host system, not the target). */ - -struct link_map_offsets * -arm_linux_svr4_fetch_link_map_offsets (void) -{ - static struct link_map_offsets lmo; - static struct link_map_offsets *lmp = 0; - - if (lmp == 0) - { - lmp = &lmo; - - lmo.r_debug_size = 8; /* Actual size is 20, but this is all we - need. */ - - lmo.r_map_offset = 4; - lmo.r_map_size = 4; - - lmo.link_map_size = 20; /* Actual size is 552, but this is all we - need. */ - - lmo.l_addr_offset = 0; - lmo.l_addr_size = 4; - - lmo.l_name_offset = 4; - lmo.l_name_size = 4; - - lmo.l_next_offset = 12; - lmo.l_next_size = 4; - - lmo.l_prev_offset = 16; - lmo.l_prev_size = 4; - } + current_option = (current_option + 1) % num_disassembly_options; - return lmp; + disassembly_style = valid_disassembly_styles[current_option]; + set_disassembly_style (); } /* Test whether the coff symbol specific value corresponds to a Thumb @@ -2706,56 +2786,42 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { struct gdbarch_tdep *tdep; struct gdbarch *gdbarch; - enum gdb_osabi osabi = GDB_OSABI_UNKNOWN; /* Try to deterimine the ABI of the object we are loading. */ - if (info.abfd != NULL) + if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN) { - osabi = gdbarch_lookup_osabi (info.abfd); - if (osabi == GDB_OSABI_UNKNOWN) + switch (bfd_get_flavour (info.abfd)) { - switch (bfd_get_flavour (info.abfd)) - { - case bfd_target_aout_flavour: - /* Assume it's an old APCS-style ABI. */ - osabi = GDB_OSABI_ARM_APCS; - break; + case bfd_target_aout_flavour: + /* Assume it's an old APCS-style ABI. */ + info.osabi = GDB_OSABI_ARM_APCS; + break; - case bfd_target_coff_flavour: - /* Assume it's an old APCS-style ABI. */ - /* XXX WinCE? */ - osabi = GDB_OSABI_ARM_APCS; - break; + case bfd_target_coff_flavour: + /* Assume it's an old APCS-style ABI. */ + /* XXX WinCE? */ + info.osabi = GDB_OSABI_ARM_APCS; + break; - default: - /* Leave it as "unknown". */ - } + default: + /* Leave it as "unknown". */ + break; } } - /* Find a candidate among extant architectures. */ - for (arches = gdbarch_list_lookup_by_info (arches, &info); - arches != NULL; - arches = gdbarch_list_lookup_by_info (arches->next, &info)) - { - /* Make sure the ABI selection matches. */ - tdep = gdbarch_tdep (arches->gdbarch); - if (tdep && tdep->osabi == osabi) - return arches->gdbarch; - } + /* If there is already a candidate, use it. */ + arches = gdbarch_list_lookup_by_info (arches, &info); + if (arches != NULL) + return arches->gdbarch; tdep = xmalloc (sizeof (struct gdbarch_tdep)); gdbarch = gdbarch_alloc (&info, tdep); - /* NOTE: cagney/2002-12-06: This can be deleted when this arch is - ready to unwind the PC first (see frame.c:get_prev_frame()). */ - set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default); - - tdep->osabi = osabi; - - /* This is the way it has always defaulted. */ - tdep->fp_model = ARM_FLOAT_FPA; + /* We used to default to FPA for generic ARM, but almost nobody uses that + now, and we now provide a way for the user to force the model. So + default to the most useful variant. */ + tdep->fp_model = ARM_FLOAT_SOFT_FPA; /* Breakpoints. */ switch (info.byte_order) @@ -2788,41 +2854,21 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->lowest_pc = 0x20; tdep->jb_pc = -1; /* Longjump support not enabled by default. */ - set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1); - set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0); - - set_gdbarch_call_dummy_p (gdbarch, 1); - set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0); - - set_gdbarch_call_dummy_words (gdbarch, arm_call_dummy_words); - set_gdbarch_sizeof_call_dummy_words (gdbarch, 0); - set_gdbarch_call_dummy_start_offset (gdbarch, 0); - set_gdbarch_call_dummy_length (gdbarch, 0); - - set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy); + set_gdbarch_deprecated_call_dummy_words (gdbarch, arm_call_dummy_words); + set_gdbarch_deprecated_sizeof_call_dummy_words (gdbarch, 0); - set_gdbarch_call_dummy_address (gdbarch, entry_point_address); - set_gdbarch_push_return_address (gdbarch, arm_push_return_address); - - set_gdbarch_push_arguments (gdbarch, arm_push_arguments); - set_gdbarch_coerce_float_to_double (gdbarch, - standard_coerce_float_to_double); + set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call); /* Frame handling. */ - set_gdbarch_frame_chain_valid (gdbarch, arm_frame_chain_valid); - set_gdbarch_init_extra_frame_info (gdbarch, arm_init_extra_frame_info); - set_gdbarch_read_fp (gdbarch, arm_read_fp); - set_gdbarch_frame_chain (gdbarch, arm_frame_chain); + set_gdbarch_unwind_dummy_id (gdbarch, arm_unwind_dummy_id); + set_gdbarch_unwind_pc (gdbarch, arm_unwind_pc); + set_gdbarch_unwind_sp (gdbarch, arm_unwind_sp); + set_gdbarch_frameless_function_invocation (gdbarch, arm_frameless_function_invocation); - set_gdbarch_frame_saved_pc (gdbarch, arm_frame_saved_pc); - set_gdbarch_frame_args_address (gdbarch, arm_frame_args_address); - set_gdbarch_frame_locals_address (gdbarch, arm_frame_locals_address); - set_gdbarch_frame_num_args (gdbarch, arm_frame_num_args); set_gdbarch_frame_args_skip (gdbarch, 0); - set_gdbarch_frame_init_saved_regs (gdbarch, arm_frame_init_saved_regs); - set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame); - set_gdbarch_pop_frame (gdbarch, arm_pop_frame); + + frame_base_set_default (gdbarch, &arm_normal_base); /* Address manipulation. */ set_gdbarch_smash_text_address (gdbarch, arm_smash_text_address); @@ -2835,7 +2881,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue); /* Get the PC when a frame might not be available. */ - set_gdbarch_saved_pc_after_call (gdbarch, arm_saved_pc_after_call); + set_gdbarch_deprecated_saved_pc_after_call (gdbarch, arm_saved_pc_after_call); /* The stack grows downward. */ set_gdbarch_inner_than (gdbarch, core_addr_lessthan); @@ -2846,32 +2892,31 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Information about registers, etc. */ set_gdbarch_print_float_info (gdbarch, arm_print_float_info); - set_gdbarch_fp_regnum (gdbarch, ARM_FP_REGNUM); /* ??? */ + set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM); /* ??? */ set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM); set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM); - set_gdbarch_register_byte (gdbarch, arm_register_byte); - set_gdbarch_register_bytes (gdbarch, - (NUM_GREGS * INT_REGISTER_RAW_SIZE - + NUM_FREGS * FP_REGISTER_RAW_SIZE - + NUM_SREGS * STATUS_REGISTER_SIZE)); + set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte); + set_gdbarch_deprecated_register_bytes (gdbarch, + (NUM_GREGS * INT_REGISTER_RAW_SIZE + + NUM_FREGS * FP_REGISTER_RAW_SIZE + + NUM_SREGS * STATUS_REGISTER_SIZE)); set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS); - set_gdbarch_register_raw_size (gdbarch, arm_register_raw_size); - set_gdbarch_register_virtual_size (gdbarch, arm_register_virtual_size); - set_gdbarch_max_register_raw_size (gdbarch, FP_REGISTER_RAW_SIZE); - set_gdbarch_max_register_virtual_size (gdbarch, FP_REGISTER_VIRTUAL_SIZE); - set_gdbarch_register_virtual_type (gdbarch, arm_register_type); + set_gdbarch_deprecated_register_raw_size (gdbarch, arm_register_raw_size); + set_gdbarch_deprecated_register_virtual_size (gdbarch, arm_register_virtual_size); + set_gdbarch_deprecated_max_register_raw_size (gdbarch, FP_REGISTER_RAW_SIZE); + set_gdbarch_deprecated_max_register_virtual_size (gdbarch, FP_REGISTER_VIRTUAL_SIZE); + set_gdbarch_deprecated_register_virtual_type (gdbarch, arm_register_type); /* Internal <-> external register number maps. */ set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno); /* Integer registers are 4 bytes. */ - set_gdbarch_register_size (gdbarch, 4); + set_gdbarch_deprecated_register_size (gdbarch, 4); set_gdbarch_register_name (gdbarch, arm_register_name); /* Returning results. */ - set_gdbarch_deprecated_extract_return_value (gdbarch, arm_extract_return_value); - set_gdbarch_deprecated_store_return_value (gdbarch, arm_store_return_value); - set_gdbarch_store_struct_return (gdbarch, arm_store_struct_return); + set_gdbarch_extract_return_value (gdbarch, arm_extract_return_value); + set_gdbarch_store_return_value (gdbarch, arm_store_return_value); set_gdbarch_use_struct_convention (gdbarch, arm_use_struct_convention); set_gdbarch_extract_struct_value_address (gdbarch, arm_extract_struct_value_address); @@ -2880,13 +2925,20 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* XXX For an RDI target we should ask the target if it can single-step. */ set_gdbarch_software_single_step (gdbarch, arm_software_single_step); + /* Disassembly. */ + set_gdbarch_print_insn (gdbarch, gdb_print_insn_arm); + /* Minsymbol frobbing. */ set_gdbarch_elf_make_msymbol_special (gdbarch, arm_elf_make_msymbol_special); set_gdbarch_coff_make_msymbol_special (gdbarch, arm_coff_make_msymbol_special); /* Hook in the ABI-specific overrides, if they have been registered. */ - gdbarch_init_osabi (info, gdbarch, osabi); + gdbarch_init_osabi (info, gdbarch); + + /* Add some default predicates. */ + frame_unwind_append_sniffer (gdbarch, arm_sigtramp_unwind_sniffer); + frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer); /* Now we have tuned the configuration, set a few final things, based on what the OS ABI has told us. */ @@ -2906,20 +2958,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) case BFD_ENDIAN_LITTLE: set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little); - if (tdep->fp_model == ARM_FLOAT_VFP - || tdep->fp_model == ARM_FLOAT_SOFT_VFP) - { - set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little); - set_gdbarch_long_double_format (gdbarch, - &floatformat_ieee_double_little); - } - else - { - set_gdbarch_double_format - (gdbarch, &floatformat_ieee_double_littlebyte_bigword); - set_gdbarch_long_double_format - (gdbarch, &floatformat_ieee_double_littlebyte_bigword); - } + arm_set_fp (gdbarch); break; default: @@ -2927,20 +2966,6 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) "arm_gdbarch_init: bad byte order for float format"); } - /* We can't use SIZEOF_FRAME_SAVED_REGS here, since that still - references the old architecture vector, not the one we are - building here. */ - if (prologue_cache.saved_regs != NULL) - xfree (prologue_cache.saved_regs); - - /* We can't use NUM_REGS nor NUM_PSEUDO_REGS here, since that still - references the old architecture vector, not the one we are - building here. */ - prologue_cache.saved_regs = (CORE_ADDR *) - xcalloc (1, (sizeof (CORE_ADDR) - * (gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch)))); - return gdbarch; } @@ -2952,9 +2977,6 @@ arm_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file) if (tdep == NULL) return; - fprintf_unfiltered (file, "arm_dump_tdep: OS ABI = %s\n", - gdbarch_osabi_name (tdep->osabi)); - fprintf_unfiltered (file, "arm_dump_tdep: Lowest pc = 0x%lx", (unsigned long) tdep->lowest_pc); } @@ -2980,20 +3002,21 @@ arm_init_abi_apcs (struct gdbarch_info info, /* Place-holder. */ } +extern initialize_file_ftype _initialize_arm_tdep; /* -Wmissing-prototypes */ + void _initialize_arm_tdep (void) { struct ui_file *stb; long length; - struct cmd_list_element *new_cmd; + struct cmd_list_element *new_set, *new_show; const char *setname; const char *setdesc; const char **regnames; int numregs, i, j; static char *helptext; - if (GDB_MULTI_ARCH) - gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep); + gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep); /* Register an ELF OS ABI sniffer for ARM binaries. */ gdbarch_register_osabi_sniffer (bfd_arch_arm, @@ -3001,38 +3024,46 @@ _initialize_arm_tdep (void) arm_elf_osabi_sniffer); /* Register some ABI variants for embedded systems. */ - gdbarch_register_osabi (bfd_arch_arm, GDB_OSABI_ARM_EABI_V1, + gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_EABI_V1, arm_init_abi_eabi_v1); - gdbarch_register_osabi (bfd_arch_arm, GDB_OSABI_ARM_EABI_V2, + gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_EABI_V2, arm_init_abi_eabi_v2); - gdbarch_register_osabi (bfd_arch_arm, GDB_OSABI_ARM_APCS, + gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_APCS, arm_init_abi_apcs); - tm_print_insn = gdb_print_insn_arm; - /* Get the number of possible sets of register names defined in opcodes. */ - num_flavor_options = get_arm_regname_num_options (); + num_disassembly_options = get_arm_regname_num_options (); + + /* Add root prefix command for all "set arm"/"show arm" commands. */ + add_prefix_cmd ("arm", no_class, set_arm_command, + "Various ARM-specific commands.", + &setarmcmdlist, "set arm ", 0, &setlist); + + add_prefix_cmd ("arm", no_class, show_arm_command, + "Various ARM-specific commands.", + &showarmcmdlist, "show arm ", 0, &showlist); /* Sync the opcode insn printer with our register viewer. */ parse_arm_disassembler_option ("reg-names-std"); /* Begin creating the help text. */ stb = mem_fileopen (); - fprintf_unfiltered (stb, "Set the disassembly flavor.\n\ -The valid values are:\n"); + fprintf_unfiltered (stb, "Set the disassembly style.\n" + "The valid values are:\n"); /* Initialize the array that will be passed to add_set_enum_cmd(). */ - valid_flavors = xmalloc ((num_flavor_options + 1) * sizeof (char *)); - for (i = 0; i < num_flavor_options; i++) + valid_disassembly_styles + = xmalloc ((num_disassembly_options + 1) * sizeof (char *)); + for (i = 0; i < num_disassembly_options; i++) { numregs = get_arm_regnames (i, &setname, &setdesc, ®names); - valid_flavors[i] = setname; + valid_disassembly_styles[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 = setname; + disassembly_style = setname; current_option = i; for (j = 0; j < numregs; j++) arm_register_names[j] = (char *) regnames[j]; @@ -3040,41 +3071,73 @@ The valid values are:\n"); } } /* Mark the end of valid options. */ - valid_flavors[num_flavor_options] = NULL; + valid_disassembly_styles[num_disassembly_options] = NULL; /* Finish the creation of the help text. */ fprintf_unfiltered (stb, "The default is \"std\"."); helptext = ui_file_xstrdup (stb, &length); ui_file_delete (stb); - /* Add the disassembly-flavor command. */ - new_cmd = add_set_enum_cmd ("disassembly-flavor", no_class, - valid_flavors, - &disassembly_flavor, + /* Add the deprecated disassembly-flavor command. */ + new_set = add_set_enum_cmd ("disassembly-flavor", no_class, + valid_disassembly_styles, + &disassembly_style, helptext, &setlist); - set_cmd_sfunc (new_cmd, set_disassembly_flavor_sfunc); - add_show_from_set (new_cmd, &showlist); - - /* ??? Maybe this should be a boolean. */ - add_show_from_set (add_set_cmd ("apcs32", no_class, - var_zinteger, (char *) &arm_apcs_32, - "Set usage of ARM 32-bit mode.\n", &setlist), - &showlist); + set_cmd_sfunc (new_set, set_disassembly_style_sfunc); + deprecate_cmd (new_set, "set arm disassembly"); + deprecate_cmd (add_show_from_set (new_set, &showlist), + "show arm disassembly"); + + /* And now add the new interface. */ + new_set = add_set_enum_cmd ("disassembler", no_class, + valid_disassembly_styles, &disassembly_style, + helptext, &setarmcmdlist); + + set_cmd_sfunc (new_set, set_disassembly_style_sfunc); + add_show_from_set (new_set, &showarmcmdlist); + + add_setshow_cmd_full ("apcs32", no_class, + var_boolean, (char *) &arm_apcs_32, + "Set usage of ARM 32-bit mode.", + "Show usage of ARM 32-bit mode.", + NULL, NULL, + &setlist, &showlist, &new_set, &new_show); + deprecate_cmd (new_set, "set arm apcs32"); + deprecate_cmd (new_show, "show arm apcs32"); + + add_setshow_boolean_cmd ("apcs32", no_class, &arm_apcs_32, + "Set usage of ARM 32-bit mode. " + "When off, a 26-bit PC will be used.", + "Show usage of ARM 32-bit mode. " + "When off, a 26-bit PC will be used.", + NULL, NULL, + &setarmcmdlist, &showarmcmdlist); + + /* Add a command to allow the user to force the FPU model. */ + new_set = add_set_enum_cmd + ("fpu", no_class, fp_model_strings, ¤t_fp_model, + "Set the floating point type.\n" + "auto - Determine the FP typefrom the OS-ABI.\n" + "softfpa - Software FP, mixed-endian doubles on little-endian ARMs.\n" + "fpa - FPA co-processor (GCC compiled).\n" + "softvfp - Software FP with pure-endian doubles.\n" + "vfp - VFP co-processor.", + &setarmcmdlist); + set_cmd_sfunc (new_set, set_fp_model_sfunc); + set_cmd_sfunc (add_show_from_set (new_set, &showarmcmdlist), show_fp_model); /* Add the deprecated "othernames" command. */ - - add_com ("othernames", class_obscure, arm_othernames, - "Switch to the next set of register names."); - - /* Fill in the prologue_cache fields. */ - prologue_cache.saved_regs = NULL; - prologue_cache.extra_info = (struct frame_extra_info *) - xcalloc (1, sizeof (struct frame_extra_info)); + deprecate_cmd (add_com ("othernames", class_obscure, arm_othernames, + "Switch to the next set of register names."), + "set arm disassembly"); /* Debugging flag. */ - add_show_from_set (add_set_cmd ("arm", class_maintenance, var_zinteger, - &arm_debug, "Set arm debugging.\n\ -When non-zero, arm specific debugging is enabled.", &setdebuglist), - &showdebuglist); + add_setshow_boolean_cmd ("arm", class_maintenance, &arm_debug, + "Set ARM debugging. " + "When on, arm-specific debugging is enabled.", + "Show ARM debugging. " + "When on, arm-specific debugging is enabled.", + NULL, NULL, + &setdebuglist, &showdebuglist); }