diff options
Diffstat (limited to 'gdb/arc-tdep.c')
-rw-r--r-- | gdb/arc-tdep.c | 3840 |
1 files changed, 2216 insertions, 1624 deletions
diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c index 8b54257..f912f89 100644 --- a/gdb/arc-tdep.c +++ b/gdb/arc-tdep.c @@ -1,1999 +1,2591 @@ -/* Target dependent code for ARC700, for GDB, the GNU debugger. +/* Target dependent code for ARC processor family, for GDB, the GNU debugger. - Copyright 2005 Free Software Foundation, Inc. + Copyright 2005, 2008, 2009 Free Software Foundation, Inc. Contributed by Codito Technologies Pvt. Ltd. (www.codito.com) - Authors: - Soam Vasani <soam.vasani@codito.com> - Ramana Radhakrishnan <ramana.radhakrishnan@codito.com> + Authors: + Soam Vasani <soam.vasani@codito.com> + Ramana Radhakrishnan <ramana.radhakrishnan@codito.com> + Richard Stuckey <richard.stuckey@arc.com> This file is part of GDB. - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/******************************************************************************/ +/* */ +/* Outline: */ +/* This module provides support for the ARC processor family's target */ +/* dependencies. In particular, it has knowledge of the processor ABI. */ +/* */ +/* See */ +/* ARCompact Instruction Set Architecture */ +/* Programmer's Reference */ +/* (5115-018) */ +/* */ +/* for a description of ARC processor architecture, and */ +/* */ +/* System V ABI Supplement */ +/* 4093-004 */ +/* */ +/* for a complete definition of the ABI. */ +/* */ +/* */ +/* Stack Frame Layout: */ +/* This shows the layout of the stack frame for the general case of a */ +/* function call; a given function might not have a variable number of */ +/* arguments or local variables, or might not save any registers, so it */ +/* would not have the corresponding frame areas. Additionally, a leaf */ +/* function (i.e. one which calls no other functions) does not need to */ +/* save the contents of the BLINK register (which holds its return */ +/* address), and a function might not have a frame pointer. */ +/* */ +/* N.B. the stack grows downward, so SP points below FP in memory; SP */ +/* always points to the last used word on the stack, not the first */ +/* one. */ +/* */ +/* | | | */ +/* | arg word N | | caller's */ +/* | : | | frame */ +/* | arg word 10 | | */ +/* | arg word 9 | | */ +/* old SP ---> |-----------------------| -- */ +/* | var arg word 8 | | */ +/* | : | | */ +/* | var arg word P+1 | | */ +/* |-----------------------| | */ +/* | | | */ +/* | callee-saved | | */ +/* | registers | | */ +/* | | | */ +/* |-----------------------| | */ +/* | saved blink (*) | | */ +/* |-----------------------| | callee's */ +/* | saved FP | | frame */ +/* FP ---> |-----------------------| | */ +/* | | | */ +/* | local | | */ +/* | variables | | */ +/* | | | */ +/* | register | | */ +/* | spill area | | */ +/* | | | */ +/* | outgoing args | | */ +/* | | | */ +/* SP ---> |-----------------------| -- */ +/* | | */ +/* | unused | */ +/* | | */ +/* | */ +/* | */ +/* V */ +/* downwards */ +/* */ +/* The list of arguments to be passed to a function is considered to be a */ +/* sequence of N words (as though all the parameters were stored in order */ +/* in memory with each parameter occupying an integral number of words). */ +/* Words 1 .. 8 are passed in registers 0 .. 7; if the function has more */ +/* than 8 words of arguments then words 9 .. N are passed on the stack in */ +/* the caller's frame. */ +/* */ +/* If the function has a variable number of arguments, e.g. it has a form */ +/* such as */ +/* function(p1, p2, ...); */ +/* */ +/* and P words are required to hold the values of the named parameters */ +/* (which are passed in registers 0 .. P-1), then the remaining 8 - P */ +/* words passed in registers P .. 7 are spilled into the top of the frame */ +/* so that the anonymous parameter words occupy a continous region. */ +/* */ +/* (*) if saved. */ +/* */ +/* Usage: */ +/* The module exports a function _initialize_arc_tdep: the call to this */ +/* function is generated by the gdb build mechanism, so this function */ +/* should not be explicitly called. */ +/* */ +/* The operations provided by this module are registered with gdb during */ +/* initialization; gdb then calls them via function pointers, rather than */ +/* by name (this allows gdb to handle multiple target architectures): */ +/* */ +/* set_gdbarch_XXX (gdbarch, <function>); */ +/* */ +/* */ +/* Build Configuration: */ +/* The ARC gdb may be built in two different configurations, according to */ +/* the nature of the target that it is to debug: */ +/* */ +/* 1) arc-elf32: */ +/* for debugging 'bare-metal' builds of user code (i.e. built with */ +/* newlib) */ +/* */ +/* ARC-specific modules: */ +/* arc-tdep */ +/* arc-elf32-tdep */ +/* arc-xiss */ +/* arc-jtag */ +/* arc-jtag-ops */ +/* arc-jtag-actionpoints */ +/* arc-gpio */ +/* arc-remote-fileio */ +/* arc-registers */ +/* arc-architecture */ +/* arc-board */ +/* arc-arguments */ +/* arc-memory */ +/* arc-inst-tracing */ +/* */ +/* 2) arc-linux-uclibc: */ +/* for deugging user mode Linux applications, via communication to */ +/* the remote gdbserver process, running on Linux for ARC700 */ +/* */ +/* ARC-specific modules: */ +/* arc-tdep */ +/* arc-linux-tdep */ +/* */ +/* This module provides operations which are common to both; operations */ +/* which are specific to one, or which have different variants in each */ +/* configuration, are provided by the other modules. */ +/* */ +/* */ +/* Debug Targets: */ +/* The ARC gdb supports a number of debug targets. These are: */ +/* */ +/* arc-elf32-gdb */ +/* built-in simulator 'target sim' */ +/* ARCangel 4 h/w emulator 'target arcjtag' */ +/* dynamically loaded xISS simulator 'target arcxiss' */ +/* separately executing xISS simulator 'target remote' */ +/* */ +/* arc-linux-uclibc-gdb */ +/* gdbserver running on ARC Linux 'target remote' */ +/* */ +/* It should, in theory, be possible for either debugger to connect to */ +/* any remote target which supports the gdb Remote Serial Protocol. */ +/* However, any such target MUST agree with the debugger on the register */ +/* numbering scheme that is used, as this controls the order of register */ +/* contents held in the RSP 'G' (set all registers) packet and the 'g' */ +/* (get all registers) response packet, as well as the register numbers */ +/* used in the 'P' (set one register) and 'p' (get one register) packets, */ +/* and in the 'T' stop reply packet. The schemes used by each debugger */ +/* are defined in the arc-elf32-tdep and arc-linux-tdep modules. */ +/* */ +/******************************************************************************/ + +/* system header files */ #include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <byteswap.h> +/* gdb header files */ #include "defs.h" +#include "config.h" #include "arch-utils.h" #include "dis-asm.h" -#include "gdbtypes.h" #include "frame.h" #include "frame-unwind.h" -#include "target.h" -#include "breakpoint.h" #include "inferior.h" #include "regcache.h" #include "reggroups.h" #include "trad-frame.h" #include "dwarf2-frame.h" -#include "gdbtypes.h" -#include "gdb_assert.h" #include "gdbcore.h" #include "observer.h" #include "osabi.h" +#include "gdbcmd.h" +#include "block.h" +#include "dictionary.h" +#include "language.h" +#include "demangle.h" +#include "objfiles.h" +#include "gdb_assert.h" -#include "opcode/arc.h" - -#include "arc-tdep.h" - +/* ARC header files */ -//#define ARC_DEBUG 1 +/* N.B. one and only one of ARC_ELF32_TARGET and ARC_LINUX_TARGET must be defined! */ -#if ARC_DEBUG -# define ENTERMSG printf ("--- entered %s:%s()\n", __FILE__, __FUNCTION__) -# define ENTERARGS(fmt, args...) printf ("--- entered %s:%s(" fmt ")\n", __FILE__, __FUNCTION__, args) -# define LEAVEMSG printf ("--- exited %s:%s()\n", __FILE__, __FUNCTION__) +#ifdef ARC_ELF32_TARGET +#ifdef ARC_LINUX_TARGET +#error ARC build is not correctly configured (both flags set) #else -# define ENTERMSG -# define ENTERARGS(fmt, args...) -# define LEAVEMSG +#include "config/arc/tm-embed.h" +#endif +#else +#ifdef ARC_LINUX_TARGET +#include "config/arc/tm-linux.h" +#else +#error ARC build is not correctly configured (no flag set) +#endif #endif -#define ARC_STATUS32_A1 0x8 -#define ARC_STATUS32_A2 0x10 -#define ARC_STATUS32_AE 0x20 -#define ARC_STATUS32_L 0x100 +#include "opcode/arc.h" +#include "opcodes/arc-dis.h" +#include "opcodes/arc-ext.h" +#include "opcodes/arcompact-dis.h" +#include "arc-support.h" +#include "arc-tdep.h" -static CORE_ADDR arc_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp); -/* The frame unwind cache for the ARC - */ +/* -------------------------------------------------------------------------- */ +/* local types */ +/* -------------------------------------------------------------------------- */ -struct arc_unwind_cache +typedef struct { - /* blink offset in stack */ - int blink_offset ; + const char *name; + CORE_ADDR address; + Boolean is_argument; + Boolean is_callee; + Boolean is_array; + unsigned int size; + unsigned int element_size; +} LocalVariable; - /* Caller's PC */ - CORE_ADDR prev_pc; - - /* 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 */ - CORE_ADDR frame_base; - /* Frame size */ - int framesize; - - /* offset of sp from the stack frame base */ - LONGEST sp_offset; - /* offset of fp from the stack frame base */ - LONGEST fp_offset; - /* Is this a leaf function */ - int is_leaf ; - /* Is there a frame pointer */ - int uses_fp; - - - /* Offsets for each register in the stack frame */ - struct trad_frame_saved_reg *saved_regs; -}; +/* The frame unwind cache for the ARC. */ +typedef struct +{ + /* BLINK save location offset from previous SP (-ve value). */ + int blink_save_offset_from_prev_sp; + /* 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 (as held in FP). + N.B. this is NOT the address of the lowest word in the frame! */ + CORE_ADDR frame_base; -/* Function Prototypes */ + /* Change in SP from previous SP (-ve value) - this is computed by scanning + the prologue of the function: initially 0, it is updated for each + instruction which changes SP (either explicitly by a subtraction from SP + or implicitly by a push operation), so at each point in the prologue it + gives the difference between the previous SP (i.e. before the function + was called) and the current SP at that point; at the end of the prologue + it holds the total change in SP, i.e. the size of the frame. */ + LONGEST delta_sp; -static CORE_ADDR arc_unwind_sp (struct gdbarch *gdbarch, - struct frame_info *next_frame); + /* Offset of old stack pointer from frame base (+ve value). */ + LONGEST old_sp_offset_from_fp; -static CORE_ADDR arc_unwind_pc (struct gdbarch *gdbarch, - struct frame_info *next_frame); + /* Is this a leaf function? */ + Boolean is_leaf; + /* Is there a frame pointer? */ + Boolean uses_fp; -static struct arc_unwind_cache * arc_frame_unwind_cache (struct frame_info *next_frame, - void ** this_prologue); + /* Offsets for each register in the stack frame. */ + struct trad_frame_saved_reg *saved_regs; + unsigned int saved_regs_mask; +} UnwindCache; -static CORE_ADDR arc_scan_prologue (CORE_ADDR pc, - struct frame_info *next_frame, - struct arc_unwind_cache *info); +/* -------------------------------------------------------------------------- */ +/* local data */ +/* -------------------------------------------------------------------------- */ -static int arc_binutils_reg_to_regnum (int reg); +#define DEBUG_COMMAND "arc-debug" +#define SHOW_FRAME_COMMAND "arc-show-frame" +#define SHOW_FRAME_COMMAND_USAGE "Usage: " SHOW_FRAME_COMMAND " [ <FRAME> ]\n" -extern struct arcDisState arcAnalyzeInstr ( bfd_vma address,disassemble_info* info ); -extern struct arcDisState a4AnalyzeInstr ( bfd_vma address,disassemble_info* info ); +#define NEW_LINE _("\n") -/* defined in opcodes, but there's no header file with this prototype... */ -disassembler_ftype arcompact_get_disassembler (void *); -/* Standard register type for the ARC platform . - * It would be builtin_type_uint32 until - * we consider the DSP extensions - */ +/* -------------------------------------------------------------------------- */ +/* externally visible data */ +/* -------------------------------------------------------------------------- */ -static struct type * -arc_register_type (struct gdbarch *gdbarch, int regnum) -{ - return builtin_type_uint32; -} +/* Global debug flag. */ +Boolean arc_debug_target; -void printFrameInfo(struct arc_unwind_cache * info) -{ -#ifdef ARC_DEBUG - printf("-------------------\n"); - printf("%lx \n",info ); - printf("prev_sp = %lx \n",info->prev_sp); - printf("prev_pc = %lx \n",info->prev_pc); - printf("frame_base is %lx \n",info->frame_base); - printf("framesize is %lx \n",info->framesize); - printf("Blink offset %lx \n",info->blink_offset); - printf("sp_offset = %lx \n",info->sp_offset ); - printf("fp_offset is %lx \n",info->fp_offset); - printf("is_leaf = %d, uses_fp=%d",info->is_leaf, info->uses_fp); -#endif -} +/* -------------------------------------------------------------------------- */ +/* local macros */ +/* -------------------------------------------------------------------------- */ -/* Print the instruction state returned - by the disassembler . Used for internal - debugging only -*/ +#define WORD_ALIGNED(addr) ((addr) & ~(BYTES_IN_WORD - 1)) +#define WORDS_OCCUPIED(bytes) (((bytes) + BYTES_IN_WORD - 1) / BYTES_IN_WORD) +#define ROUND_UP_TO_WORDS(bytes) (WORDS_OCCUPIED(bytes) * BYTES_IN_WORD) -void printInsnState(struct arcDisState state) -{ -#ifdef ARC_DEBUG - printf("---------------------------------\n"); - printf("Instruction Length %d\n", state.instructionLen); - printf("Opcode [0x%x] : Cond [%x]\n", state._opcode, state._cond); - printf("Words 1 [%lx] : 2 [%lx]\n", state.words[0], state.words[1]); - printf("ea present [%x] : memload [%x]\n", state._ea_present, state._mem_load); - printf("Load length [%d]:\n", state._load_len); - printf("Address writeback [%d]\n", state._addrWriteBack); - printf("ea reg1 is [%x] offset [%x] \n", state.ea_reg1, state._offset); - printf("ea reg2 is [%x] \n", state.ea_reg2); - printf("operands buffer is %s \n", state.operandBuffer); - printf("SourceType is %d \n",state.sourceType); - printf("Flow is %d\n",state.flow); - printf("Branch is %d,'%c'\n",state.isBranch, state.isBranch); -#endif -} -/* Scan the prologue and update the - * corresponding frame cache for the frame unwinder for unwinding - * frames without debug info . In such a situation GDB attempts to - * parse the prologue for this purpose . This currently would attempt - * to parse the prologue generated by our gcc 2.95 .(We should support - * Metaware generated binaries at some suitable point of time ) - * This function is called with the pc where gdb stopped , the next_frame - * to be filled in (if need be?) and the existing cached info . - - * scan_prologue is called by our unwinder as well - * as from skip_prologue in the case that it cannot detect - * the end of the prologue. next_frame is set to NULL if we are called from - * arc_skip_prologue in an attempt to discover the end of the prologue. In - * such a case we don't fill the frame info that is passed to us :-) - - * Todos. - * 1. Support 32 bit normal frames generated by GCC 2.95 . - * 2. Support 16 and 32 bit mixed frames generated by GCC 2.95 - * 3. Support 32 bit normal variadic function frames by GCC 2.95 - * 4. Support 32 bit normal frames from GCC 3.4.x with variadic args - * 5. Support 16 and 32 bit normal frames from GCC 3.4.x with variadic args - * 6. Support 16 and 32 bit mixed frames generated by GCC 3.4.x - * 7. Support Metaware generated prologues .( The difference is - * in the use of thunks to identify the saving and restoring of - * callee saves :-) May have to do some hackery even in next_pc. - * since the call is going to create its own set of problems - * with our stack setup :-( - * We attempt to use the disassembler interface from the opcodes - * library to do our disassembling . - - * The usual 32 bit normal - * gcc -O0 prologue looks like this. - - * Complete Prologue for all GCC frames (Cases #1 to #6 in Todos above) - - * sub sp, sp, limm ; space for variadic arguments. - * st.a blink, [sp,-4] ; push blink (if not a leaf function) - * sub sp, sp , limm ; (optional space creation for callee saves ) - * st r13, [sp] ; pushes of all callee saves. - * st r14, [sp,4] ; pushes of more callee saves. - * XXXX - * st.a fp , [sp,-4] ; push fp (if fp has to be saved ) - * mov fp , sp ; Set the current frame up correctly - * sub sp , sp , #immediate ; Create space for local vars on the stack. - */ +/* Macros to be used with disassembling the prologue and update the frame info. + The *FI macros are to update the frame info and the ACT macros are to + actually do the action on a corresponding match. */ +#define IS_INSTRUCTION(insn_name, search_string) !strcmp(insn_name, search_string) +#define CHECK_OPERAND_STRING_AND_ACT(target_check, search_string, action) \ + if (strstr(target_check, search_string) == target_check) \ + { \ + action; \ + return TRUE; \ + } -/* Macros to be used with disassembling the prologue - * and update the frame info.The *FI macros are to update - * the frame info and the ACT macros are to actually do the - * action on a corresponding match. - * -*/ -#define CHECKOPDSTRING(targetcheck,searchstring) \ - if(strstr(targetcheck,searchstring) == targetcheck) \ - {continue;} - -#define CHECKOPDSTRINGANDACT(targetcheck,searchstring,action) \ - if(strstr(targetcheck,searchstring) == targetcheck) \ - {\ - action;\ - continue;} - - -/* The frame info changes by changing the decrementing - the sp_offset and setting the leaf function to be NIL; - Also the offset of the blink register from the previous - value of sp is calculated. Finally this can be updated - as - info->blink_offset = info-> prev_sp + info->blink_offset ; - Also the addition below is coz the offsets are usually negative -*/ -#define PUSHBLINKACT do { \ - if(info) \ - { \ - info->sp_offset += current_instr._offset; \ - info->blink_offset = info->sp_offset ; \ - info->is_leaf = 0;\ - }}while(0); - +/* The frame info changes by changing the decrementing the delta_sp and setting + the leaf function flag to be False (if this function prologue is saving blink + then it must be going to call another function - so it can not be a leaf!); + also the offset of the blink register save location from the previous value + of sp is recorded. This will eventually used to compute the address of the + save location: -#define ISPUSHBLINK(state) CHECKOPDSTRING(state.operandBuffer,"blink") -#define ISPUSHBLINKFI(state) CHECKOPDSTRINGANDACT(state.operandBuffer,"blink",PUSHBLINKACT) + <blink saved address> = <prev sp> + <blink offset from prev sp> + The addition (+=) below is because the sp offset and the instruction offset + are negative - so incrementing the sp offset by the instruction offset is + actually making the sp offset more negative, correctly reflecting that SP + is moving further down the downwards-growing stack. */ -#define PUSHFPACT do { \ - if(info) \ - { \ - info->sp_offset += current_instr._offset ; \ - info->fp_offset = -info->sp_offset; \ - }}while(0); - -#define ISPUSHFP(state) CHECKOPDSTRING(state.operandBuffer,"fp") -#define ISPUSHFPFI(state) CHECKOPDSTRINGANDACT(state.operandBuffer,"fp",PUSHFPACT) -#define ISINSTRUCTION(insnname,searchstring) !strcmp(insnname,searchstring) +#define PUSH_BLINK(offset) \ + { \ + info->delta_sp += offset; \ + info->blink_save_offset_from_prev_sp = (int) info->delta_sp; \ + info->is_leaf = FALSE; \ + } +#define PUSH_BLINK_ACT \ + do { \ + if (info) PUSH_BLINK(instr->_offset) \ + } while (0); -#define UPDATEFPACT do {\ - if(info) {\ - info->uses_fp = 1;\ - }}while(0); +#define IS_PUSH_BLINK_FI(state) CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "blink", PUSH_BLINK_ACT) +/* At the point that that FP is pushed onto the stack (so saving the dynamic + link chain pointer to the previous frame), at the address that will be the + base of the new frame, we know the offset of SP from the previous SP - so the + offset of the old SP from the new frame base is known (the -ve delta_sp is + negated to give the +ve old_sp_offset_from_fp). */ +#define PUSH_FP_ACT do { \ + if (info) \ + { \ + info->delta_sp += instr->_offset; \ + info->old_sp_offset_from_fp = -info->delta_sp; \ + }} while (0); -#define ISUPDATEFPFI(state) \ - if(ISINSTRUCTION(state.instrBuffer,"mov")) \ -{ \ - CHECKOPDSTRINGANDACT(state.operandBuffer,"fp,sp",UPDATEFPACT); \ -} +#define IS_PUSH_FP_FI(state) CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "fp", PUSH_FP_ACT) +#define UPDATE_FP_ACT do { \ + if (info) \ + info->uses_fp = TRUE; \ + } while (0); -#define ISUPDATEFP(state) \ - if(ISINSTRUCTION(state.instrBuffer,"mov")) \ -{ \ - CHECKOPDSTRING(state.operandBuffer,"fp,sp") \ -} +#define IS_UPDATE_FP_FI(state) \ + if (IS_INSTRUCTION(state->instrBuffer, "mov")) \ + { \ + CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "fp,sp", UPDATE_FP_ACT); \ + } +#define UPDATE_STACK_SPACE(state) do { \ + if (info) { \ + /* Eat up sp,sp. */ \ + int immediate = atoi(state->operandBuffer + 6); \ + info->delta_sp -= immediate; \ + }} while (0); -#define ISSUBSP(state) \ -if(ISINSTRUCTION(state.instrBuffer,"sub"))\ -{ \ - CHECKOPDSTRING(state.operandBuffer,"sp,sp") \ + +#define IS_SUB_SP_FI(state) \ + if (IS_INSTRUCTION(state->instrBuffer, "sub") || \ + IS_INSTRUCTION(state->instrBuffer, "sub_s")) \ + { \ + CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "sp,sp", UPDATE_STACK_SPACE(state)) \ + } + + +/* -------------------------------------------------------------------------- */ +/* forward declarations */ +/* -------------------------------------------------------------------------- */ + +static CORE_ADDR scan_prologue (CORE_ADDR entrypoint, + struct frame_info *next_frame, + UnwindCache *info); + + +/* -------------------------------------------------------------------------- */ +/* local debug functions */ +/* -------------------------------------------------------------------------- */ + +/* Print information for a frame. */ + +static void +printFrameInfo (const char *message, + UnwindCache *info, + Boolean addresses_known) +{ + unsigned int i; + + DEBUG("-------------------\n"); + DEBUG("%s (info = %p)\n", message, info); + DEBUG("prev_sp = %lx\n", (long unsigned int) info->prev_sp); + DEBUG("frame_base = %lx\n", (long unsigned int) info->frame_base); + DEBUG("blink offset = %d\n", info->blink_save_offset_from_prev_sp); + DEBUG("delta_sp = %d\n", (int) info->delta_sp); + DEBUG("old_sp_offset_from_fp = %d\n", (int) info->old_sp_offset_from_fp); + DEBUG("is_leaf = %d, uses_fp = %d\n", info->is_leaf, info->uses_fp); + + for (i = ARC_ABI_FIRST_CALLEE_SAVED_REGISTER; i < ARC_ABI_LAST_CALLEE_SAVED_REGISTER; i++) + { + if (info->saved_regs_mask & (1 << i)) + DEBUG("saved register R%02d %s 0x%lx\n", + i, + (addresses_known) ? "address" : "offset", + (unsigned long) info->saved_regs[i].addr); + } + DEBUG("-------------------\n"); } -#define UPDATESTACKSPACE(state) do { \ - if(info){ \ -/* Eat up sp,sp */ \ - int tmp = atoi(state.operandBuffer + 6); \ - info->sp_offset -= tmp; \ - }}while(0); + +static const char* +ARC_Debugger_OperandType_Image (enum ARC_Debugger_OperandType value) +{ + switch (value) + { + case ARC_LIMM : return "LIMM"; + case ARC_SHIMM : return "SHIMM"; + case ARC_REGISTER : return "REGISTER"; + case ARCOMPACT_REGISTER: return "COMPACT REGISTER"; + case ARC_UNDEFINED : return "UNDEFINED"; + } + return "?"; +} -#define ISSUBSPFI(state) \ -if(ISINSTRUCTION(state.instrBuffer,"sub") \ - || ISINSTRUCTION(state.instrBuffer,"sub_s"))\ -{ \ - CHECKOPDSTRINGANDACT(state.operandBuffer,"sp,sp",UPDATESTACKSPACE(state)) \ +/* Print the instruction state returned by the disassembler. + Used for internal debugging only. */ + +static void +printInsnState (struct arcDisState state) +{ + DEBUG("---------------------------------\n"); + DEBUG("Instruction Length %d\n", state.instructionLen); + DEBUG("Opcode [0x%x] : Cond [%x]\n", state._opcode, state._cond); + DEBUG("Words 1 [%lx] : 2 [%lx]\n", state.words[0], state.words[1]); + DEBUG("Ea present [%x] : memload [%x]\n", state._ea_present, state._mem_load); + DEBUG("Load Length [%d]:\n", state._load_len); + DEBUG("Address Writeback [%d]\n", state._addrWriteBack); + DEBUG("EA reg1 is [%x] offset [%x]\n", state.ea_reg1, state._offset); + DEBUG("EA reg2 is [%x]\n", state.ea_reg2); + DEBUG("Instr buffer is %s\n", state.instrBuffer); + DEBUG("Operand buffer is %s\n", state.operandBuffer); + DEBUG("SourceType is %s\n", ARC_Debugger_OperandType_Image(state.sourceType)); + DEBUG("Source operand is %u\n", state.source_operand.registerNum); /* All fields of the union have same type. */ + DEBUG("Flow is %d\n", state.flow); + DEBUG("Branch is %d\n", state.isBranch); + DEBUG("---------------------------------\n"); } -/*Function to scan the prologue of a A4 binary - -ARCtangent-A4 Prolog - The stack back-trace data structure is a 16-byte structure which is - used to save the return register (blink, 4 bytes), the frame pointer - register (fp, 4-bytes) and 8-bytes is reserved. - - The compiler-generated prolog code does the following: - --> Allocates space for register arguments in case of variadic function - (functions with variable argument lists) - --> Saves the return address register (blink) - --> Saves the caller's frame pointer (fp), if required, and - sets the new frame pointer to this location - --> Decrements the stack pointer to account for the new stack frame - --> Saves required non-volatile general-purpose registers into the - register save area - --> Stores the arguments above the stack back-trace data structure - - - Demo Patterns: - st blink,[sp,4] ; Saves the return address - st fp,[sp] ; Saves the callers frame pointer - mov fp,sp ; Saves - sub sp,sp,24 - -0xa 538e7e20 sub sp,sp,32 ; Space for variadic args -0x2 100e3e04 st blink,[sp,4] ; Saves the return address -0x2 100e3600 st fp,[sp] ; Saves the callers frame pointer -0xc 636e3800 mov fp,sp ; Resets stack pointer to fp -0xa 538e7e18 sub sp,sp,24 ; Decrements sp to add for new - ; stack frame -0x2 100d81fc st r0,[fp,-4] ; Stores the args -0x2 100d83f8 st r1,[fp,-8] ; ----"------- - ... -*/ +/* -------------------------------------------------------------------------- */ +/* local functions for the disassembler */ +/* -------------------------------------------------------------------------- */ -/* FIXMEA: -called from arc_skip_prologue as - skip_pc = arc_scan_prologue(pc,NULL,NULL); - Then it is supposed to return the first valid pc - after the prologue +/* Wrapper for the target_read_memory function. */ - Prologue analysis does the rest... - Currently our scan prologue does not - support getting input for the frame unwinder +static int +read_memory_for_disassembler (bfd_vma memaddr, + bfd_byte *myaddr, + unsigned int length, + struct disassemble_info *info) // unused +{ + return target_read_memory((CORE_ADDR) memaddr, (gdb_byte*) myaddr, (int) length); +} - - pc = frame_func_unwind(next_frame); - arc_scan_prologue (pc, next_frame, info); -*/ +/* This is a callback function which gets called by gdb whenever the current + object file changes. */ -#ifdef ARC4_JTAG -static CORE_ADDR -a4_scan_prologue (CORE_ADDR pc, struct frame_info *next_frame, - struct arc_unwind_cache *info) +static void +set_disassembler (struct objfile *objfile) { - /* End of prologue */ - CORE_ADDR prologue_ends_pc = pc; - int i = 0; - struct arcDisState current_instr, instr_in_delay; - int insn_length; - - /* Initializations to use the opcodes - * library . - */ - - struct disassemble_info di; - - unsigned int saved_regs_mask = 0; - /* An arbitrary length on the length of the - prologue. If next_frame is NULL this means that there was - no debug info and we are called from arc_skip_prologue - */ - /*FIXMEANOW: pc + 64 is probably the max size of the prologue*/ - CORE_ADDR final_pc = (next_frame)?frame_pc_unwind(next_frame):pc+(16*4); - - - - - if (info) + if (objfile) { - /* All functions start as leaf functions until - we identify push blink - */ - info->is_leaf = 1; + /* The ARC libopcodes wants obfd so that it can find out what CPU + extensions are defined in the file. */ + set_gdbarch_print_insn(current_gdbarch, arcompact_get_disassembler(objfile->obfd)); +// dump_ARC_extmap(); } - - - - /* Initializations to use the opcodes - * library . - */ - init_disassemble_info(&di, gdb_stderr, fprintf_unfiltered); - di.arch = gdbarch_bfd_arch_info(current_gdbarch)->arch; - di.mach = gdbarch_bfd_arch_info(current_gdbarch)->mach; - di.endian = gdbarch_byte_order(current_gdbarch); - di.read_memory_func = target_read_memory; - - - for (prologue_ends_pc= pc; - prologue_ends_pc< final_pc; - prologue_ends_pc += current_instr.instructionLen ) /*FIXMEA: This could as - well be 4 */ +} + + +/* This function is supplied to gdb as the disassembler until such time as we do + have a disassembler available. */ + +static int +dummy_disassembler (bfd_vma address, disassemble_info *info) +{ + error(_("No disassembly operation yet available (no executable file loaded)")); + return 0; +} + + +/* -------------------------------------------------------------------------- */ +/* local functions for decoding call chains */ +/* -------------------------------------------------------------------------- */ + +/* Simple utility function to create a new frame cache structure. */ + +static UnwindCache* +create_cache (struct frame_info *next_frame) +{ + UnwindCache *cache = FRAME_OBSTACK_ZALLOC (UnwindCache); + + /* Zero all fields. */ + cache->blink_save_offset_from_prev_sp = 0; + cache->prev_sp = 0; + cache->frame_base = 0; + cache->delta_sp = 0; + cache->old_sp_offset_from_fp = 0; + cache->is_leaf = FALSE; + cache->uses_fp = FALSE; + + /* Allocate space for saved register info. */ + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + + return cache; +} + + +/* Compute the previous frame's stack pointer (which is also the frame's ID's + stack address), and this frame's base pointer. */ + +static void +find_previous_stack_pointer (UnwindCache *info, + struct frame_info *next_frame) +{ + ENTERARGS("next_frame = %p", next_frame); + + /* If the frame has a frame pointer. */ + if (info->uses_fp) { - current_instr = a4AnalyzeInstr(prologue_ends_pc, &di); - printInsnState(current_instr); -#ifdef ARC_DEBUG - printf("Prologue PC: %d\n", prologue_ends_pc); - printf("Final PC: %d\n", final_pc); -#endif + ULONGEST this_base; + unsigned int i; + + /* The SP was moved to the FP. This indicates that a new frame + was created. Get THIS frame's FP value by unwinding it from + the next frame. The old contents of FP were saved in the location + at the base of this frame, so this also gives us the address of + the FP save location. */ + this_base = frame_unwind_register_unsigned(next_frame, ARC_FP_REGNUM); + info->frame_base = (CORE_ADDR) this_base; + info->saved_regs[ARC_FP_REGNUM].addr = (long long) this_base; + + /* The previous SP is the current frame base + the difference between + that frame base and the previous SP. */ + info->prev_sp = info->frame_base + (CORE_ADDR) info->old_sp_offset_from_fp; + + for (i = ARC_ABI_FIRST_CALLEE_SAVED_REGISTER; i < ARC_ABI_LAST_CALLEE_SAVED_REGISTER; i++) + { + /* If this register has been saved, add the previous stack pointer + to the offset from the previous stack pointer at which the + register was saved, so giving the address at which it was saved. */ + if (info->saved_regs_mask & (1 << i)) + { + info->saved_regs[i].addr += info->prev_sp; + +#ifdef DUMP_SAVED_REGISTERS + /* This is a really useful debugging aid: we can debug a test + program which loads known values into the callee-saved + registers, then calls another function which uses those + registers (and hence must save them) then hits a breakpoint; + traversing the stack chain (e.g. with the 'where' command) + should then execute this code, and we should see those known + values being dumped, so showing that we have got the right + addresses for the save locations! */ + { + unsigned int contents; + DEBUG("saved R%02d is at 0x%lx\n", i, (long unsigned int) info->saved_regs[i].addr); - if (current_instr._opcode == 0x2) - { - // Saves the return address st blink,[sp,4] 0x100e3e04 - // Save the callers fp st fp,[sp] 0x100e3600 - // Saves the args st rX,[fp, #imm] 0x100d8xxx - if (current_instr.ea_reg1 == 28) - { - if( strstr(current_instr.operandBuffer,"blink") == current_instr.operandBuffer) - { - if(info) - { - info->sp_offset += current_instr._offset; - // info->blink_offset = info->sp_offset ; - info->blink_offset = current_instr._offset; - info->is_leaf = 0; - -#ifdef ARC_DEBUG - printf("Blink instruction:\n"); - printFrameInfo(info); -#endif - } - continue; - } - else - if(strstr(current_instr.operandBuffer,"fp") == current_instr.operandBuffer) - { - if(info) - { -/* info->sp_offset += current_instr._offset ; */ -/* info->fp_offset = info->sp_offset; */ - info->fp_offset = 0; - } - continue; - } - } - else if (current_instr.ea_reg1 == 27) - { - /* Saving of arguments onto the stack using the - frame pointer (r27). */ - if(info) - { - // Save regs offsets - } -#ifdef ARC_DEBUG - printf(" Saving registers onto stack\n%s\n",current_instr.operandBuffer); -#endif - continue; - } - // ISPUSHBLINK(current_instr); - } - else if (current_instr._opcode == 0xc) - { - // Resets stack pointer to fp - // 0x636e3800 - // 636e3800 mov fp,sp - if (current_instr.words[0] == 0x636e3800) - { - if (info) - { - info->uses_fp = 1; - } - continue; - } - } - else if (current_instr._opcode == 0xa) - { - // Decrements stackpointer to add for new stack frame - // 0x538e7e18 sub sp,sp,#imm - // 538e7e20 sub sp,sp,32 - if( current_instr.words[0] == 0x538e7e20) - { - //sub sp,sp, 32 //// variadic - if (info) - { - int tmp = atoi(current_instr.operandBuffer + 6); - info->sp_offset -= tmp; - } - continue; - } - else if((current_instr.words[0] & 0xffffff00) == 0x538e7e00) - { - // sub sp,sp,xx - if(info) - { - int tmp = atoi(current_instr.operandBuffer + 6); - info->sp_offset -= tmp; - } - continue; - } - } - - /* Found a instruction that is not in - the prologue*/ -#ifdef ARC_DEBUG - printf("End of Prologue reached \n"); + if (target_read_memory((CORE_ADDR) info->saved_regs[i].addr, + (gdb_byte*) &contents, + BYTES_IN_REGISTER) == 0) + { + DEBUG("saved R%02d contents: 0x%0x\n", i, contents); + } + } #endif - break; + } + } } - - /* Means we were called from skip_prologue */ - if((next_frame == NULL)&& (info == NULL)) + else { - return prologue_ends_pc; - } + ULONGEST this_sp; + /* Get the stack pointer for this frame by getting the saved SP + from the next frame. */ + this_sp = frame_unwind_register_unsigned (next_frame, ARC_SP_REGNUM); - info->framesize = -info->sp_offset; - /* Compute the previous frame's stack pointer (which is also the - frame's ID's stack address), and this frame's base pointer. */ - if(info->uses_fp) - { + /* The previous SP is this frame's SP plus the known difference between + the previous SP and this frame's SP (the delta_sp is negated as it is + a negative quantity). */ + info->prev_sp = (CORE_ADDR) (this_sp + (ULONGEST) (-info->delta_sp)); - ULONGEST this_base; - /* The SP was moved to the FP. This indicates that a new frame - was created. Get THIS frame's FP value by unwinding it from - the next frame. */ - frame_unwind_unsigned_register(next_frame, ARC_FP_REGNUM, - &this_base); - info->frame_base = this_base; - info->saved_regs[ARC_FP_REGNUM].addr = info->frame_base; - - /* The previous sp is the current frame base + the offset of the - fp in the current frame */ - info->prev_sp = info->frame_base + info->fp_offset; - for(i = 13; i < 26 ; i++ ) - { - if(saved_regs_mask & (1 << i)) - info->saved_regs[i].addr += info->frame_base ; - } - - printFrameInfo(info); - + /* Assume that the FP is this frame's SP. */ + info->frame_base = (CORE_ADDR) this_sp; } - else + + /* If the function owning this frame is not a leaf function. */ + if (!info->is_leaf) { - ULONGEST this_base; - /* Assume that the FP is this frame's SP but with that pushed - stack space added back. */ - frame_unwind_unsigned_register (next_frame, ARC_SP_REGNUM, &this_base); - info->frame_base = this_base; - - /* In such a case it would be the previous SP + the size of the current frame */ - info->prev_sp = info->frame_base + info->framesize; - + /* Usually blink is saved above the callee save registers and below the + space created for variable arguments. The quantity + + info->blink_save_offset_from_prev_sp + + is negative, so adding it to the the previous SP gives the address of + a location further down the stack from that SP. */ + info->saved_regs[ARC_BLINK_REGNUM].addr = + (LONGEST) (info->prev_sp + info->blink_save_offset_from_prev_sp); } - +} + - if(!info->is_leaf) +/* The workhorse : frame_unwind_cache for the ARC700 target. */ + +static UnwindCache * +frame_unwind_cache (struct frame_info *next_frame, + void **this_prologue_cache) +{ + ENTERMSG; + + if ((*this_prologue_cache) == NULL) { + CORE_ADDR entrypoint = frame_func_unwind(next_frame, NORMAL_FRAME); + UnwindCache *cache = create_cache(next_frame); - /* Usually blink is saved before the callee save registers and - below the space created for variadic arguments . We maintain - info->blink_offset as negative when we stored it initially - */ - info->saved_regs[ARC_BLINK_REGNUM].addr = info->prev_sp + info->blink_offset; -#ifdef ARC_DEBUG - printf("blink offset is [%x] \n",info->blink_offset); -#endif + /* Return the newly-created cache. */ + *this_prologue_cache = cache; + + /* Prologue analysis does the rest... */ + + /* Currently our scan prologue does not support getting input for the + frame unwinder. */ + (void) scan_prologue(entrypoint, next_frame, cache); } - - /* The PC is found in blink (the actual register or located on the stack). */ - // FIXMEA: - //info->saved_regs[ARC_STATUS_REGNUM] |= (info->saved_regs[ARC_BLINK_REGNUM] & 0xffffff)>>2; - info->saved_regs[ARC_STATUS_REGNUM] = info->saved_regs[ARC_BLINK_REGNUM]; - return prologue_ends_pc; + return *this_prologue_cache; } -#endif -static CORE_ADDR -arc_scan_prologue (CORE_ADDR pc, struct frame_info *next_frame, - struct arc_unwind_cache *info) + +/* -------------------------------------------------------------------------- */ +/* local functions for decoding function prologues */ +/* -------------------------------------------------------------------------- */ + +/* This function determines whether the given register, which is being saved + by a function prologue on the stack at a known offset from the current SP, + is a callee-saved register. If it is, the information in the frame unwind + cache is updated. */ + +static Boolean +is_callee_saved_register (unsigned int reg, + int offset, + UnwindCache * info) { -#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf("\narc_scan_prologue called\n"); -#endif -#else - /* End of prologue */ - CORE_ADDR prologue_ends_pc = pc; - int i = 0; - struct arcDisState current_instr, instr_in_delay; - int insn_length; - - /* Initializations to use the opcodes - * library . - */ - - struct disassemble_info di; - - unsigned int saved_regs_mask = 0; - /* An arbitrary length on the length of the - prologue. If next_frame is NULL this means that there was - no debug info and we are called from arc_skip_prologue - */ - CORE_ADDR final_pc = (next_frame)?frame_pc_unwind(next_frame):pc+64; - - - - - if (info) - { - /* All functions start as leaf functions until - we identify push blink - */ - info->is_leaf = 1; - - } - - - - /* Initializations to use the opcodes - * library . - */ - init_disassemble_info(&di, gdb_stderr, fprintf_unfiltered); - di.arch = gdbarch_bfd_arch_info(current_gdbarch)->arch; - di.mach = gdbarch_bfd_arch_info(current_gdbarch)->mach; - di.endian = gdbarch_byte_order(current_gdbarch); - di.read_memory_func = target_read_memory; - - - for(prologue_ends_pc= pc; prologue_ends_pc< final_pc; - prologue_ends_pc += current_instr.instructionLen ) + if (ARC_ABI_FIRST_CALLEE_SAVED_REGISTER <= reg && reg <= ARC_ABI_LAST_CALLEE_SAVED_REGISTER) { - current_instr = arcAnalyzeInstr(prologue_ends_pc, &di); - printInsnState(current_instr); - /* Might be a push or a pop */ - if(current_instr._opcode == 0x3) - { - if(current_instr._addrWriteBack) - { - /* This is a st.a */ - if((current_instr.ea_reg1 == 28) && - (current_instr._offset == -4)) - { - - /* This is a push something at sp */ - /* Is it a push of the blink */ - ISPUSHBLINKFI(current_instr); - /* Is it a push for fp */ - ISPUSHFPFI(current_instr); - - } - - } - else - { - /* Is this a store of some register onto - the stack using the stack pointer.*/ - if(current_instr.ea_reg1 == 28) - { - if(current_instr.sourceType == ARC_REGISTER ) - { - /* R13..R26 are the callee saved registers. [R27 (fp) - is also a callee saved register, but it's usually - pushed using st.a and so handled in the st.a case - above.] */ - if((current_instr.source_operand.registerNum > 12 - && current_instr.source_operand.registerNum <= 26)) - { - if(info) - { - printFrameInfo(info); - /* Save up the offsets for the correct instruction */ - info->saved_regs[current_instr.source_operand.registerNum].addr - = - info->sp_offset - current_instr._offset; - saved_regs_mask |= (1 << current_instr.source_operand.registerNum); - } - continue; - } - - } - - } - /* Is this the store of some register on the - stack using the frame pointer. We check - for argument registers getting saved and - restored. - */ - if(current_instr.ea_reg1 == 27) - if((current_instr.source_operand.registerNum <= 7)) - { - /* Saving argument registers.Don't save them in saved_regs, just skip. - */ - continue; - } - - - - } - } - - if(current_instr._opcode == 0x4) - { - /* A major opcode 0x4 instruction */ - /* We are usually interested in a - mov or a sub */ - ISUPDATEFPFI(current_instr); - ISSUBSPFI(current_instr); - } - if(current_instr._opcode == 0x18) - { - /* sub_s sp,sp,constant */ - ISSUBSPFI(current_instr); - /* push_s blink */ - if(strcmp(current_instr.instrBuffer,"push_s") == 0) - { - if(strcmp(current_instr.operandBuffer,"blink") == 0) - { - if(info) - { - info->sp_offset += 4; - info->blink_offset = info->sp_offset ; - info->is_leaf = 0; - } - continue; - } - } - } - - /* If we reach here . we have - * reached end of the prologue - */ - break; - - } - - /* Means we were called from skip_prologue */ - if((next_frame == NULL)&& (info == NULL)) - { - return prologue_ends_pc; + DEBUG("register R%02u saved\n", reg); + + if (info) + { + /* We can not determine the address of the location in the stack + frame in which the register was saved, as we do not (yet) know + the frame or stack pointers for the frame; so the most we can do + is to record the offset from the old SP of that location, which + we can compute as we know the offset of SP from the old SP, and + the offset of the location from SP (which is the offset in the + store instruction). + + N.B. the stack grows downward, so the store offset is positive, + but the delta-SP is negative, so the save offset is also + negative. + + | | + old sp ------> |------------| + / | | \ + : | | : + : | | : -ve + : | | : save offset + : |------------| : + -ve : | save loc | / + delta sp : |------------| <--- store address + : / | | + : +ve : | | + : store : | | + : offset : | | + \ \ | | + sp' ---------> | | + | | + | | + |------------| <---- frame base + | | + | | + | | + | | | + | + V + downwards + + where sp' is the stack pointer at the current point in the code */ + + info->saved_regs[reg].addr = info->delta_sp + offset; + + /* We now know that this register has been saved, so set the + corresponding bit in the save mask. */ + info->saved_regs_mask |= (1 << reg); + + printFrameInfo("after callee register save", info, FALSE); + + return TRUE; + } } - - - info->framesize = -info->sp_offset; - /* Compute the previous frame's stack pointer (which is also the - frame's ID's stack address), and this frame's base pointer. */ - if(info->uses_fp) + + return FALSE; +} + + +/* This function determines whether the given disassembled instruction may be + part of a function prologue. If it is, the information in the frame unwind + cache may be updated. */ + +static Boolean +is_in_prologue (UnwindCache *info, struct arcDisState *instr) +{ + /* Might be a push or a pop */ + if (instr->_opcode == 0x3) { + if (instr->_addrWriteBack != (char) 0) + { + /* This is a st.a instruction. */ + if (instr->ea_reg1 == ARC_ABI_STACK_POINTER) + { + if (instr->_offset == -4) + { + /* This is a push something at SP. */ + /* Is it a push of the blink? */ + IS_PUSH_BLINK_FI(instr); + + /* Is it a push for fp? */ + IS_PUSH_FP_FI(instr); + } + else + { + if (instr->sourceType == ARC_REGISTER ) + { + /* st.a <reg>, [sp,<offset>] */ + + if (is_callee_saved_register(instr->source_operand.registerNum, + instr->_offset, + info)) + { + /* This is a push onto the stack, so change delta_sp. */ + info->delta_sp += instr->_offset; + return TRUE; + } + } + } + } + } + else + { + if (instr->sourceType == ARC_REGISTER ) + { + /* Is this a store of some register onto the stack using the + stack pointer? */ + if (instr->ea_reg1 == ARC_ABI_STACK_POINTER) + { + /* st <reg>, [sp,offset] */ + + if (is_callee_saved_register(instr->source_operand.registerNum, + instr->_offset, + info)) + /* This is NOT a push onto the stack, so do not change delta_sp. */ + return TRUE; + } - ULONGEST this_base; - /* The SP was moved to the FP. This indicates that a new frame - was created. Get THIS frame's FP value by unwinding it from - the next frame. */ - frame_unwind_unsigned_register(next_frame, ARC_FP_REGNUM, - &this_base); - info->frame_base = this_base; - info->saved_regs[ARC_FP_REGNUM].addr = info->frame_base; - - /* The previous sp is the current frame base + the offset of the - fp in the current frame */ - info->prev_sp = info->frame_base + info->fp_offset; - for(i = 13; i < 26 ; i++ ) - { - if(saved_regs_mask & (1 << i)) - info->saved_regs[i].addr += info->frame_base ; - } - - printFrameInfo(info); - + /* Is this the store of some register on the stack using the + frame pointer? We check for argument registers getting saved + and restored. */ + if (instr->ea_reg1 == ARC_ABI_FRAME_POINTER) + { + if (IS_ARGUMENT_REGISTER(instr->source_operand.registerNum)) + { + /* Saving argument registers. Don't set the bits in the + saved mask, just skip. */ + return TRUE; + } + } + } + } } - else + + else if (instr->_opcode == 0x4) { - ULONGEST this_base; - /* Assume that the FP is this frame's SP but with that pushed - stack space added back. */ - frame_unwind_unsigned_register (next_frame, ARC_SP_REGNUM, &this_base); - info->frame_base = this_base; - - /* In such a case it would be the previous SP + the size of the current frame */ - info->prev_sp = info->frame_base + info->framesize; - + /* A major opcode 0x4 instruction. */ + /* We are usually interested in a mov or a sub. */ + IS_UPDATE_FP_FI(instr); + IS_SUB_SP_FI(instr); } - - if(!info->is_leaf) + else if (instr->_opcode == 0x18) { + /* sub_s sp,sp,constant */ + IS_SUB_SP_FI(instr); - /* Usually blink is saved before the callee save registers and - below the space created for variadic arguments . We maintain - info->blink_offset as negative when we stored it initially - */ - info->saved_regs[ARC_BLINK_REGNUM].addr = info->prev_sp + info->blink_offset; -#ifdef ARC_DEBUG - printf("blink offset is [%x] \n",info->blink_offset); -#endif + /* push_s blink */ + if (strcmp(instr->instrBuffer, "push_s") == 0) + { + if (strcmp(instr->operandBuffer, "blink") == 0) + { + if (info) + { + /* SP is decremented by the push_s instruction (before it + stores blink at the stack location addressed by SP). */ + PUSH_BLINK(-BYTES_IN_REGISTER) + } + return TRUE; + } + } + else if (strcmp(instr->instrBuffer, "st_s") == 0) + { + unsigned int reg; + int offset; + + if (sscanf(instr->operandBuffer, "r%u,[sp,%d]", ®, &offset) == 2) + { + /* st_s <reg>,[sp,<offset>] */ + + if (is_callee_saved_register(reg, offset, info)) + /* This is NOT a push onto the stack, so do not change delta_sp. */ + return TRUE; + } + } } - - /* The PC is found in blink (the actual register or located on the stack). */ - info->saved_regs[PC_REGNUM] = info->saved_regs[ARC_BLINK_REGNUM]; - /*info->saved_regs[ARC_PC_REGNUM] = info->saved_regs[ARC_BLINK_REGNUM];*/ - return prologue_ends_pc; -#endif + + return FALSE; } -/* Skip the prologue for the function at pc. - * This is done by checking from the line - * information picked up during dwarf reading - * FIXME: more stuff to be added when we - * parse the prologue. - */ +/* Scan the prologue and update the corresponding frame cache for the frame + unwinder for unwinding frames without debug info. In such a situation GDB + attempts to parse the prologue for this purpose. This currently would attempt + to parse the prologue generated by our gcc 2.95 compiler (we should support + Metaware generated binaries at some suitable point of time). + + This function is called with: + entrypoint : the address of the functon entry point + next_frame : the next frame to be filled in (if need be) + info : the existing cached info. + + Returns: the address of the first instruction after the prologue. + + This function is called by our unwinder as well as from arc_skip_prologue + in the case that it cannot detect the end of the prologue. + + 'next_frame' and 'info' are NULL if this function is called from + arc_skip_prologue in an attempt to discover the end of the prologue. + In this case we don't fill in the 'info' structure that is passed in. + + TODOs: + 1. Support 32 bit normal frames generated by GCC 2.95 + 2. Support 16 and 32 bit mixed frames generated by GCC 2.95 + 3. Support 32 bit normal variadic function frames by GCC 2.95 + 4. Support 32 bit normal frames from GCC 3.4.x with variadic args + 5. Support 16 and 32 bit normal frames from GCC 3.4.x with variadic args + 6. Support 16 and 32 bit mixed frames generated by GCC 3.4.x + 7. Support Metaware generated prologues + (The difference is in the use of thunks to identify the saving and + restoring of callee saves: may have to do some hackery even in + next_pc, since the call is going to create its own set of problems + with our stack setup). + + We attempt to use the disassembler interface from the opcodes library to do + our disassembling. + + The usual 32 bit normal gcc -O0 prologue looks like this: + + Complete Prologue for all GCC frames (Cases #1 to #6 in TODOs above): + + sub sp, sp, limm ; space for variadic arguments + st.a blink, [sp,-4] ; push blink (if not a leaf function) - decrements sp + sub sp, sp , limm ; (optional space creation for callee saves) + st r13, [sp] ; push of first callee saved register + st r14, [sp,4] ; push of next callee saved register + ... + st.a fp , [sp,-4] ; push fp (if fp has to be saved) - decrements sp + mov fp , sp ; set the current frame up correctly + sub sp , sp , #immediate ; create space for local vars on the stack */ + +/* 3 instructions before and after callee saves, and max number of saves; assume each is 4-byte inst. */ +#define MAX_PROLOGUE_LENGTH ((6 + (ARC_ABI_LAST_CALLEE_SAVED_REGISTER - ARC_ABI_FIRST_CALLEE_SAVED_REGISTER + 1)) * 4) static CORE_ADDR -arc_skip_prologue (CORE_ADDR pc) +scan_prologue (CORE_ADDR entrypoint, + struct frame_info *next_frame, + UnwindCache *info) { - //#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_skip_prologue called\n"); -#endif - // FIXMEA: cleanup #else - unsigned long inst; - unsigned long addend = 4; - CORE_ADDR skip_pc = pc; - CORE_ADDR func_addr, func_end = 0; - char *func_name; - struct symtab_and_line sal; + ENTERARGS("next_frame = %p, info = %p", next_frame, info); - /* If we're in a dummy frame, don't even try to skip the prologue. */ - if (deprecated_pc_in_call_dummy (pc)) - return pc; + { + /* Will be set to end of prologue. */ + CORE_ADDR prologue_ends_pc = entrypoint; + struct disassemble_info di; + + /* An arbitrary limit on the length of the prologue. If next_frame is + NULL this means that there was no debug info and we are called from + arc_skip_prologue; otherwise, if we know the frame, we can find the + pc within the function. + + N.B. that pc will usually be after the end of the prologue, but + it could actually be within the prologue (i.e. execution has + halted within the prologue, e.g. at a breakpoint); in that + case, do NOT go beyond that pc, as the instructions at the + pc and after have not been executed yet, so have had no effect! */ + CORE_ADDR final_pc = (next_frame) ? frame_pc_unwind(next_frame) + : entrypoint + MAX_PROLOGUE_LENGTH; + + if (info) + { + /* Assume that the function is a leaf function until we find out + that it is not (i.e. when we find the 'push blink' instruction + in the prologue). */ + info->is_leaf = TRUE; - /* See what the symbol table says. */ + /* No registers known to be saved, as yet. */ + info->saved_regs_mask = 0; + } - if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end)) - { - struct symbol *sym; + /* Initializations to use the opcodes library. */ + arc_initialize_disassembler(&di); + + DEBUG("Prologue PC: %lx\n", (unsigned long) prologue_ends_pc); + DEBUG("Final PC: %lx\n", (unsigned long) final_pc); - /* Found a function. */ - sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL, NULL); - if (sym && SYMBOL_LANGUAGE (sym) != language_asm) + /* Look at each instruction in the prologue. */ + while (prologue_ends_pc < final_pc) { - /* Don't use this trick for assembly source files. */ - sal = find_pc_line (func_addr, 0); - if ((sal.line != 0) && (sal.end < func_end)) - return sal.end; + struct arcDisState current_instr = arcAnalyzeInstr(prologue_ends_pc, &di); + + printInsnState(current_instr); + + /* If this instruction is in the prologue, fields in the info will be updated, + and the saved registers mask may be updated. */ + if (!is_in_prologue(info, ¤t_instr)) + { + /* Found a instruction that is not in the prologue. */ + DEBUG("End of Prologue reached \n"); + break; + } + + prologue_ends_pc += current_instr.instructionLen; } - } - -#ifdef ARC4_JTAG - skip_pc = a4_scan_prologue(pc, NULL, NULL); -#else - skip_pc = arc_scan_prologue(pc,NULL,NULL); -#endif - return skip_pc; /* End of prologue */ - //#endif -} + /* Means we were not called from arc_skip_prologue. */ + if (!((next_frame == NULL) && (info == NULL))) + { + printFrameInfo("after prologue", info, FALSE); -/* Breakpoint from pc. Return whatever is in the tdep - * structure. The tdep structure is changed depending - * on the correct target / architecture chosen. - */ + find_previous_stack_pointer(info, next_frame); -static const unsigned char * -arc_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr) -{ + /* The PC is found in blink (the actual register or located on the stack). */ + info->saved_regs[ARC_PC_REGNUM] = info->saved_regs[ARC_BLINK_REGNUM]; - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - *lenptr = tdep->arc_breakpoint_size; - return tdep->arc_breakpoint_insn; + printFrameInfo("after previous SP found", info, TRUE); + } + + return prologue_ends_pc; + } } -/* 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 the PC match the dummy frame's - breakpoint. */ +/* -------------------------------------------------------------------------- */ +/* local functions for handling function return values */ +/* -------------------------------------------------------------------------- */ -static struct frame_id -arc_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) -{ - return frame_id_build (arc_unwind_sp (gdbarch, next_frame), - frame_pc_unwind (next_frame)); -} +/* This function gets the return value of a function from the registers used to + return it, according to the convention used by the ABI. + + Parameters: + type : the information for the return type of the function + regcache : the register cache holding the register contents + valbuf : a buffer to be filled with the return value +*/ + +static void +extract_return_value (struct type *type, + struct regcache *regcache, + gdb_byte *valbuf) -/* The workhorse : frame_unwind_cache for the ARC700 platform . - */ -static struct arc_unwind_cache * -arc_frame_unwind_cache (struct frame_info *next_frame, - void **this_prologue_cache) { - //#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_frame_unwind_cache called\n "); -#endif - //#else - CORE_ADDR pc; - struct arc_unwind_cache *info; - int i; - - - if ((*this_prologue_cache)) - return (*this_prologue_cache); - - info = FRAME_OBSTACK_ZALLOC (struct arc_unwind_cache); - (*this_prologue_cache) = info; - info->saved_regs = trad_frame_alloc_saved_regs (next_frame); - - /* Zero all fields. */ - info->blink_offset = 0; - info->prev_pc = 0; - info->prev_sp = 0; - info->frame_base = 0; - info->framesize = 0; - info->sp_offset = 0; - info->fp_offset = 0; - info->prev_pc = 0; - info->is_leaf = 0; - info->uses_fp = 0; - - /* Prologue analysis does the rest... */ - /* Currently our scan prologue does not - * support getting input for the frame unwinder - */ - - pc = frame_func_unwind(next_frame); -#ifdef ARC4_JTAG - a4_scan_prologue (pc, next_frame, info); -#else - arc_scan_prologue (pc, next_frame, info); -#endif + unsigned int len = TYPE_LENGTH (type); + + ENTERMSG; + + if (len <= BYTES_IN_REGISTER) + { + ULONGEST val; + + /* Get the return value from one register. */ + regcache_cooked_read_unsigned (regcache, ARC_ABI_RETURN_REGNUM, &val); + store_unsigned_integer (valbuf, (int) len, val); + + DEBUG("returning 0x%08lX\n", (unsigned long) val); + } + else if (len <= BYTES_IN_REGISTER * 2) + { + ULONGEST low, high; + + /* Get the return value from two registers. */ + regcache_cooked_read_unsigned (regcache, ARC_ABI_RETURN_LOW_REGNUM, &low); + regcache_cooked_read_unsigned (regcache, ARC_ABI_RETURN_HIGH_REGNUM, &high); - return info; - //#endif + store_unsigned_integer (valbuf, BYTES_IN_REGISTER, low); + store_unsigned_integer (valbuf + BYTES_IN_REGISTER, (int) len - BYTES_IN_REGISTER, high); + + DEBUG("returning 0x%08lX%08lX\n", + (unsigned long) high, (unsigned long) low); + } + else + error(_("%s: type length %u too large"), __FUNCTION__, len); } +/* This function loads the return value of a function into the registers used to + return it, according to the convention used by the ABI. -/* - * Construct frame id for the normal frame - */ + Parameters: + type : the information for the return type of the function + regcache : the register cache holding the register contents + valbuf : a buffer holding the return value +*/ static void -arc_frame_this_id (struct frame_info *next_frame, - void **this_prologue_cache, - struct frame_id *this_id) +store_return_value (struct type *type, + struct regcache *regcache, + const gdb_byte *valbuf) { - // FIXMEA: cleanup #ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\n arc_frame_this_id called()\n "); -#endif - //#else + unsigned int len = TYPE_LENGTH (type); + + ENTERMSG; - struct arc_unwind_cache *info - = arc_frame_unwind_cache (next_frame, this_prologue_cache); - CORE_ADDR base; - CORE_ADDR func; - struct frame_id id; + if (len <= BYTES_IN_REGISTER) + { + ULONGEST val; - /* The FUNC is easy. */ - func = frame_func_unwind (next_frame); + /* Put the return value into one register. */ + val = extract_unsigned_integer (valbuf, (int) len); + regcache_cooked_write_unsigned (regcache, ARC_ABI_RETURN_REGNUM, val); - /* This is meant to halt the backtrace at the entry point (_start). */ - if (func <= gdbarch_tdep (current_gdbarch)->lowest_pc) - return; - - /* Hopefully the prologue analysis either correctly determined the - frame's base (which is the SP from the previous frame), or set - that base to "NULL". */ - base = info->prev_sp; - if (base == 0) - return; + DEBUG("storing 0x%08lX\n", (unsigned long) val); + } + else if (len <= BYTES_IN_REGISTER * 2) + { + ULONGEST low, high; - id = frame_id_build (base, func); + /* Put the return value into two registers. */ + low = extract_unsigned_integer (valbuf, BYTES_IN_REGISTER); + high = extract_unsigned_integer (valbuf + BYTES_IN_REGISTER, (int) len - BYTES_IN_REGISTER); - (*this_id) = id; - //#endif + regcache_cooked_write_unsigned (regcache, ARC_ABI_RETURN_LOW_REGNUM, low); + regcache_cooked_write_unsigned (regcache, ARC_ABI_RETURN_HIGH_REGNUM, high); + DEBUG("storing 0x%08lX%08lX\n", + (unsigned long) high, (unsigned long) low); + } + else + error(_("arc_store_return_value: type length too large.")); } -/* - * Unwind and obtain the register information - */ -static void -arc_frame_prev_register (struct frame_info *next_frame, - void **this_prologue_cache, - int regnum, int *optimizedp, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnump, void *bufferp) +/* -------------------------------------------------------------------------- */ +/* local functions for handling the stack frame */ +/* -------------------------------------------------------------------------- */ + +/* This is copied from file stack.c in the gdb sources. + It identifies a frame from information (such as frame number) given by the + user (in the frame_exp parameter). */ + +static struct frame_info* +parse_frame_specification_1 (const char *frame_exp, + const char *message, + int *selected_frame_p) { - // FIXMEA: - //#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\n arc_frame_prev_register() called for regnum %d\n ",regnum ); -#endif - //#else - struct arc_unwind_cache *info - = arc_frame_unwind_cache (next_frame, this_prologue_cache); + int numargs = 0; + struct value *args[4]; + CORE_ADDR addrs[ARRAY_SIZE (args)]; + if (frame_exp) + { + while (TRUE) + { + char *addr_string; + struct cleanup *cleanup; + const char *p; - /* If we are asked to unwind the PC, then we need to return blink - instead. The saved value of PC points into this frame's - prologue, not the next frame's resume location. */ -#ifdef ARC4_JTAG - if (regnum == ARC_STATUS_REGNUM) -#else - if (regnum == PC_REGNUM) -#endif - regnum = ARC_BLINK_REGNUM; + /* Skip leading white space. */ + while (isspace (*frame_exp)) + frame_exp++; + + if (*frame_exp == '\0') + break; + + /* Parse the argument, extract it, save it. */ + for (p = frame_exp; (*p != '\0') && !isspace (*p); p++); + + addr_string = savestring (frame_exp, (size_t) (p - frame_exp)); + frame_exp = p; + cleanup = make_cleanup (xfree, addr_string); + + /* NOTE: Parse and evaluate expression, but do not use + functions such as parse_and_eval_long or + parse_and_eval_address to also extract the value. + Instead value_as_long and value_as_address are used. + This avoids problems with expressions that contain + side-effects. */ + if (numargs >= (int) ARRAY_SIZE (args)) + error (_("Too many args in frame specification")); + + args[numargs++] = parse_and_eval (addr_string); + + do_cleanups (cleanup); + } + } - /* 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 (regnum == ARC_SP_REGNUM) + /* If no args, default to the selected frame. */ + if (numargs == 0) { - *lvalp = not_lval; - if (bufferp) - store_unsigned_integer (bufferp, 4, info->prev_sp); - return; + if (selected_frame_p != NULL) + (*selected_frame_p) = 1; + return get_selected_frame (message); } + /* None of the remaining use the selected frame. */ + if (selected_frame_p != NULL) + (*selected_frame_p) = 0; - trad_frame_get_prev_register (next_frame, info->saved_regs, regnum, - optimizedp, lvalp, addrp, realnump, bufferp); + /* Assume the single arg[0] is an integer, and try using that to + select a frame relative to current. */ + if (numargs == 1) + { + int level = (int) value_as_long (args[0]); + struct frame_info *fid = find_relative_frame (get_current_frame (), &level); + if (level == 0) + /* find_relative_frame was successful. */ + return fid; + } -#ifdef ARC_DEBUG - printf("-*-*-*\n Regnum =%d, realnump=%d,%d \n",regnum, (char *)(bufferp), *((char*)bufferp)); -#endif - //#endif + /* Convert each value into a corresponding address. */ + { + int i; + for (i = 0; i < numargs; i++) + addrs[i] = value_as_address (args[i]); + } + + /* Assume that the single arg[0] is an address, use that to identify + a frame with a matching ID. Should this also accept stack/pc or + stack/pc/special. */ + if (numargs == 1) + { + struct frame_id id = frame_id_build_wild (addrs[0]); + struct frame_info *fid; + + /* If (s)he specifies the frame with an address, he deserves + what (s)he gets. Still, give the highest one that matches. + (NOTE: cagney/2004-10-29: Why highest, or outer-most, I don't + know). */ + for (fid = get_current_frame (); + fid != NULL; + fid = get_prev_frame (fid)) + { + if (frame_id_eq (id, get_frame_id (fid))) + { + while (frame_id_eq (id, frame_unwind_id (fid))) + fid = get_prev_frame (fid); + return fid; + } + } + } + + /* We couldn't identify the frame as an existing frame, but + perhaps we can create one with a single argument. */ + if (numargs == 1) + return create_new_frame (addrs[0], 0); + else if (numargs == 2) + return create_new_frame (addrs[0], addrs[1]); + else + error (_("Too many args in frame specification")); } +/* Return an array (and count) of the local variables and parameters declared + in the function which owns the given frame. + Parameters: + frame : the frame information for the function + variables: a pointer to an existing array of variable information (may be NULL) + count : (IN/OUT) the total number of variables found + callee : TRUE if the function is a callee of another function -static const struct frame_unwind arc_frame_unwind = { - NORMAL_FRAME, - arc_frame_this_id, - arc_frame_prev_register -}; + Result: + A pointer to an array containing one element for each parameter, and, if + 'callee' is FALSE, each local variable, of the function. */ -const struct frame_unwind * -arc_frame_sniffer (struct frame_info *next_frame) +static LocalVariable* +find_variables (struct frame_info *frame, + LocalVariable *variables, + unsigned int *count, + Boolean callee) { - return &arc_frame_unwind; + struct block *block = get_frame_block (frame, 0); + unsigned int vars = *count; + + while (block) + { + struct dict_iterator iter; + struct symbol *sym; + + ALL_BLOCK_SYMBOLS (block, iter, sym) + { + Boolean is_arg = (SYMBOL_CLASS(sym) == LOC_COMPUTED_ARG); + CORE_ADDR addr; + + switch (SYMBOL_CLASS (sym)) + { + case LOC_COMPUTED: + case LOC_COMPUTED_ARG: + addr = SYMBOL_OPS (sym)->get_variable_address(sym, frame); + + /* For callees, we are only interested in the arguments. */ + if ((addr != 0) && (!callee || is_arg)) + { + struct type *type = SYMBOL_TYPE (sym); + + vars++; + variables = xrealloc(variables, sizeof(LocalVariable) * vars); + + if (variables) + { + LocalVariable *var = &variables[vars - 1]; + + var->name = SYMBOL_PRINT_NAME (sym); + var->address = addr; + var->is_callee = callee; + var->is_argument = is_arg; + var->is_array = (TYPE_CODE (type) == TYPE_CODE_ARRAY); + var->size = SYMBOL_OPS (sym)->get_variable_size(sym, frame); + + if (var->is_array) + var->element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (type)); + } + else + { + *count = 0; + return NULL; + } + } + break; + + default: + /* Ignore symbols which are not locals. */ + break; + } + } + + /* After handling the function's top-level block, stop. Don't continue + to its superblock, the block of per-file symbols. */ + if (BLOCK_FUNCTION (block)) + break; + block = BLOCK_SUPERBLOCK (block); + } + + *count = vars; + return variables; } -/* read-only registers */ -static int -arc_cannot_store_register (int regno) +/* Return an array (and count) of the local variables declared in the function + which owns the given frame, and also those declared in the function which is + the callee (if any) of that function in the current call chain. */ + +static LocalVariable* +find_local_variables (struct frame_info *frame, unsigned int *count) { - if( -#ifndef ARC4_JTAG - regno == ARC_EFA_REGNUM || - regno == ARC_ERET_REGNUM || - regno == ARC_STATUS32_L1_REGNUM || - regno == ARC_STATUS32_L2_REGNUM || - regno == ARC_ERSTATUS_REGNUM || -#endif - regno == ARC_ILINK1_REGNUM || - regno == ARC_ILINK2_REGNUM - ) + struct frame_info *callee = get_next_frame(frame); + LocalVariable *variables; + + *count = 0; + + variables = find_variables(frame, NULL, count, FALSE); + + if (callee) + variables = find_variables(callee, variables, count, TRUE); + + return variables; +} + + +/* Try to add the name of a local variable or function parameter to a line of + output, if a given address lies within the range of locations occupied by + that data item. + + Parameters: + line : the line in which any output is to be placed + location : the address of a location on the stack + variables : an array of local variables and parameters + num_variables : the number of elements in the array + is_following_element : set to TRUE if the location lies within an + array element, and it is not the 0th element + elements_are_word_sized: set to TRUE if the array element is word-sized + + Returns TRUE if the given location holds a local variable or parameter + (i.e. information has been added to the line of output). */ + +static Boolean +add_local_name (char *line, + CORE_ADDR location, + LocalVariable *variables, + unsigned int num_variables, + Boolean *is_following_element, + Boolean *elements_are_word_sized) +{ + unsigned int i; + + *is_following_element = FALSE; + *elements_are_word_sized = FALSE; + + /* Look at each of the local variables / parameters in the array. */ + for (i = 0; i < num_variables; i++) { - /* No warning should be printed. arc_cannot_store_register being - called does not imply that someone is actually writing to regnum. */ + LocalVariable *var = &variables[i]; + int index = -1; - /*warning("writing to read-only register: %s\n", arc_register_name(regno));*/ - return 1; - } - return 0; + /* is the variable an array? */ + if (var->is_array) + { + /* If we know the size of the array, and the size of its elements. */ + if (var->size > 0 && var->element_size > 0) + { + /* What is the offset of the given stack location from the start + of the array? */ + int offset = (int) ((long int) location - (long int) var->address); + + /* Does that offset actually lie within the array? */ + if (0 <= offset && offset < (int) var->size) + { + /* Compute the index of the array element which contains the + location. */ + index = offset / var->element_size; + } + + if (var->element_size == BYTES_IN_WORD) + *elements_are_word_sized = FALSE; + } + } + + /* If the variable starts in the given location, or the variable is an + array and one of its elements contains the location. */ + if (var->address == location || index >= 0) + { + int n; + + /* What is the variable? */ + if (var->is_callee) + n = sprintf(line, _("callee parameter")); + else if (var->is_argument) + n = sprintf(line, _("parameter")); + else + n = sprintf(line, _("local variable")); + + line[n] = ' '; + n++; + n += sprintf(line + n, _("'%s'"), var->name); + line[n] = ' '; + + /* If it is an array element. */ + if (index >= 0) + { + /* Add the array element index to the output. */ + (void) sprintf(line + n, _("[%u]"), index); + + /* Is it an element which follows another element? */ + *is_following_element = (index > 0); + } + else if (var->size > BYTES_IN_WORD) + { + /* It occupies more than one word. */ + (void) sprintf(line + n + 1, _("(%u words)"), + WORDS_OCCUPIED(var->size)); + } + + return TRUE; + } + } + + return FALSE; } -/* Returns true if the insn at PC is a branch. *fall_thru is the address of - the next insn. *target is the branch target. */ -static int -arc_next_pc(CORE_ADDR pc, CORE_ADDR *fall_thru, CORE_ADDR *target) + +/* Try to identify the given frame, and output that identification. */ + +static void +identify_frame (struct frame_info *frame) { -#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_next_pc called\n"); -#endif -#else - struct arcDisState instr, instr_d; - int insn_length; - struct disassemble_info di; - int two_targets = 0; - - init_disassemble_info(&di, NULL, NULL); - di.arch = gdbarch_bfd_arch_info(current_gdbarch)->arch; - di.mach = gdbarch_bfd_arch_info(current_gdbarch)->mach; - di.endian = gdbarch_byte_order(current_gdbarch); - di.read_memory_func = target_read_memory; - - instr = arcAnalyzeInstr(pc, &di); - - *fall_thru = pc + instr.instructionLen; - -#ifdef ARC_DEBUG - printf("--- arc_next_pc(%x) = %x, isBranch = %d, tcnt = %d [%x], flow = %s (%d), " - "reg for indirect jump = %d, nullifyMode = %s\n", - pc, *fall_thru, instr.isBranch, instr.tcnt, instr.targets[0], - (instr.flow == direct_jump || instr.flow == direct_call) ? "direct" : "indirect", - instr.flow, - instr.register_for_indirect_jump, - (instr.nullifyMode == BR_exec_always ? "delay slot" : "no delay")); -#endif + enum language func_lang = language_unknown; + char *func_name = NULL; + char *demangled = NULL; + struct symbol *func; + struct symtab_and_line sal; - if(instr.isBranch) + find_frame_sal (frame, &sal); + func = get_frame_function (frame); + + /* Have we found the function owning the frame? */ + if (func) { - two_targets = 1; - - if(instr.flow == direct_jump || instr.flow == direct_call) - *target = instr.targets[0]; - else - regcache_cooked_read(current_regcache, - arc_binutils_reg_to_regnum(instr.register_for_indirect_jump), - target); + func_name = DEPRECATED_SYMBOL_NAME (func); + func_lang = SYMBOL_LANGUAGE (func); } + else + { + struct minimal_symbol *msymbol; - /* for instructions with delay slots, the fall thru is not the instruction - immediately after the branch instruction, but the one after that */ - if(instr.isBranch && instr.nullifyMode == BR_exec_always) + /* Try to find the symbol most closely associated with the PC + corresponding to the frame. */ + msymbol = lookup_minimal_symbol_by_pc (get_frame_pc (frame)); + + if (msymbol != NULL) + { + func_name = DEPRECATED_SYMBOL_NAME (msymbol); + func_lang = SYMBOL_LANGUAGE (msymbol); + } + } + + /* Have we found a name? */ + if (func_name) { - instr_d = arcAnalyzeInstr(*fall_thru, &di); - *fall_thru += instr_d.instructionLen; + /* If user wants to see raw output, no problem. + (demangle is a global flag which can be set by user command). */ + if (demangle) + { + demangled = language_demangle (language_def (func_lang), + func_name, + DMGL_ANSI | DMGL_PARAMS); + + /* If the demangler fails, try the demangled name from the symbol + table. That'll have parameters, but that's preferable to + displaying a mangled name. */ + if (demangled == NULL) + { + if (func == NULL) + func_name = _("<unknown function>"); + else + func_name = SYMBOL_PRINT_NAME (func); + } + else + func_name = demangled; + } } + else + func_name = _("<unknown function>"); - /* zero-overhead loops: - if(status32[L] == 0 && next_pc == lp_end && lp_count > 1) - next_pc = lp_start; - */ - { - unsigned int lp_end, lp_start, lp_count, status32; - - regcache_cooked_read(current_regcache, ARC_LP_START_REGNUM, &lp_start); - regcache_cooked_read(current_regcache, ARC_LP_END_REGNUM, &lp_end); - regcache_cooked_read(current_regcache, ARC_LP_COUNT_REGNUM, &lp_count); -#ifndef ARC4_JTAG - regcache_cooked_read(current_regcache, ARC_STATUS32_REGNUM, &status32); -#endif + printf_filtered(_("Frame of function: %s"), func_name); + if (sal.symtab) + printf_filtered(_(" (%s:%d)"), sal.symtab->filename, sal.line); + printf_filtered(NEW_LINE); - if( !(status32 & ARC_STATUS32_L) && *fall_thru == lp_end && lp_count > 1) - { - two_targets = 1; - *target = lp_start; - } - } - - return two_targets; -#endif // + if (demangled != NULL) + xfree (demangled); } -/* this is called with insert_breakpoints_p = 1 before single-stepping and - with insert_breakpoints_p = 0 after the step */ -void -arc_software_single_step(enum target_signal ignore, int insert_breakpoints_p) + +/* -------------------------------------------------------------------------- */ +/* local functions called from gdb */ +/* -------------------------------------------------------------------------- */ + +/* Standard register type for the ARC platform. + It would be builtin_type_uint32 until we consider the DSP extensions. */ + +static struct type * +arc_register_type (struct gdbarch *gdbarch, int regnum) { -#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_software_single_step called\n" ); -#endif -#else - typedef char binsn_quantum[BREAKPOINT_MAX]; - - static CORE_ADDR fall_thru, branch_target; - static binsn_quantum break_mem[2]; - static char two_breakpoints; - CORE_ADDR pc; - - { -#ifdef ARC_DEBUG - unsigned int efa, ret; - regcache_cooked_read(current_regcache, ARC_EFA_REGNUM, &efa); - // regcache_cooked_read(current_regcache, ARC_RET_REGNUM, &ret); - - printf("--- arc_software_single_step, efa = %x, ret = %x, (%s)\n", efa, ret, - (insert_breakpoints_p ? "add" : "remove")); -#endif - } - - if (insert_breakpoints_p) - { - pc = read_pc (); - two_breakpoints = arc_next_pc (pc, &fall_thru, &branch_target); - - if (two_breakpoints && branch_target == pc) - { - warning ("Cannot single-step branch-to-self or single instruction zero overhead loop,\n" - " Stepping across it."); - /* Don't insert/remove the branch-target breakpoint. */ - two_breakpoints = 0; - } - - target_insert_breakpoint (fall_thru, break_mem[0]); - if(two_breakpoints) - target_insert_breakpoint (branch_target, break_mem[1]); - } - else + return builtin_type_uint32; +} + + +/* Skip the prologue for the function at pc. + Returns the address of the first instruction after the prologue. */ + +static CORE_ADDR +arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + CORE_ADDR function_addr, function_end = 0; + char *function_name; + + /* This is done by checking from the line information read from the DWARF, + if possible; otherwise, we scan the function prologue to find its end. */ + + ENTERMSG; + + /* If we're in a dummy frame, don't even try to skip the prologue. */ + if (deprecated_pc_in_call_dummy (pc)) + return pc; + + /* See what the symbol table says. */ + if (find_pc_partial_function (pc, &function_name, &function_addr, &function_end)) { - target_remove_breakpoint (fall_thru, break_mem[0]); - if(two_breakpoints) - target_remove_breakpoint (branch_target, break_mem[1]); + /* Found a function. */ + struct symbol *sym = lookup_symbol (function_name, NULL, VAR_DOMAIN, NULL, NULL); + + if ((sym != NULL) && SYMBOL_LANGUAGE (sym) != language_asm) + { + /* Don't use this trick for assembly source files. */ + struct symtab_and_line sal = find_pc_line (function_addr, 0); + + if ((sal.line != 0) && (sal.end < function_end)) + return sal.end; + } } -#endif + + /* Find the address of the first instruction after the prologue by scanning + through it - no other information is needed, so pass NULL for the other + parameters. */ + return scan_prologue(pc, NULL, NULL); } -/* - * mapping from binutils/gcc register number to - * GDB register number ("regnum") - */ -static int -arc_binutils_reg_to_regnum (int reg) + +/* Construct frame id for the normal frame. */ + +static void +arc_frame_this_id (struct frame_info *next_frame, + void **this_prologue_cache, + struct frame_id *this_id) { -#ifdef ARC4_JTAG - if (reg >= 0 && reg <= 26) - return reg; - else if (reg == 27) /* fp */ - return ARC_FP_REGNUM; - else if (reg == 28) /* sp */ - return ARC_SP_REGNUM; - else if (reg == 29) /* ilink1 */ - return ARC_ILINK1_REGNUM; - else if (reg == 30) /* ilink2 */ - return ARC_ILINK2_REGNUM; - else if (reg == 31) /* blink */ - return ARC_BLINK_REGNUM; + ENTERMSG; -#else - /* from gcc/config/arc/arc.h */ - - if (reg >= 0 && reg <= 26) - return reg; - else if (reg == 27) /* fp */ - return ARC_FP_REGNUM; - else if (reg == 28) /* sp */ - return ARC_SP_REGNUM; - else if (reg == 29) /* ilink1 */ - return ARC_ILINK1_REGNUM; - else if (reg == 30) /* ilink2 */ - return ARC_ILINK2_REGNUM; - else if (reg == 31) /* blink */ - return ARC_BLINK_REGNUM; - else if (reg >= 32 && reg <= 59) /* reserved */ - ; - else if (reg == 60) /* lp_count */ - return ARC_LP_COUNT_REGNUM; - else if (reg == 61) /* reserved */ - ; - else if (reg == 62) /* no such register */ - ; -/* else if (reg == 63) /\* PCL *\/ */ -/* return ARC_RET_REGNUM; */ + /* FIXME: to what should *this_id be set if the frame base can not be found? */ + + { + /* Find the entry point of the function which owns the frame. */ + CORE_ADDR entrypoint = frame_func_unwind (next_frame, NORMAL_FRAME); + + /* This is meant to halt the backtrace at the entry point (_start) + (it assumes that there is no code at a lower address). */ + if (entrypoint > gdbarch_tdep (current_gdbarch)->lowest_pc) + { + UnwindCache *info = frame_unwind_cache (next_frame, this_prologue_cache); + CORE_ADDR base = info->prev_sp; + + /* Hopefully the prologue analysis either correctly determined the + frame's base (which is the SP from the previous frame), or set + that base to "NULL". */ + if (base != 0) + { + /* Build the ID from the frame base address. */ + *this_id = frame_id_build (base, entrypoint); + +#if 0 + printf("*** Frame ID: %x ==> (%x %x %x)\n", + base, + this_id->stack_addr, + this_id->code_addr, + this_id->special_addr); #endif - warning ("Unmapped register #%d encountered\n", reg); - return -1; + } + } + } } +/* Unwind and obtain the register information. */ + static void -arc_add_reggroups (struct gdbarch *gdbarch) +arc_frame_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, + int *optimized, + enum lval_type *lval, + CORE_ADDR *addr, + int *realnum, + gdb_byte *buffer) { - reggroup_add (gdbarch, general_reggroup); - reggroup_add (gdbarch, all_reggroup); - reggroup_add (gdbarch, system_reggroup); + ENTERARGS("regnum %d ", regnum); + + { + UnwindCache *info = frame_unwind_cache (next_frame, this_prologue_cache); + + /* If we are asked to unwind the PC, then we need to return blink + instead: the saved value of PC points into this frame's function's prologue, + not the next frame's function's resume location. */ + if (regnum == ARC_PC_REGNUM) + regnum = ARC_BLINK_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 (regnum == ARC_SP_REGNUM) + { + /* This value is not an L-value, i.e. it can not be changed, because + it is implicit in the structure of the call-chain. */ + *lval = not_lval; + + if (buffer) + store_unsigned_integer (buffer, BYTES_IN_REGISTER, info->prev_sp); + return; + } + + trad_frame_get_prev_register (next_frame, + info->saved_regs, + regnum, + optimized, + lval, + addr, + realnum, + buffer); + + DEBUG("-*-*-*\n Regnum = %d, buffer = %p\n", regnum, buffer); + } } -int -arc_register_reggroup_p (struct gdbarch *gdbarch, int regnum, - struct reggroup *group) + +/* This function is passed to gdb to enable it to unwind frames. */ + +static const struct frame_unwind * +arc_frame_sniffer (struct frame_info *next_frame) { - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - int tdep_answer; - - tdep_answer = tdep->register_reggroup_p (regnum, group); - if(tdep_answer != -1) - return tdep_answer; - - if (group == all_reggroup) - return 1; - else if (group == save_reggroup || group == restore_reggroup) + static const struct frame_unwind arc_frame_unwind = { - /* don't save/restore read-only registers. */ - return (!arc_cannot_store_register(regnum)); - } - else if (group == general_reggroup) + NORMAL_FRAME, // type + arc_frame_this_id, // this_id + arc_frame_prev_register, // prev_register + NULL, // unwind_data + NULL, // sniffer + NULL, // prev_pc + NULL // dealloc_cache + }; + + return &arc_frame_unwind; +} + + +/* Get the breakpoint which is appropriate for address at which it is to be set. + + Return whatever is in the ARC-private tdep structure (this has been set up + according to the correct target / architecture chosen). + + Fortunately, the ARC processor does not have separate instruction sets (like + the ARM's normal 32-bit and 16-bit Thumb instructions), so the bp instruction + to be used does not depend on the address (although the ARC does have both + 16- and 32-bit instructions, they may be freely intermixed). */ + +static const unsigned char * +arc_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int end = gdbarch_byte_order (gdbarch); + + /* Return the breakpoint instruction length. */ + *lenptr = (int) tdep->breakpoint_size; + + /* Return the breakpoint instruction code. */ + if (end == BFD_ENDIAN_LITTLE) + return tdep->le_breakpoint_instruction; + if (end == BFD_ENDIAN_BIG) + return tdep->be_breakpoint_instruction; + + internal_error (__FILE__, __LINE__, "target endianness is not known"); +} + + +/* Determine whether the given register is a member of the given group. + + Returns 0, 1, or -1: + 0 means the register is not in the group. + 1 means the register is in the group. + -1 means the tdep has nothing to say about this register and group. */ + +static int +arc_register_reggroup_p (struct gdbarch *gdbarch, + int regnum, + struct reggroup *group) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int tdep_answer = tdep->register_reggroup_p (regnum, group); + + /* If the configuration-specific tdep knows about this register. */ + if (tdep_answer != -1) + return tdep_answer; + + if (group == all_reggroup) + return 1; + + if (group == save_reggroup || group == restore_reggroup) { -#ifndef ARC4_JTAG - if (regnum == ARC_STATUS32_REGNUM) - return 0; -#endif - return 1; + /* Don't save/restore read-only registers. */ + return (!gdbarch_cannot_store_register(current_gdbarch, regnum)); } - else + + if (group == system_reggroup) { - internal_error(__FILE__, __LINE__, "bad register group"); + if (regnum == ARC_ILINK1_REGNUM || + regnum == ARC_ILINK2_REGNUM) + return 1; + + return 0; } + + internal_error(__FILE__, __LINE__, _("bad register group")); + return 0; } +/* This function is used by the DWARF-2 frame sniffer. + It is the architecture-specific register state initialization function: + it tells gdb how to find certain registers in the DWARF-2 Call Frame Information. */ static void -arc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, - struct dwarf2_frame_state_reg *reg) +arc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, + int regnum, + struct dwarf2_frame_state_reg *reg, + struct frame_info *info) { -#ifdef ARC4_JTAG - // FIXMEA: Clean up. if ( debug_arc_jtag_target_message) -#ifdef ARC_DEBUG - printf ("\n arc_dwarf2_frame_init_reg called.\n Regno no:%d,0x%x\n",regnum,regnum); -#endif +// ENTERARGS("Regno no:%d, 0x%x", regnum, (unsigned int) regnum); + + /* Make sure that we know the number of the PC! */ + arc_check_pc_defined(gdbarch); + /* The return address column. */ - if (regnum == ARC_STATUS_REGNUM) - reg->how = DWARF2_FRAME_REG_RA; - - /* The call frame address. */ - if (regnum == ARC_SP_REGNUM) - reg->how = DWARF2_FRAME_REG_CFA; + if (regnum == ARC_PC_REGNUM) + reg->how = DWARF2_FRAME_REG_RA; -#else - /* The return address column. */ - if (regnum == PC_REGNUM) - reg->how = DWARF2_FRAME_REG_RA; - - /* The call frame address. */ - if (regnum == ARC_SP_REGNUM) - reg->how = DWARF2_FRAME_REG_CFA; -#endif + /* The call frame address. */ + if (regnum == ARC_SP_REGNUM) + reg->how = DWARF2_FRAME_REG_CFA; } + +/* Unwind the frame to find the previous frame's PC. */ + static CORE_ADDR arc_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { - ULONGEST pc; -#ifdef ARC4_JTAG - frame_unwind_unsigned_register (next_frame, ARC_STATUS_REGNUM, &pc); - pc = pc & 0x00ffffff; - pc = pc << 2; -#else - frame_unwind_unsigned_register (next_frame, PC_REGNUM, &pc); -#endif - return pc; + ULONGEST pc; + + /* Make sure that we know the number of the PC! */ + arc_check_pc_defined(gdbarch); + + pc = frame_unwind_register_unsigned (next_frame, ARC_PC_REGNUM); + + DEBUG("unwind PC: 0x%08lx\n", (unsigned long) pc); + + return (CORE_ADDR) pc; } + +/* Unwind the frame to find the previous frame's SP. */ + static CORE_ADDR arc_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame) { - ULONGEST sp; - frame_unwind_unsigned_register (next_frame, SP_REGNUM, &sp); - return sp; -} + ULONGEST sp; + sp = frame_unwind_register_unsigned (next_frame, ARC_SP_REGNUM); + DEBUG("unwind SP: 0x%08lx\n", (unsigned long) sp); -static void -arc_extract_return_value (struct type *type, struct regcache *regcache, - void *valbuf) -{ - //#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_extract_return_value called\n"); -#endif - //#else - ULONGEST val; - int len = TYPE_LENGTH (type); - - if (len <= 4) - { - /* Get the return value from R0. */ - regcache_cooked_read_unsigned (regcache, ARC_RETURN1_REGNUM, &val); - store_unsigned_integer (valbuf, len, val); - } - else if (len <= 8) - { - /* Get the return value from R0 and R1. */ - /* R0 holds the lower-order bytes */ - regcache_cooked_read_unsigned (regcache, ARC_RETURN1_REGNUM, &val); - store_unsigned_integer (valbuf, 4, val); - regcache_cooked_read_unsigned (regcache, ARC_RETURN2_REGNUM, &val); - store_unsigned_integer ((char *)valbuf + 4, len - 4, val); - } - else - error ("arc_extract_return_value: type length too large"); - //#endif + return (CORE_ADDR) sp; } -static void -arc_store_return_value (struct type *type, struct regcache *regcache, - const void *valbuf) -{ - //#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_store_return_value called\n "); -#endif - //#else - ULONGEST val; - int len = TYPE_LENGTH (type); - - if (len <= 4) - { - /* Put the return value in R0. */ - val = extract_unsigned_integer (valbuf, len); - regcache_cooked_write_unsigned (regcache, ARC_RETURN1_REGNUM, val); - } - else if (len <= 8) - { - /* Put the return value in R10 and R11. */ - val = extract_unsigned_integer (valbuf, 4); - regcache_cooked_write_unsigned (regcache, ARC_RETURN1_REGNUM, val); - val = extract_unsigned_integer ((char *)valbuf + 4, len - 4); - regcache_cooked_write_unsigned (regcache, ARC_RETURN2_REGNUM, val); - } - else - error ("arc_store_return_value: type length too large."); - //#endif -} +/* This function returns the convention used by the ABI for returning a result + of the given type from a function; it may also be required to: + + a) set the return value (this is for the situation where the debugger user + has issued a "return <value>" command to request immediate return from + the current function with the given result; or + + b) get the return value ((this is for the situation where the debugger user + has executed a "call <function>" command to execute the specified + function in the target program, and that function has a non-void result + which must be returned to the user. + + Parameters: + gdbarch : gdbarch structure for the backend to use if needed + valtype : the information for the return type of the function + regcache: the register cache to be used for altered register values + readbuf : if non-NULL, read the return value into this buffer + writebuf: if non-NULL, write the return value from this buffer + */ static enum return_value_convention -arc_return_value (struct gdbarch *gdbarch, struct type *valtype, - struct regcache *regcache, void *readbuf, - const void *writebuf) +arc_return_value (struct gdbarch *gdbarch, + struct type *valtype, + struct regcache *regcache, + gdb_byte *readbuf, + const gdb_byte *writebuf) { - //#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_return_value called"); -#endif - //#else - /* This will change with the ABI */ - int struct_return = (TYPE_CODE (valtype) == TYPE_CODE_STRUCT || - TYPE_CODE (valtype) == TYPE_CODE_UNION || - TYPE_LENGTH (valtype) > 8); - - - if (writebuf != NULL) - { - gdb_assert (!struct_return); - arc_store_return_value (valtype, regcache, writebuf); - } + ENTERARGS("readbuf = %p, writebuf = %p", readbuf, writebuf); - if (readbuf != NULL) { - gdb_assert (!struct_return); - arc_extract_return_value (valtype, regcache, readbuf); + /* If the return type is a struct, or a union, or would occupy more + than two registers, the ABI uses the "struct return convention": the + calling function passes a hidden first parameter to the callee (in R0). + That parameter is the address at which the value being returned + should be stored. Otherwise, the result is returned in registers. */ + Boolean is_struct_return = (TYPE_CODE (valtype) == TYPE_CODE_STRUCT || + TYPE_CODE (valtype) == TYPE_CODE_UNION || + TYPE_LENGTH (valtype) > 2 * BYTES_IN_REGISTER); + + /* case a) */ + if (writebuf != NULL) + { + /* gdb should not ask us to set a struct return value: it should + know the struct return location and write the value there + itself. */ + gdb_assert (!is_struct_return); + store_return_value (valtype, regcache, writebuf); + } + + /* case b) */ + if (readbuf != NULL) + { + /* gdb should not ask us to get a struct return value: it should + know the struct return location and read the value from there + itself. */ + gdb_assert (!is_struct_return); + extract_return_value (valtype, regcache, readbuf); + } + + return (is_struct_return) ? RETURN_VALUE_STRUCT_CONVENTION + : RETURN_VALUE_REGISTER_CONVENTION; } +} + + +/* Assuming that 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() (!!!! WHAT IS THIS???), and the PC to match the dummy + frame's breakpoint. */ - if (struct_return) - return RETURN_VALUE_STRUCT_CONVENTION; - else - return RETURN_VALUE_REGISTER_CONVENTION; - //#endif +static struct frame_id +arc_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + return frame_id_build (arc_unwind_sp (gdbarch, next_frame), + frame_pc_unwind (next_frame)); } -/* Signal Trampoline Frame Unwinder. These - * unwinders allow frame unwinding to happen - * from within signal handlers. - */ -static struct arc_unwind_cache * +/* Signal Trampoline Frame Unwinder. + These unwinders allow frame unwinding to happen from within signal handlers. */ + +static UnwindCache * arc_sigtramp_frame_cache (struct frame_info *next_frame, - void **this_cache) + void **this_cache) { - // FIXMEA: cleanup#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_sigtramp_frame_cache called"); -#endif - //#else - struct arc_unwind_cache *cache; - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - CORE_ADDR addr; - char buf[4]; - - if (*this_cache) - return *this_cache; + ENTERMSG; - cache = FRAME_OBSTACK_ZALLOC (struct arc_unwind_cache); - (*this_cache) = cache; - cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); - - /* Zero all fields. */ - cache->blink_offset = 0; - cache->prev_pc = 0; - cache->prev_sp = 0; - cache->frame_base = 0; - cache->framesize = 0; - cache->sp_offset = 0; - cache->fp_offset = 0; - cache->prev_pc = 0; - cache->is_leaf = 0; - cache->uses_fp = 0; - - - frame_unwind_register (next_frame, SP_REGNUM, buf); - cache->frame_base = extract_unsigned_integer (buf, 4); - - addr = tdep->sigcontext_addr (next_frame); - if (tdep->sc_reg_offset) + if (*this_cache == NULL) { - int i; - - for (i = 0; i < tdep->sc_num_regs; i++) - if (tdep->sc_reg_offset[i] != -1) - cache->saved_regs[i].addr = addr + tdep->sc_reg_offset[i]; + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + UnwindCache *cache = create_cache(next_frame); + gdb_byte buf[BYTES_IN_REGISTER]; + + *this_cache = cache; + + /* Get the stack pointer and use it as the frame base. */ + frame_unwind_register (next_frame, ARC_SP_REGNUM, buf); + cache->frame_base = (CORE_ADDR) extract_unsigned_integer (buf, BYTES_IN_REGISTER); + + /* If the ARC-private target-dependent info has a table of offsets of + saved register contents within a O/S signal context structure. */ + if (tdep->sc_reg_offset) + { + /* Find the address of the sigcontext structure. */ + CORE_ADDR addr = tdep->sigcontext_addr (next_frame); + unsigned int i; + + /* For each register, if its contents have been saved within the + sigcontext structure, determine the address of those contents. */ + for (i = 0; i < tdep->sc_num_regs; i++) + if (tdep->sc_reg_offset[i] != REGISTER_NOT_PRESENT) + cache->saved_regs[i].addr = (LONGEST) (addr + tdep->sc_reg_offset[i]); + } } - return cache; - //#endif + return *this_cache; } + +/* Construct id for the given frame. */ + static void -arc_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache, - struct frame_id *this_id) +arc_sigtramp_frame_this_id (struct frame_info *next_frame, + void **this_cache, + struct frame_id *this_id) { - //FIXMEA: cleanup #ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_sigtramp_frame_this_id called"); -#endif - //#else - struct arc_unwind_cache *cache = - arc_sigtramp_frame_cache (next_frame, this_cache); - - (*this_id) = frame_id_build (cache->frame_base, frame_pc_unwind (next_frame)); - //#endif + UnwindCache *cache; + + ENTERMSG; + + cache = arc_sigtramp_frame_cache (next_frame, this_cache); + + *this_id = frame_id_build (cache->frame_base, frame_pc_unwind (next_frame)); } + +/* Retrieve the value of the register in the frame. */ + static void arc_sigtramp_frame_prev_register (struct frame_info *next_frame, - void **this_cache, - int regnum, int *optimizedp, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnump, void *valuep) + void **this_cache, + int regnum, + int *optimizedp, + enum lval_type *lvalp, + CORE_ADDR *addrp, + int *realnump, + gdb_byte *valuep) { - // FIXMEA: cleanup#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_sigtramp_frame_prev_register called"); -#endif - //#else - struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); - - /* Make sure we've initialized the cache. */ - struct arc_unwind_cache *cache = - arc_sigtramp_frame_cache (next_frame, this_cache); + ENTERMSG; - /* on a signal, the PC is in ret */ -#ifdef ARC4_JTAG - if (regnum == ARC_STATUS_REGNUM) -#else - if(regnum == PC_REGNUM) -#endif - regnum = tdep->pc_regnum_in_sigcontext; - - trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum, - optimizedp, lvalp, addrp, realnump, valuep); - //#endif + { + struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + + /* Make sure we've initialized the cache. */ + UnwindCache *cache = arc_sigtramp_frame_cache (next_frame, this_cache); + + /* On a signal, the PC is in ret. */ + if (regnum == ARC_PC_REGNUM) + regnum = tdep->pc_regnum_in_sigcontext; + + trad_frame_get_prev_register (next_frame, + cache->saved_regs, + regnum, + optimizedp, + lvalp, + addrp, + realnump, + valuep); + } } -static const struct frame_unwind arc_sigtramp_frame_unwind = -{ - SIGTRAMP_FRAME, - arc_sigtramp_frame_this_id, - arc_sigtramp_frame_prev_register -}; - -const struct frame_unwind * +static const struct frame_unwind * arc_sigtramp_frame_sniffer (struct frame_info *next_frame) { - //FIXMEA: cleanup#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_sigtramp_frame_sniffer called() "); -#endif - //#else - CORE_ADDR pc = frame_pc_unwind (next_frame); - struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame)); + ENTERMSG; - /* We shouldn't even bother if we don't have a sigcontext_addr - handler. */ - if (tdep->sigcontext_addr == NULL) - return NULL; - - if (tdep->sigtramp_p != NULL) { - if (tdep->sigtramp_p (next_frame)) - { - return &arc_sigtramp_frame_unwind; - } - } + struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame)); - return NULL; - //#endif -} + /* We don't even bother if we don't have a sigcontext_addr handler. */ + if ((tdep->sigcontext_addr != NULL) && + (tdep->is_sigtramp != NULL) && + tdep->is_sigtramp (next_frame)) + { + static const struct frame_unwind arc_sigtramp_frame_unwind = + { + SIGTRAMP_FRAME, // type + arc_sigtramp_frame_this_id, // this_id + arc_sigtramp_frame_prev_register, // prev_register + NULL, // unwind_data + NULL, // sniffer + NULL, // prev_pc + NULL // dealloc_cache + }; + + return &arc_sigtramp_frame_unwind; + } + return NULL; + } +} -/* Allow calls to be made to functions defined in the debuggee. - a.k.a dummy calls -*/ -/* When arguments must be pushed onto the stack, they go on in reverse - order. The below implements a FILO (stack) to do this. - Copied from d10v-tdep.c. */ +/* Allow calls to be made to functions defined in the debuggee (A.K.A dummy calls). -struct stack_item -{ - int len; - struct stack_item *prev; - void *data; -}; + Parameters: + gdbarch : gdbarch structure for the backend to use if needed. + function : the function to be called + regcache : the register cache to be used for altered register values + bp_addr : return address for the breakpoint. + nargs : the number of arguments to the function + args : the arguments to be passed to the function + sp : current value of SP. + struct_return: 1 if structures are returned by the function. + struct_addr : hidden address for returning a struct. */ -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 CORE_ADDR +arc_push_dummy_call (struct gdbarch *gdbarch, + struct value *function, + struct regcache *regcache, + CORE_ADDR bp_addr, + int nargs, + struct value **args, + CORE_ADDR sp, + int struct_return, + CORE_ADDR struct_addr) -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; -} + int arg_reg = ARC_ABI_FIRST_ARGUMENT_REGISTER; + ENTERARGS("nargs = %d, struct_return = %d", nargs, struct_return); + /* Push the return address. */ + regcache_cooked_write_unsigned (regcache, ARC_BLINK_REGNUM, bp_addr); + DEBUG("set BLINK = %X\n", (unsigned int) bp_addr); -/* arc_push_dummy_call : - * gdbarch : gdbarch structure for the backend to use if needed. - * function : - * regcache : - * bp_addr : Return address for the breakpoint. - * sp : Current value of sp. - * struct_return: struct_return is 1 if structures are returned by - * the function. - * struct_addr: Hidden address for returning a struct. - */ + /* Are we returning a value using a structure return instead of a normal + value return? If so, struct_addr is the address of the reserved space + for the return structure to be written on the stack, and that address + is passed to that function as a hidden first argument. */ + if (struct_return) + { + /* Pass the return address in the first argument register. */ + regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr); -static CORE_ADDR -arc_push_dummy_call(struct gdbarch *gdbarch, struct value *function, - struct regcache *regcache, CORE_ADDR bp_addr, int nargs, - struct value **args, CORE_ADDR sp, int struct_return, - CORE_ADDR struct_addr) + DEBUG("struct return address 0x%08lX passed in R%d", struct_addr, arg_reg); -{ - //#ifdef ARC4_JTAG -#ifdef ARC_DEBUG - printf ("\narc_push_dummy_call called"); -#endif - // #else - int stack_alloc; - int stack_offset; - int argreg; - int argnum; - - CORE_ADDR regval; - struct stack_item *si = NULL; - - - /* Push the return address. */ -#ifdef ARC4_JTAG - CORE_ADDR modified_bp_addr; - modified_bp_addr = arc_debug_fetch_regs(ARC_STATUS_REGNUM); - regcache_raw_collect(regcache, ARC_STATUS_REGNUM, &modified_bp_addr); - modified_bp_addr = modified_bp_addr & 0xff000000; - bp_addr = bp_addr >>2; - modified_bp_addr |= bp_addr; - regcache_cooked_write_unsigned (regcache, ARC_BLINK_REGNUM, modified_bp_addr); -#else - regcache_cooked_write_unsigned (regcache, ARC_BLINK_REGNUM, bp_addr); -#endif + arg_reg++; + } - /* Are we returning a value using a structure return or a normal value - return? struct_addr is the address of the reserved space for the return - structure to be written on the stack. - */ - /* FIXME:: Ramana :: What about 4 byte structures returned in r0 as - claimed by Metaware. - */ - - /* Now load as many as possible of the first arguments into registers, - and push the rest onto the stack. */ - argreg = ARC_ARG0_REGNUM; - - if (struct_return) + /* If the function has arguments. */ + if (nargs > 0) { - regcache_cooked_write_unsigned (regcache, ARC_ARG0_REGNUM, struct_addr); - argreg++; -#ifdef ARC4_JTAG - sp = sp - 16; -#endif - } + Boolean big_endian = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG; + unsigned int total_space = 0; + gdb_byte *memory_image; + gdb_byte *data; + int i; + + /* How much space do the arguments occupy in total? + N.B. must round each argument's size up to an integral number of words. */ + for (i = 0; i < nargs; i++) + { + unsigned int len = TYPE_LENGTH (value_type (args[i])); + unsigned int space = ROUND_UP_TO_WORDS(len); - stack_offset = 0; + total_space += space; - for (argnum = 0; argnum < nargs; argnum++) - { - int len; - char *val; - int reg_demand; - int i; - - len = TYPE_LENGTH (VALUE_TYPE (args[argnum])); - val = (char *) VALUE_CONTENTS (args[argnum]); - - /* How may registers worth of storage do we need for this argument? */ - reg_demand = (len / 4) + (len % 4 != 0 ? 1 : 0); - - if (argreg + reg_demand - 1 <= ARC_ARG7_REGNUM) + DEBUG("function arg[%d]: %d bytes -> %d\n", i, len, space); + } + + /* Allocate a buffer to hold a memory image of the arguments. */ + memory_image = XCALLOC((size_t) total_space, gdb_byte); + if (memory_image == NULL) { - /* Data passed by value. Fits in available register(s). */ - for (i = 0; i < reg_demand; i++) - { - regcache_cooked_write_unsigned (regcache, argreg, - *(unsigned long *) val); - argreg++; - val += 4; - } + /* could not do the call! */ + return 0; } - else if (argreg <= ARC_ARG7_REGNUM) + + /* Now copy all of the arguments into the buffer, correctly aligned. */ + data = memory_image; + for (i = 0; i < nargs; i++) { - /* Data passed by value. Does not fit in available register(s). - Use the register(s) first, then the stack. */ - for (i = 0; i < reg_demand; i++) - { - if (argreg <= ARC_ARG7_REGNUM) - { - regcache_cooked_write_unsigned (regcache, argreg, - *(unsigned long *) val); - argreg++; - val += 4; - } - else - { - /* Push item for later so that pushed arguments - come in the right order. */ - si = push_stack_item (si, val, 4); - val += 4; - } - } + unsigned int len = TYPE_LENGTH (value_type (args[i])); + unsigned int space = ROUND_UP_TO_WORDS(len); + gdb_byte* actual = data; + unsigned int w; + + /* Parameters smaller than a word are normally aligned by gcc to the + least significant byte, so if we have a big-endian target we put + the data at the end of the word rather than at the start. */ + if ((len < BYTES_IN_WORD) && big_endian) + actual += BYTES_IN_WORD - len; + + (void) memcpy(actual, value_contents (args[i]), (size_t) len); + + DEBUG("function arg[%d] =", i); + for (w = 0; w < space / BYTES_IN_WORD; w++) + DEBUG(" 0x%08X", *((int*) data + w)); + DEBUG("\n"); + + data += space; } - else if (len > (2 * 4)) + + /* Now load as much as possible of the memory image into registers. */ + data = memory_image; + while (arg_reg <= ARC_ABI_LAST_ARGUMENT_REGISTER) { - /* FIXME */ - internal_error (__FILE__, __LINE__, "We don't do this"); + ARC_RegisterContents contents = *(ARC_RegisterContents*) data; + + DEBUG("passing 0x%08X in register R%d\n", (unsigned int) contents, arg_reg); + + /* Convert to target byte order if necessary. */ + if (HOST_AND_TARGET_ENDIANNESS_DIFFER(gdbarch)) + { + contents = __bswap_32(contents); + DEBUG("byte-swapped to 0x%08X\n", contents); + } + + regcache_cooked_write_unsigned (regcache, + arg_reg, + (ULONGEST) contents); + + data += BYTES_IN_REGISTER; + total_space -= BYTES_IN_REGISTER; + + /* If all the data is now in registers. */ + if (total_space == 0) + break; + + arg_reg++; } - else + + /* If there is any data left, push it onto the stack (in a single write operation). */ + if (total_space > 0) { - /* Data passed by value. No available registers. Put it on - the stack. */ - si = push_stack_item (si, val, len); + DEBUG("passing %d bytes on stack\n", total_space); + + sp -= total_space; + write_memory (sp, data, (int) total_space); } - } - while (si) - { - /* fp_arg must be word-aligned (i.e., don't += len) to match - the function prologue. */ - sp = (sp - si->len) & ~3; -#ifdef ARC4_JTAG - write_memory (sp + 16, si->data, si->len); -#else - write_memory (sp, si->data, si->len); -#endif - si = pop_stack_item (si); + xfree(memory_image); } - /* Finally, update the SP register. */ - regcache_cooked_write_unsigned (regcache, ARC_SP_REGNUM, sp); + /* Finally, update the SP register. */ + regcache_cooked_write_unsigned (regcache, ARC_SP_REGNUM, sp); + + DEBUG("set SP = %X\n", (unsigned int) sp); - return sp; - //#endif + return sp; } -/* Align Frame */ + +/* Align frame. */ + static CORE_ADDR arc_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) { - /* Align to the normal alignment on the stack). */ - return sp & ~3; + /* Align to the normal alignment on the stack). */ + return WORD_ALIGNED(sp); } /* Print interesting information about the floating point processor (if present) or emulator. */ + static void arc_print_float_info (struct gdbarch *gdbarch, struct ui_file *file, - struct frame_info *frame, const char *args) + struct frame_info *frame, const char *args) { - printf("Software FPU \n"); + printf(_("Software FPU\n")); } /* Set the main_name to "_main" if required. This is set as an observer of inferior_created. */ + static void arc_set_main_name (struct target_ops *objfile, int from_tty) { - struct minimal_symbol *umainsym, *mainsym; - - /* Old ARC toolchains prepend an underscore to symbol names. If there is - an _main but no main, then we're probably debugging a binary that was - made with the old toolchain. */ - umainsym = lookup_minimal_symbol ("_main", NULL, NULL); - mainsym = lookup_minimal_symbol ("main", NULL, NULL); - if(umainsym && !mainsym) + /* Old ARC toolchains prepend an underscore to symbol names. If there is + an _main but no main, then we're probably debugging a binary that was + made with the old toolchain. */ + struct minimal_symbol *umainsym = lookup_minimal_symbol ("_main", NULL, NULL); + struct minimal_symbol *mainsym = lookup_minimal_symbol ("main", NULL, NULL); + + if ((umainsym != NULL) && (mainsym == NULL)) { - set_main_name ("_main"); + set_main_name ("_main"); } - /* If we don't have any symbols, the default, i.e. "main", will get used. */ + /* If we don't have any symbols, the default, i.e. "main", will get used. */ } -/* The following piece of code is borrowed from d10v */ -static void -a4_address_to_pointer (struct type *type, void *buf, CORE_ADDR addr) +/* This initialization function is called by gdb. + See gdbarch.h for a description of its parameters. */ + +static struct gdbarch* +arc_gdbarch_init (struct gdbarch_info info, + struct gdbarch_list *arches) { -#ifdef ARC4_JTAG - if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC - || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD) - store_unsigned_integer (buf, TYPE_LENGTH (type), (addr>>2) & 0xffffff); - else - store_unsigned_integer (buf, TYPE_LENGTH (type), addr); + /* Allocate the ARC-private target-dependent information structure, and the + gdb target-independent information structure. */ + struct gdbarch_tdep *tdep = xmalloc (sizeof (struct gdbarch_tdep)); + struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep); + + memset(tdep, 0, sizeof(*tdep)); + + /* Put stuff in gdbarch. */ + + /* Breakpoint manipulation. */ + set_gdbarch_breakpoint_from_pc (gdbarch, arc_breakpoint_from_pc); + set_gdbarch_decr_pc_after_break (gdbarch, 0); + + info.osabi = CONFIG_OSABI; + gdbarch_init_osabi(info, gdbarch); + + /* Characters are unsigned by default. */ + set_gdbarch_char_signed (gdbarch, 0); + + set_gdbarch_sp_regnum (gdbarch, ARC_SP_REGNUM); + set_gdbarch_register_type (gdbarch, arc_register_type); + set_gdbarch_print_float_info (gdbarch, arc_print_float_info); + + /* Advance PC across function entry code. */ + set_gdbarch_skip_prologue (gdbarch, arc_skip_prologue); + + /* Hook in the Dwarf-2 frame sniffer. */ + dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg); + frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer); + + /* Signal frames. */ + frame_unwind_append_sniffer (gdbarch, arc_sigtramp_frame_sniffer); + + /* The stack grows downward. */ + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + set_gdbarch_unwind_pc (gdbarch, arc_unwind_pc); + set_gdbarch_unwind_sp (gdbarch, arc_unwind_sp); + set_gdbarch_unwind_dummy_id (gdbarch, arc_unwind_dummy_id); + frame_unwind_append_sniffer (gdbarch, arc_frame_sniffer); + set_gdbarch_return_value (gdbarch, arc_return_value); + + /* Add the ARC register groups. */ + reggroup_add (gdbarch, general_reggroup); + reggroup_add (gdbarch, all_reggroup); + reggroup_add (gdbarch, system_reggroup); + + set_gdbarch_register_reggroup_p (gdbarch, arc_register_reggroup_p); + + set_gdbarch_cannot_step_breakpoint (gdbarch, 1); + set_gdbarch_frame_align(gdbarch, arc_frame_align); + + /* Dummy Frame handling. */ + set_gdbarch_push_dummy_call (gdbarch, arc_push_dummy_call); + set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT); + + /* N.B. we do not want to call arcompact_get_disassembler at this point, as we do + not as yet have an executable file, so do not know whether we want + the disassembler for the A4 architecture (still supported by the + opcodes library!) or the one for the ARCompact architecture; also, + it is better to pass the arcompact_get_disassembler function a valid bfd + structure, rather than a faked one, so that it can read the ARC- + specific sections in the ELF file (for whatever reason...). + + So just set up a dummy disassembler at this point (gdb requires that + *some* disassembler is defined for an architecture), and set up a + callback which will set up the appropriate disassembler once an + executable file has been selected for debugging. */ + +#if 0 + { + /* The arc libopcodes wants abfd so that it can find out what CPU + extensions are there. */ + bfd abfd; + + abfd.sections = NULL; + + set_gdbarch_print_insn(gdbarch, arcompact_get_disassembler(&abfd)); + } #endif + set_gdbarch_print_insn(gdbarch, dummy_disassembler); + (void) observer_attach_new_objfile(set_disassembler); + + /* Set main_name to _main if necessary. Ideally we'd want a hook that + gets called when symbols are loaded, but it seems there isn't one; so + we'll use this. This will not work if the user does "target remote + ..." and then "add-symbol-file ...". */ + (void) observer_attach_inferior_created (arc_set_main_name); + + /* Initialize the target-dependent modules (if any). */ + CONFIG_INIT_TDEP + + /* Return a pointer to the new object - indicates that a new architecture + has been created. */ + return gdbarch; } -static CORE_ADDR -a4_pointer_to_address (struct type *type, const void *buf) + +static void +arc_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file) { -#ifdef ARC4_JTAG - CORE_ADDR addr = extract_unsigned_integer (buf, TYPE_LENGTH(type)); - /* Is it a code address? */ - if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC - || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD - || TYPE_CODE_SPACE (TYPE_TARGET_TYPE (type))) - return ((addr<<2) & 0x2ffffff); - else - return addr; -#endif + /* Do nothing. */ } -static struct gdbarch * -arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + +/* -------------------------------------------------------------------------- */ +/* local functions implementing commands */ +/* -------------------------------------------------------------------------- */ + +/* <command> [ <frame> ] + Display annotated stack frame. */ + +static void +arc_show_stack_frame_command (char *arg, int from_tty) { - struct gdbarch_tdep *tdep; - struct gdbarch *gdbarch; + struct frame_info *fi; + gdb_byte value[MAX_REGISTER_SIZE]; + CORE_ADDR pc, fp, sp, old_sp; + CORE_ADDR addr; + enum lval_type lval; + int optimized; + int realnum; + int frame_size; + unsigned int *frame_contents; + LocalVariable *variables; + unsigned int num_variables; + + /* Find the frame. */ + fi = parse_frame_specification_1 (arg, _("No stack."), NULL); + gdb_assert(fi != NULL); + + /* Find out PC, FP and SP for the frame. */ + pc = get_frame_pc(fi); + sp = get_frame_sp(fi); + get_frame_register(fi, ARC_FP_REGNUM, value); + fp = (CORE_ADDR) extract_unsigned_integer (value, BYTES_IN_REGISTER); + + DEBUG("*** PC = %x, FP = %x, SP = %x\n", (unsigned int) pc, (unsigned int) fp, (unsigned int) sp); + + if (pc == 0) + { + warning(_("invalid frame")); + return; + } - tdep = xmalloc (sizeof (struct gdbarch_tdep)); - gdbarch = gdbarch_alloc (&info, tdep); - - /* Fixme :: Worry about default initialization of breakpoints - for the ARC platform. In our case currently this is handled - out of arc-linux-tdep.c for default arc linux breakpoints. - */ + frame_register_unwind (fi, ARC_SP_REGNUM, &optimized, &lval, &addr, &realnum, value); + old_sp = (CORE_ADDR) extract_unsigned_integer (value, BYTES_IN_REGISTER); - info.osabi = CONFIG_OSABI; - gdbarch_init_osabi(info, gdbarch); - - /* Put stuff in gdbarch. */ + /* Find the local variables and parameters. */ + variables = find_local_variables(fi, &num_variables); - /* Characters are unsigned by default */ - set_gdbarch_char_signed (gdbarch, 0); + printf_filtered(NEW_LINE); + identify_frame(fi); - set_gdbarch_print_float_info (gdbarch, arc_print_float_info); - set_gdbarch_sp_regnum (gdbarch, ARC_SP_REGNUM); - set_gdbarch_register_type (gdbarch, arc_register_type); + DEBUG(_("\n\n*** FRAME: 0x%x .. 0x%x\n\n"), (unsigned int) sp, (unsigned int) (old_sp - 1)); - set_gdbarch_cannot_store_register (gdbarch, arc_cannot_store_register); + frame_size = (int) (old_sp - sp); + frame_contents = xmalloc((size_t) frame_size); - /* Advance PC across function entry code. */ - set_gdbarch_skip_prologue (gdbarch, arc_skip_prologue); + if (frame_contents) + { + /* Read all of the frame's contents from target memory. */ + if (target_read_memory(sp, (gdb_byte*) frame_contents, frame_size) == 0) + { + int numregs = ARC_TOTAL_REGS; + int i = frame_size / BYTES_IN_WORD - 1; + unsigned int the_same = 0; + unsigned int previous_word = 0; + Boolean first_word = TRUE; + Boolean is_following_element; + Boolean elements_are_word_sized; - - /* Hook in the Dwarf-2 frame sniffer. */ - set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arc_binutils_reg_to_regnum); - dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg); - frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer); + addr = old_sp - BYTES_IN_WORD; - /* signal frames */ - frame_unwind_append_sniffer (gdbarch, arc_sigtramp_frame_sniffer); + printf_filtered(NEW_LINE); + /* Traverse the frame from high address to low address, one word at a time. */ + while (i >= 0) + { + unsigned int this_word = frame_contents[i]; + Boolean print = first_word; /* Always print the first word. */ + char line[256]; + int n; + /* Start with a blank line. */ + (void) memset(line, (int) ' ', sizeof(line)); - /* The stack grows downward. */ - set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + /* Does FP and/or SP address this particular stack location? */ + if (addr == sp && fp == sp) + { + (void) strcpy(line + 14, _("SP/FP ===> ")); + line[25] = ' '; + print = TRUE; + } + else if (addr == sp) + { + (void) strcpy(line + 17, _("SP ===> ")); + line[25] = ' '; + print = TRUE; + } + else if (addr == fp) + { + (void) strcpy(line + 17, _("FP ===> ")); + line[25] = ' '; + print = TRUE; + } - set_gdbarch_unwind_pc (gdbarch, arc_unwind_pc); - set_gdbarch_unwind_sp (gdbarch, arc_unwind_sp); - set_gdbarch_unwind_dummy_id (gdbarch, arc_unwind_dummy_id); - frame_unwind_append_sniffer (gdbarch, arc_frame_sniffer); - + /* Does this stack location hold a local variable or parameter? */ + if ((add_local_name(line + 38, + addr, + variables, + num_variables, + &is_following_element, + &elements_are_word_sized))) + { + /* Yes - so we want to print it (but this may be revised below!). */ + print = TRUE; + } + else + { + int r; + + /* Does this location hold a saved register? */ + for (r = 0; r < numregs; r++) + { + if (r != ARC_SP_REGNUM && + gdbarch_register_reggroup_p (current_gdbarch, r, all_reggroup)) + { + CORE_ADDR saved_addr; + + /* Find out the location of the saved register without + fetching the corresponding value. */ + frame_register_unwind (fi, r, &optimized, &lval, &saved_addr, &realnum, NULL); + + if (!optimized && lval == lval_memory && saved_addr == addr) + { + (void) sprintf(line + 38, _("saved register '%s'"), gdbarch_register_name(current_gdbarch, r)); + print = TRUE; + break; + } + } + } + } - set_gdbarch_return_value (gdbarch, arc_return_value); + /* Do we think we need to print out the line? */ + if (print) + { + /* If the location is a non-zeroth word-sized array element, + and this word is the same as the previous word. */ + if (is_following_element && elements_are_word_sized && (this_word == previous_word)) + { + /* No need to print it - one more word the same! */ + the_same++; + print = FALSE; + } + } + else + { + /* N.B. this will not be the first word (since print is FALSE) */ + + /* This location does not hold anything "interesting", but + if this word is not the same as the previous word, we + want to print it. */ + if (this_word == previous_word) + the_same++; + else + print = TRUE; + } - /* Add the arc register groups. */ - arc_add_reggroups (gdbarch); - set_gdbarch_register_reggroup_p (gdbarch, arc_register_reggroup_p); - - /* Breakpoint manipulation. */ - set_gdbarch_breakpoint_from_pc (gdbarch, arc_breakpoint_from_pc); - set_gdbarch_frame_align(gdbarch,arc_frame_align); + /* OK, now we really know whether we need to print out the line. */ + if (print) + { + n = sprintf(line, _("0x%08X:"), (unsigned int) addr); + line[n] = ' '; + + n = sprintf(line + 25, "%08X", this_word); + line[25 + n] = ' '; + + n = (int) sizeof(line) - 1; + while (line[n] == ' ') n--; + line[n + 1] = '\0'; + + /* If we did not print the previous word because it was the + same as the word before, but not the same as any preceding + words, print it now (there is no point in outputting a + message which says simply "... 1 words omitted" - we might + just as well print out the word! */ + if (the_same == 1) + printf_filtered(_("0x%08X: %08X\n"), (unsigned int) addr + BYTES_IN_WORD, previous_word); + else if (the_same != 0) + /* 2 or more words the same... */ + printf_filtered(_("... %u words omitted\n"), the_same); + + /* Now print out the line with the current word (and other information). */ + printf_filtered(_("%s\n"), line); + + /* No words omitted. */ + the_same = 0; + } - /* Dummy Frame handling */ - set_gdbarch_push_dummy_call (gdbarch, arc_push_dummy_call); - set_gdbarch_call_dummy_location (gdbarch,AT_ENTRY_POINT); - - /* Disassembly. */ - { - /* the arc libopcodes wants abfd so that it can find out what CPU - extensions are there */ - bfd abfd; - abfd.sections = NULL; + first_word = FALSE; + previous_word = this_word; + addr -= BYTES_IN_WORD; + i--; + } -#ifndef ARC4_JTAG - set_gdbarch_print_insn(gdbarch, arcompact_get_disassembler(&abfd)); -#else - set_gdbarch_print_insn(gdbarch, arc_get_disassembler(&abfd)); -#endif - } + printf_filtered(NEW_LINE); + } -#ifdef ARC4_JTAG - set_gdbarch_address_to_pointer (gdbarch, a4_address_to_pointer); - set_gdbarch_pointer_to_address (gdbarch, a4_pointer_to_address); -#endif - //#ifndef ARC4_JTAG - /* Set main_name to _main if necessary. Ideally we'd want a hook that - gets called when symbols are loaded, but it seems there isn't one; so - we'll use this. This will not work if the user does "target remote - ..." and then "add-symbol-file ..." */ - observer_attach_inferior_created (arc_set_main_name); - //#endif - -#ifdef ARC4_JTAG - // set_gdbarch_write_pc (gdbarch, a4_write_pc); -#endif + xfree(frame_contents); + } - CONFIG_INIT_TDEP (gdbarch); - - return gdbarch; + xfree(variables); } -static void -arc_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file) + +/* -------------------------------------------------------------------------- */ +/* externally visible functions */ +/* -------------------------------------------------------------------------- */ + +/* Initialize the module. This function is called from the gdb core on start-up. */ + +void +_initialize_arc_tdep (void) { + /* Register the ARC processor architecture with gdb, providing an + initialization function and a dump function; 'bfd_arch_arc' is + an enumeration value specifically denoting the ARC architecture. */ + gdbarch_register(bfd_arch_arc, arc_gdbarch_init, arc_dump_tdep); + + /* Register ARC-specific commands with gdb. */ + + add_setshow_boolean_cmd(DEBUG_COMMAND, + no_class, + &arc_debug_target, + _("Set whether to print ARC debug messages.\n"), + _("Show whether to print ARC debug messages.\n"), + _("If set debug messages are printed.\n"), + NULL, + NULL, + &setlist, + &showlist); + + (void) add_cmd(SHOW_FRAME_COMMAND, + class_obscure, + arc_show_stack_frame_command, + _("Display the stack frame with annotation.\n" + SHOW_FRAME_COMMAND_USAGE + "<FRAME> may be the number or address of a frame.\n"), + &cmdlist); } + +/* Initialize the info structure to enable the disassembler to be used. */ + void -_initialize_arc_tdep (void) +arc_initialize_disassembler (struct disassemble_info *info) { - gdbarch_register (bfd_arch_arc, arc_gdbarch_init, arc_dump_tdep); + /* N.B. this type cast is not strictly correct: the return types differ! */ + init_disassemble_info(info, gdb_stdout, (fprintf_ftype) fprintf_filtered); + info->arch = gdbarch_bfd_arch_info(current_gdbarch)->arch; + info->mach = gdbarch_bfd_arch_info(current_gdbarch)->mach; + info->endian = gdbarch_byte_order (current_gdbarch); + info->read_memory_func = read_memory_for_disassembler; } +/******************************************************************************/ |