From: Michael Snyder Date: Wed, 27 Nov 1996 19:10:07 +0000 (+0000) Subject: Added target function calls for SH, M32R and H8300. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=dc1b349d39a95d3944428155d352ff04c3115963;p=binutils-gdb.git Added target function calls for SH, M32R and H8300. Added some generic target-independant code for managing call-dummy frames. Wed Nov 27 10:32:14 1996 Michael Snyder * breakpoint.c: DELETE command will not delete CALL_DUMMY breakpoint. * blockframe.c: Add target-independant support for managing CALL_DUMMY frames on the host side. * frame.h: Declarations for generic CALL_DUMMY frame support. * h8300-tdep.c: Add target function calls using generic frame support. * config/h8300/tm-h8300.h: config for generic target function calls. start-sanitize-m32r * m32r-tdep.c: Add target function calls using generic frame support. * config/m32r/tm-m32r.h: config for generic target function calls. end-sanitize-m32r * sh-tdep.c: Add target function calls using generic frame support. * config/sh/tm-sh.h: config for generic target function calls. start-sanitize-v850 * v850-tdep.c: Add target function calls using generic frame support. * config/v850/tm-v850.h: config for generic target function calls. end-sanitize-v850 * valops.c: ADD PUSH_RETURN_ADDRESS so that it doesn't have to be done by PUSH_ARGUMENTS when there's no CALL_DUMMY. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c184f3a4ac5..a0a64cd5252 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,24 @@ +Wed Nov 27 10:32:14 1996 Michael Snyder + + * breakpoint.c: DELETE command will not delete CALL_DUMMY breakpoint. + * blockframe.c: Add target-independant support for managing + CALL_DUMMY frames on the host side. + * frame.h: Declarations for generic CALL_DUMMY frame support. + * h8300-tdep.c: Add target function calls using generic frame support. + * config/h8300/tm-h8300.h: config for generic target function calls. +start-sanitize-m32r + * m32r-tdep.c: Add target function calls using generic frame support. + * config/m32r/tm-m32r.h: config for generic target function calls. +end-sanitize-m32r + * sh-tdep.c: Add target function calls using generic frame support. + * config/sh/tm-sh.h: config for generic target function calls. +start-sanitize-v850 + * v850-tdep.c: Add target function calls using generic frame support. + * config/v850/tm-v850.h: config for generic target function calls. +end-sanitize-v850 + * valops.c: ADD PUSH_RETURN_ADDRESS so that it doesn't have to be + done by PUSH_ARGUMENTS when there's no CALL_DUMMY. + Tue Nov 26 19:21:35 1996 Mark Alexander * config/mips/tm-mips.h (ADDR_BITS_REMOVE, TARGET_READ_SP): Define. diff --git a/gdb/blockframe.c b/gdb/blockframe.c index a55e85a9f8d..de2a30be736 100644 --- a/gdb/blockframe.c +++ b/gdb/blockframe.c @@ -1,6 +1,7 @@ /* Get info from stack frames; convert between frames, blocks, functions and pc values. - Copyright 1986, 1987, 1988, 1989, 1991, 1994 Free Software Foundation, Inc. + Copyright 1986, 1987, 1988, 1989, 1991, 1994, 1995, 1996 + Free Software Foundation, Inc. This file is part of GDB. @@ -49,7 +50,8 @@ inside_entry_file (addr) #if CALL_DUMMY_LOCATION == AT_ENTRY_POINT /* Do not stop backtracing if the pc is in the call dummy at the entry point. */ - if (PC_IN_CALL_DUMMY (addr, 0, 0)) +/* FIXME: Won't always work with zeros for the last two arguments */ + if (PC_IN_CALL_DUMMY (addr, 0, 0)) return 0; #endif return (addr >= symfile_objfile -> ei.entry_file_lowpc && @@ -68,22 +70,26 @@ int inside_main_func (pc) CORE_ADDR pc; { -struct symbol *mainsym; if (pc == 0) return 1; if (symfile_objfile == 0) return 0; - if (symfile_objfile -> ei.main_func_lowpc == 0 && - symfile_objfile -> ei.main_func_highpc == 0) + /* If the addr range is not set up at symbol reading time, set it up now. + This is for FRAME_CHAIN_VALID_ALTERNATE. I do this for coff, because + it is unable to set it up and symbol reading time. */ + + if (symfile_objfile -> ei.main_func_lowpc == INVALID_ENTRY_LOWPC && + symfile_objfile -> ei.main_func_highpc == INVALID_ENTRY_HIGHPC) { + struct symbol *mainsym; + mainsym = lookup_symbol ("main", NULL, VAR_NAMESPACE, NULL, NULL); if (mainsym && SYMBOL_CLASS(mainsym) == LOC_BLOCK) { symfile_objfile->ei.main_func_lowpc = BLOCK_START (SYMBOL_BLOCK_VALUE (mainsym)); symfile_objfile->ei.main_func_highpc = BLOCK_END (SYMBOL_BLOCK_VALUE (mainsym)); } - } return (symfile_objfile -> ei.main_func_lowpc <= pc && symfile_objfile -> ei.main_func_highpc > pc); @@ -108,6 +114,7 @@ CORE_ADDR pc; #if CALL_DUMMY_LOCATION == AT_ENTRY_POINT /* Do not stop backtracing if the pc is in the call dummy at the entry point. */ +/* FIXME: Won't always work with zeros for the last two arguments */ if (PC_IN_CALL_DUMMY (pc, 0, 0)) return 0; #endif @@ -239,9 +246,10 @@ frameless_look_for_prologue (frame) struct frame_info *frame; { CORE_ADDR func_start, after_prologue; - func_start = (get_pc_function_start (frame->pc) + FUNCTION_START_OFFSET); + func_start = get_pc_function_start (frame->pc); if (func_start) { + func_start += FUNCTION_START_OFFSET; after_prologue = func_start; #ifdef SKIP_PROLOGUE_FRAMELESS_P /* This is faster, since only care whether there *is* a prologue, @@ -655,8 +663,8 @@ find_pc_partial_function (pc, name, address, endaddr) #if defined SIGTRAMP_START if (IN_SIGTRAMP (pc, (char *)NULL)) { - cache_pc_function_low = SIGTRAMP_START; - cache_pc_function_high = SIGTRAMP_END; + cache_pc_function_low = SIGTRAMP_START (pc); + cache_pc_function_high = SIGTRAMP_END (pc); cache_pc_function_name = ""; goto return_cached_value; @@ -738,25 +746,7 @@ find_pc_partial_function (pc, name, address, endaddr) return 0; } - /* See if we're in a transfer table for Sun shared libs. - - Note the hack for Sun shared library transfer tables creates - problems for single stepping through the return path from a shared - library call if the return path includes trampoline code. - - I don't really understand the reasoning behind the magic handling - for mst_trampoline symbols. */ - -#ifdef INHIBIT_SUNSOLIB_TRANSFER_TABLE_HACK - cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol); -#else - if (msymbol -> type == mst_text || msymbol -> type == mst_file_text) - cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol); - else - /* It is a transfer table for Sun shared libraries. */ - cache_pc_function_low = pc - FUNCTION_START_OFFSET; -#endif - + cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol); cache_pc_function_name = SYMBOL_NAME (msymbol); /* Use the lesser of the next minimal symbol, or the end of the section, as @@ -860,6 +850,283 @@ sigtramp_saved_pc (frame) } #endif /* SIGCONTEXT_PC_OFFSET */ +/* + * DUMMY FRAMES + * + * The following code serves to maintain the dummy stack frames for + * inferior function calls (ie. when gdb calls into the inferior via + * call_function_by_hand). This code saves the machine state before + * the call in host memory, so it must maintain an independant stack + * and keep it consistant etc. I am attempting to make this code + * generic enough to be used by many targets. + * + * The cheapest and most generic way to do CALL_DUMMY on a new target + * is probably to define CALL_DUMMY to be empty, CALL_DUMMY_LENGTH to zero, + * and CALL_DUMMY_LOCATION to AT_ENTRY. Then you must remember to define + * PUSH_RETURN_ADDRESS, because there won't be a call instruction to do it. + */ + +static struct dummy_frame *dummy_frame_stack = NULL; + +/* Function: find_dummy_frame(pc, fp, sp) + Search the stack of dummy frames for one matching the given PC, FP and SP. + This is the work-horse for pc_in_call_dummy and read_register_dummy */ + +char * +generic_find_dummy_frame (pc, fp) + CORE_ADDR pc; + CORE_ADDR fp; +{ + struct dummy_frame * dummyframe; +#ifdef NEED_TEXT_START_END + CORE_ADDR bkpt_address; + extern CORE_ADDR text_end; +#endif + +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT + if (pc != entry_point_address ()) + return 0; +#endif /* AT_ENTRY_POINT */ + +#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END + bkpt_address = text_end - CALL_DUMMY_LENGTH + CALL_DUMMY_BREAKPOINT_OFFSET; + if (pc != bkpt_address) + return 0; +#endif /* BEFORE_TEXT_END */ + +#if CALL_DUMMY_LOCATION == AFTER_TEXT_END + bkpt_address = text_end + CALL_DUMMY_BREAKPOINT_OFFSET; + if (pc != bkpt_address) + return 0; +#endif /* AFTER_TEXT_END */ + +#if CALL_DUMMY_LOCATION == ON_STACK + /* compute the displacement from the CALL_DUMMY breakpoint + to the frame pointer */ + if (1 INNER_THAN 2) + pc += CALL_DUMMY_LENGTH - CALL_DUMMY_BREAKPOINT_OFFSET; + else + pc += CALL_DUMMY_BREAKPOINT_OFFSET; +#endif /* ON_STACK */ + + for (dummyframe = dummy_frame_stack; dummyframe != NULL; + dummyframe = dummyframe->next) + if (fp == dummyframe->fp || fp == dummyframe->sp) + { + /* The frame in question lies between the saved fp and sp, inclusive */ +#if CALL_DUMMY_LOCATION == ON_STACK + /* NOTE: a better way to do this might be simply to test whether + the pc lies between the saved (sp, fp) and CALL_DUMMY_LENGTH. + */ + + if (pc == dummyframe->fp || pc == dummyframe->sp) +#endif /* ON_STACK */ + return dummyframe->regs; + } + return 0; +} + +/* Function: pc_in_call_dummy (pc, fp) + Return true if this is a dummy frame created by gdb for an inferior call */ + +int +generic_pc_in_call_dummy (pc, fp) + CORE_ADDR pc; + CORE_ADDR fp; +{ + /* if find_dummy_frame succeeds, then PC is in a call dummy */ + return (generic_find_dummy_frame (pc, fp) != 0); +} + +/* Function: read_register_dummy + Find a saved register from before GDB calls a function in the inferior */ + +CORE_ADDR +generic_read_register_dummy (pc, fp, regno) + CORE_ADDR pc; + CORE_ADDR fp; + int regno; +{ + char *dummy_regs = generic_find_dummy_frame (pc, fp); + + if (dummy_regs) + return extract_address (&dummy_regs[REGISTER_BYTE (regno)], + REGISTER_RAW_SIZE(regno)); + else + return 0; +} + +/* Save all the registers on the dummy frame stack. Most ports save the + registers on the target stack. This results in lots of unnecessary memory + references, which are slow when debugging via a serial line. Instead, we + save all the registers internally, and never write them to the stack. The + registers get restored when the called function returns to the entry point, + where a breakpoint is laying in wait. */ + +void +generic_push_dummy_frame () +{ + struct dummy_frame *dummy_frame; + CORE_ADDR fp = (get_current_frame ())->frame; + + /* check to see if there are stale dummy frames, + perhaps left over from when a longjump took us out of a + function that was called by the debugger */ + + dummy_frame = dummy_frame_stack; + while (dummy_frame) + if (dummy_frame->fp INNER_THAN fp) /* stale -- destroy! */ + { + dummy_frame_stack = dummy_frame->next; + free (dummy_frame); + dummy_frame = dummy_frame_stack; + } + else + dummy_frame = dummy_frame->next; + + dummy_frame = xmalloc (sizeof (struct dummy_frame)); + dummy_frame->pc = read_register (PC_REGNUM); + dummy_frame->sp = read_register (SP_REGNUM); + dummy_frame->fp = fp; + read_register_bytes (0, dummy_frame->regs, REGISTER_BYTES); + dummy_frame->next = dummy_frame_stack; + dummy_frame_stack = dummy_frame; +} + +/* Function: pop_dummy_frame + Restore the machine state from a saved dummy stack frame. */ + +void +generic_pop_dummy_frame () +{ + struct dummy_frame *dummy_frame = dummy_frame_stack; + + /* FIXME: what if the first frame isn't the right one, eg.. + because one call-by-hand function has done a longjmp into another one? */ + + if (!dummy_frame) + error ("Can't pop dummy frame!"); + dummy_frame_stack = dummy_frame->next; + write_register_bytes (0, dummy_frame->regs, REGISTER_BYTES); + free (dummy_frame); +} + +/* Function: frame_chain_valid + Returns true for a user frame or a call_function_by_hand dummy frame, + and false for the CRT0 start-up frame. Purpose is to terminate backtrace */ + +int +generic_frame_chain_valid (fp, fi) + CORE_ADDR fp; + struct frame_info *fi; +{ +#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT + if (PC_IN_CALL_DUMMY(FRAME_SAVED_PC(fi), fp, fp)) + return 1; /* don't prune CALL_DUMMY frames */ + else /* fall back to default algorithm (see frame.h) */ +#endif + return (fp != 0 && !inside_entry_file (FRAME_SAVED_PC(fi))); +} + +/* Function: get_saved_register + Find register number REGNUM relative to FRAME and put its (raw, + target format) contents in *RAW_BUFFER. + + Set *OPTIMIZED if the variable was optimized out (and thus can't be + fetched). Note that this is never set to anything other than zero + in this implementation. + + Set *LVAL to lval_memory, lval_register, or not_lval, depending on + whether the value was fetched from memory, from a register, or in a + strange and non-modifiable way (e.g. a frame pointer which was + calculated rather than fetched). We will use not_lval for values + fetched from generic dummy frames. + + Set *ADDRP to the address, either in memory on as a REGISTER_BYTE + offset into the registers array. If the value is stored in a dummy + frame, set *ADDRP to zero. + + To use this implementation, define a function called + "get_saved_register" in your target code, which simply passes all + of its arguments to this function. + + The argument RAW_BUFFER must point to aligned memory. */ + +void +generic_get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) + char *raw_buffer; + int *optimized; + CORE_ADDR *addrp; + struct frame_info *frame; + int regnum; + enum lval_type *lval; +{ + CORE_ADDR addr; + struct frame_saved_regs fsr; + + if (!target_has_registers) + error ("No registers."); + + /* Normal systems don't optimize out things with register numbers. */ + if (optimized != NULL) + *optimized = 0; + + if (addrp) /* default assumption: not found in memory */ + *addrp = 0; + + /* Note: since the current frame's registers could only have been + saved by frames INTERIOR TO the current frame, we skip examining + the current frame itself: otherwise, we would be getting the + previous frame's registers which were saved by the current frame. */ + + while ((frame = frame->next) != NULL) + { + if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)) + { + if (lval) /* found it in a CALL_DUMMY frame */ + *lval = not_lval; + if (raw_buffer) + memcpy (raw_buffer, + generic_find_dummy_frame (frame->pc, frame->frame) + + REGISTER_BYTE (regnum), + REGISTER_RAW_SIZE (regnum)); + return; + } + + FRAME_FIND_SAVED_REGS(frame, fsr); + if (fsr.regs[regnum] != 0) + { + if (lval) /* found it saved on the stack */ + *lval = lval_memory; + if (regnum == SP_REGNUM) + { + if (raw_buffer) /* SP register treated specially */ + store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), + fsr.regs[regnum]); + } + else + { + if (addrp) /* any other register */ + *addrp = fsr.regs[regnum]; + if (raw_buffer) + read_memory (fsr.regs[regnum], raw_buffer, + REGISTER_RAW_SIZE (regnum)); + } + return; + } + } + + /* If we get thru the loop to this point, it means the register was + not saved in any frame. Return the actual live-register value. */ + + if (lval) /* found it in a live register */ + *lval = lval_register; + if (addrp) + *addrp = REGISTER_BYTE (regnum); + if (raw_buffer) + read_register_gen (regnum, raw_buffer); +} + void _initialize_blockframe () { diff --git a/gdb/config/h8300/tm-h8300.h b/gdb/config/h8300/tm-h8300.h index ee270b23c82..5f5f6130e4e 100644 --- a/gdb/config/h8300/tm-h8300.h +++ b/gdb/config/h8300/tm-h8300.h @@ -19,6 +19,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Contributed by Steve Chamberlain sac@cygnus.com */ +#ifdef __STDC__ +struct frame_info; +struct frame_saved_regs; +struct value; +struct type; +#endif /* 1 if debugging H8/300H application */ extern int h8300hmode; @@ -41,9 +47,9 @@ extern int h8300smode; indicate real, cached values. */ #define INIT_EXTRA_FRAME_INFO(fromleaf, fi) \ - init_extra_frame_info (fromleaf, fi) + h8300_init_extra_frame_info (fromleaf, fi) -extern void init_extra_frame_info (); +extern void h8300_init_extra_frame_info (); #define IEEE_FLOAT /* Define the bit, byte, and word ordering of the machine. */ @@ -142,10 +148,12 @@ extern CORE_ADDR h8300_skip_prologue (); to be actual register numbers as far as the user is concerned but do serve to get the desired values when passed to read_register. */ -#define FP_REGNUM 6 /* Contains address of executing stack frame */ -#define SP_REGNUM 7 /* Contains address of top of stack */ -#define CCR_REGNUM 8 /* Contains processor status */ -#define PC_REGNUM 9 /* Contains program counter */ +#define ARG0_REGNUM 0 /* first reg in which an arg may be passed */ +#define ARGLAST_REGNUM 2 /* last reg in which an arg may be passed */ +#define FP_REGNUM 6 /* Contain saddress of executing stack frame */ +#define SP_REGNUM 7 /* Contains address of top of stack */ +#define CCR_REGNUM 8 /* Contains processor status */ +#define PC_REGNUM 9 /* Contains program counter */ /* Extract from an array REGBUF containing the (raw) register state a function return value of type TYPE, and copy that, in virtual format, @@ -153,24 +161,33 @@ extern CORE_ADDR h8300_skip_prologue (); /* FIXME: Won't work with both h8/300's. */ +extern void h8300_extract_return_value PARAMS((struct type *, char *, char *)); #define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ - memcpy (VALBUF, (char *)(REGBUF), TYPE_LENGTH(TYPE)) + h8300_extract_return_value (TYPE, (char *)(REGBUF), (char *)(VALBUF)) /* Write into appropriate registers a function return value of type TYPE, given in virtual format. Assumes floats are passed in d0/d1. */ /* FIXME: Won't work with both h8/300's. */ +extern void h8300_store_return_value PARAMS((struct type *, char *)); #define STORE_RETURN_VALUE(TYPE,VALBUF) \ - write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE)) + h8300_store_return_value(TYPE, (char *) (VALBUF)) + +/* struct passing and returning stuff */ +#define STORE_STRUCT_RETURN(STRUCT_ADDR, SP) \ + write_register (0, STRUCT_ADDR) + +#define USE_STRUCT_CONVENTION(gcc_p, type) (1) /* Extract from an array REGBUF containing the (raw) register state the address in which a function should return its structure value, as a CORE_ADDR (or an expression that can be used as one). */ -/* FIXME: Won't work with both h8/300's. */ -#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(CORE_ADDR *)(REGBUF)) - +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \ + extract_address (REGBUF + REGISTER_BYTE (0), \ + REGISTER_RAW_SIZE (0)) + /* Describe the pointer in each stack frame to the previous stack frame (its caller). */ @@ -181,7 +198,6 @@ extern CORE_ADDR h8300_skip_prologue (); it means the given frame is the outermost one and has no caller. */ #define FRAME_CHAIN(FRAME) h8300_frame_chain(FRAME) -struct frame_info ; CORE_ADDR h8300_frame_chain PARAMS ((struct frame_info *)); /* In the case of the H8/300, the frame's nominal address @@ -212,7 +228,7 @@ CORE_ADDR h8300_frame_chain PARAMS ((struct frame_info *)); LOCALS1 <-SP POINTS HERE */ -#define FRAME_SAVED_PC(FRAME) frame_saved_pc(FRAME) +#define FRAME_SAVED_PC(FRAME) h8300_frame_saved_pc(FRAME) #define FRAME_ARGS_ADDRESS(fi) frame_args_address(fi) @@ -237,17 +253,9 @@ CORE_ADDR h8300_frame_chain PARAMS ((struct frame_info *)); the address we return for it IS the sp for the next frame. */ #define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ - frame_find_saved_regs(frame_info, &(frame_saved_regs)) + h8300_frame_find_saved_regs(frame_info, &(frame_saved_regs)) -/* Push an empty stack frame, to record the current PC, etc. */ - -/*#define PUSH_DUMMY_FRAME { h8300_push_dummy_frame (); }*/ - -/* Discard from the stack the innermost frame, restoring all registers. */ - -#define POP_FRAME { h8300_pop_frame (); } - typedef unsigned short INSN_WORD; @@ -259,3 +267,37 @@ typedef unsigned short INSN_WORD; #define NOP { 0x01, 0x80} /* A sleep insn */ #define BELIEVE_PCC_PROMOTION 1 + +/* + * CALL_DUMMY stuff: + */ + +#define CALL_DUMMY {0} +#define CALL_DUMMY_LENGTH (0) +#define CALL_DUMMY_ADDRESS() entry_point_address () +#define CALL_DUMMY_LOCATION AT_ENTRY_POINT +#define CALL_DUMMY_START_OFFSET (0) +#define CALL_DUMMY_BREAKPOINT_OFFSET (0) + +extern CORE_ADDR h8300_push_arguments PARAMS ((int nargs, + struct value **args, + CORE_ADDR sp, + unsigned char struct_return, + CORE_ADDR struct_addr)); +extern CORE_ADDR h8300_push_return_address PARAMS ((CORE_ADDR, CORE_ADDR)); + +#define PC_IN_CALL_DUMMY(PC, SP, FP) generic_pc_in_call_dummy (PC, SP) +#define FIX_CALL_DUMMY(DUMMY, START_SP, FUNADDR, NARGS, ARGS, TYPE, GCCP) +#define PUSH_ARGUMENTS(NARGS, ARGS, SP, STRUCT_RETURN, STRUCT_ADDR) \ + (SP) = h8300_push_arguments (NARGS, ARGS, SP, STRUCT_RETURN, STRUCT_ADDR) +/* Push an empty stack frame, to record the current PC, etc. */ +#define PUSH_DUMMY_FRAME generic_push_dummy_frame () +/* Discard from the stack the innermost frame, restoring all registers. */ +#define POP_FRAME h8300_pop_frame () +#define PUSH_RETURN_ADDRESS(PC, SP) h8300_push_return_address (PC, SP) + +/* override the standard get_saved_register function with + one that takes account of generic CALL_DUMMY frames */ +#define GET_SAVED_REGISTER + + diff --git a/gdb/config/m32r/tm-m32r.h b/gdb/config/m32r/tm-m32r.h index 8eac68e00f9..c9342e13ec1 100644 --- a/gdb/config/m32r/tm-m32r.h +++ b/gdb/config/m32r/tm-m32r.h @@ -128,16 +128,15 @@ m32r_frame_find_saved_regs PARAMS ((struct frame_info *fi, extern CORE_ADDR m32r_frame_chain PARAMS ((struct frame_info *fi)); /* mvs_check FRAME_CHAIN */ -#define FRAME_CHAIN(fi) m32r_frame_chain (fi) +#define FRAME_CHAIN(fi) m32r_frame_chain (fi) -extern int generic_frame_chain_valid PARAMS ((CORE_ADDR, struct frame_info *)); -#define FRAME_CHAIN_VALID(fp, frame) (generic_frame_chain_valid (fp, frame)) +#define FRAME_CHAIN_VALID(fp, frame) generic_frame_chain_valid (fp, frame) extern CORE_ADDR m32r_find_callers_reg PARAMS ((struct frame_info *fi, int regnum)); extern CORE_ADDR m32r_frame_saved_pc PARAMS((struct frame_info *)); /* mvs_check FRAME_SAVED_PC */ -#define FRAME_SAVED_PC(fi) (m32r_frame_saved_pc (fi)) +#define FRAME_SAVED_PC(fi) m32r_frame_saved_pc (fi) /* mvs_check EXTRACT_RETURN_VALUE */ #define EXTRACT_RETURN_VALUE(TYPE, REGBUF, VALBUF) \ @@ -183,32 +182,16 @@ extern CORE_ADDR m32r_skip_prologue PARAMS ((CORE_ADDR pc)); (TYPE_LENGTH (TYPE) > 8) #define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \ - (extract_address (REGBUF + REGISTER_BYTE (V0_REGNUM), \ - REGISTER_RAW_SIZE (V0_REGNUM))) + extract_address (REGBUF + REGISTER_BYTE (V0_REGNUM), \ + REGISTER_RAW_SIZE (V0_REGNUM)) #define REG_STRUCT_HAS_ADDR(gcc_p,type) (TYPE_LENGTH (type) > 8) - - - /* generic dummy frame stuff */ -extern CORE_ADDR generic_read_register_dummy PARAMS ((struct frame_info *fi, - int regno)); - -extern void generic_push_dummy_frame PARAMS ((void)); -extern void generic_pop_dummy_frame PARAMS ((void)); - -extern int generic_pc_in_call_dummy PARAMS ((CORE_ADDR pc, - CORE_ADDR fp, - CORE_ADDR sp)); -extern char * generic_find_dummy_frame PARAMS ((CORE_ADDR pc, - CORE_ADDR fp, - CORE_ADDR sp)); - -#define PUSH_DUMMY_FRAME (generic_push_dummy_frame ()) -#define PC_IN_CALL_DUMMY(PC, SP, FP) (generic_pc_in_call_dummy (PC, SP, FP)) +#define PUSH_DUMMY_FRAME generic_push_dummy_frame () +#define PC_IN_CALL_DUMMY(PC, SP, FP) generic_pc_in_call_dummy (PC, SP) /* target-specific dummy_frame stuff */ @@ -220,7 +203,7 @@ extern struct frame_info *m32r_pop_frame PARAMS ((struct frame_info *frame)); /* mvs_no_check STACK_ALIGN */ /* #define STACK_ALIGN(x) ((x + 3) & ~3) */ -extern void m32r_push_return_address PARAMS ((CORE_ADDR)); +extern CORE_ADDR m32r_push_return_address PARAMS ((CORE_ADDR, CORE_ADDR)); extern CORE_ADDR m32r_push_arguments PARAMS ((int nargs, struct value **args, CORE_ADDR sp, @@ -233,18 +216,41 @@ extern CORE_ADDR m32r_push_arguments PARAMS ((int nargs, #define PUSH_ARGUMENTS(NARGS, ARGS, SP, STRUCT_RETURN, STRUCT_ADDR) \ (SP) = m32r_push_arguments (NARGS, ARGS, SP, STRUCT_RETURN, STRUCT_ADDR) - - -#define CALL_DUMMY { } /* mvs_no_check CALL_DUMMY */ -#define CALL_DUMMY_ADDRESS() (entry_point_address ()) /* mvs_no_check CALL_DUMMY_ADDRESS */ - -#define CALL_DUMMY_START_OFFSET (0) /* mvs_no_check CALL_DUMMY_START_OFFSET */ -#define CALL_DUMMY_BREAKPOINT_OFFSET (0) /* mvs_no_check CALL_DUMMY_BREAKPOINT_OFFSET */ -#define CALL_DUMMY_LENGTH (0) /* mvs_no_check CALL_DUMMY_LENGTH */ - -/* mvs_no_check FIX_CALL_DUMMY */ -#define FIX_CALL_DUMMY(DUMMY1, START_SP, FUNADDR, NARGS, \ - ARGS, VALUE_TYPE, USING_GCC) - -#define CALL_DUMMY_LOCATION AT_ENTRY_POINT -#define PUSH_RETURN_ADDRESS(pc) (m32r_push_return_address (pc)) +#define PUSH_RETURN_ADDRESS(PC, SP) m32r_push_return_address (PC, SP) + +/* override the standard get_saved_register function with + one that takes account of generic CALL_DUMMY frames */ +#define GET_SAVED_REGISTER + +#if 1 +#define CALL_DUMMY {0} +#define CALL_DUMMY_LENGTH (0) +#define CALL_DUMMY_START_OFFSET (0) +#define CALL_DUMMY_BREAKPOINT_OFFSET (0) +#define FIX_CALL_DUMMY(DUMMY1, STARTADDR, FUNADDR, NARGS, ARGS, TYPE, GCCP) +#define CALL_DUMMY_LOCATION AT_ENTRY_POINT +#define CALL_DUMMY_ADDRESS() entry_point_address () + +#else +/* +/* Use these defines if, for whatever reason, you want to use a + genuine call_dummy sequence (A sequence of machine instructions + that GDB will write into the target address space, usually on the + stack, for calling a function in the inferior): + + This sequence of words defines the instructions: + + ld24 R8, + jl R8 + nop + trap +*/ +#define CALL_DUMMY { 0xe8000000, 0x1ec87000, 0x10f110f1 } +#define CALL_DUMMY_LENGTH (12) +#define CALL_DUMMY_START_OFFSET (0) +#define CALL_DUMMY_BREAKPOINT_OFFSET (8) +#define FIX_CALL_DUMMY(DUMMY1, STARTADDR, FUNADDR, NARGS, ARGS, TYPE, GCCP) \ + m32r_fix_call_dummy (DUMMY1, STARTADDR, FUNADDR, NARGS, ARGS, TYPE, GCCP) +#define CALL_DUMMY_LOCATION ON_STACK +#define NEED_TEXT_START_END +#endif diff --git a/gdb/config/sh/tm-sh.h b/gdb/config/sh/tm-sh.h index 2b879d1638c..5347d72ceb4 100644 --- a/gdb/config/sh/tm-sh.h +++ b/gdb/config/sh/tm-sh.h @@ -55,8 +55,7 @@ extern CORE_ADDR sh_skip_prologue (); The return address is the value saved in the PR register + 4 */ -#define SAVED_PC_AFTER_CALL(frame) \ - (ADDR_BITS_REMOVE(read_register(PR_REGNUM))) +#define SAVED_PC_AFTER_CALL(frame) (ADDR_BITS_REMOVE(read_register(PR_REGNUM))) /* Stack grows downward. */ @@ -110,7 +109,7 @@ extern CORE_ADDR sh_skip_prologue (); #define REGISTER_VIRTUAL_TYPE(N) \ ((((N) >= FP0_REGNUM && (N) <= FP15_REGNUM) \ || (N) == FPUL_REGNUM) \ - ? builtin_type_float : builtin_type_int) + ? builtin_type_float : builtin_type_int) /* Initializer for an array of names of registers. Entries beyond the first NUM_REGS are ignored. */ @@ -189,8 +188,9 @@ extern void sh_extract_return_value PARAMS ((struct type *, void *, void *)); the address in which a function should return its structure value, as a CORE_ADDR (or an expression that can be used as one). */ -#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(CORE_ADDR *)(REGBUF)) - +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \ + extract_address (REGBUF, REGISTER_RAW_SIZE (0)) + /* Define other aspects of the stack frame. we keep a copy of the worked out return pc lying around, since it @@ -242,43 +242,63 @@ extern void sh_frame_find_saved_regs PARAMS ((struct frame_info *fi, typedef unsigned short INSN_WORD; -extern CORE_ADDR generic_read_register_dummy PARAMS ((struct frame_info *, - int regno)); - -extern void generic_push_dummy_frame PARAMS ((void)); -extern void generic_pop_dummy_frame PARAMS ((void)); - -extern int generic_pc_in_call_dummy PARAMS ((CORE_ADDR pc, - CORE_ADDR fp, - CORE_ADDR sp)); -extern char * generic_find_dummy_frame PARAMS ((CORE_ADDR pc, - CORE_ADDR fp, - CORE_ADDR sp)); - -extern void sh_push_return_address PARAMS ((CORE_ADDR)); extern CORE_ADDR sh_push_arguments PARAMS ((int nargs, struct value **args, CORE_ADDR sp, unsigned char struct_return, CORE_ADDR struct_addr)); -extern int generic_frame_chain_valid PARAMS((CORE_ADDR, struct frame_info *)); +#if 0 +/* Use these defines if, for whatever reason, you want to use a + genuine call_dummy sequence (A sequence of machine instructions + that GDB will write into the target address space, usually on the + stack, for calling a function in the inferior): + + This sequence of words defines the instructions: + mov.w @(2,PC), R8 + jsr @R8 + nop + trap + -#define CALL_DUMMY { } + Note that the destination address is actually written into a word + 8 bytes after the start of the CALL_DUMMY. The first instruction + loads it from here using PC-relative addressing. Note also the + NOP that must follow the jsr instruction to fill up the delay slot. +*/ + +#define CALL_DUMMY { 0xd801480b, 0x0009c3c3, 0x32323232, } +#define CALL_DUMMY_LENGTH (12) +#define CALL_DUMMY_START_OFFSET (0) +#define CALL_DUMMY_BREAKPOINT_OFFSET (6) +#define FIX_CALL_DUMMY(DUMMY, STARTADDR, FUNADDR, NARGS, ARGS, TYPE, GCCP) \ + sh_fix_call_dummy(DUMMY, STARTADDR, FUNADDR, NARGS, ARGS, TYPE, GCCP) +#define CALL_DUMMY_LOCATION ON_STACK + +#else /* These defines write NO instructions into the inferior process, + and are therefore preferred because they make target calls faster. */ +#define CALL_DUMMY {0} #define CALL_DUMMY_LENGTH (0) #define CALL_DUMMY_START_OFFSET (0) #define CALL_DUMMY_BREAKPOINT_OFFSET (0) +#define FIX_CALL_DUMMY(DUMMY, STARTADDR, FUNADDR, NARGS, ARGS, TYPE, GCCP) #define CALL_DUMMY_LOCATION AT_ENTRY_POINT -#define CALL_DUMMY_ADDRESS() (entry_point_address ()) -#define PUSH_RETURN_ADDRESS(PC) (sh_push_return_address (PC)) -#define FRAME_CHAIN(FRAME) (sh_frame_chain(FRAME)) -#define PUSH_DUMMY_FRAME (generic_push_dummy_frame ()) -#define FRAME_CHAIN_VALID(FP, FRAME) (generic_frame_chain_valid (FP, FRAME)) -#define PC_IN_CALL_DUMMY(PC, SP, FP) (generic_pc_in_call_dummy (PC, SP, FP)) -#define FIX_CALL_DUMMY(DUMMYNAME, STARTADDR, FUNADDR, NARGS, ARGS, TYPE, GCCP) +#define CALL_DUMMY_ADDRESS() entry_point_address () +extern CORE_ADDR sh_push_return_address PARAMS ((CORE_ADDR, CORE_ADDR)); +#define PUSH_RETURN_ADDRESS(PC, SP) sh_push_return_address (PC, SP) +#endif + +#define FRAME_CHAIN(FRAME) sh_frame_chain(FRAME) +#define PUSH_DUMMY_FRAME generic_push_dummy_frame () +#define FRAME_CHAIN_VALID(FP, FRAME) generic_frame_chain_valid (FP, FRAME) +#define PC_IN_CALL_DUMMY(PC, SP, FP) generic_pc_in_call_dummy (PC, SP) #define PUSH_ARGUMENTS(NARGS, ARGS, SP, STRUCT_RETURN, STRUCT_ADDR) \ - (SP) = sh_push_arguments (NARGS, ARGS, SP, STRUCT_RETURN, STRUCT_ADDR) + (SP) = sh_push_arguments (NARGS, ARGS, SP, STRUCT_RETURN, STRUCT_ADDR) + +/* override the standard get_saved_register function with + one that takes account of generic CALL_DUMMY frames */ +#define GET_SAVED_REGISTER /* Discard from the stack the innermost frame, restoring all saved registers. */ diff --git a/gdb/config/v850/tm-v850.h b/gdb/config/v850/tm-v850.h index eec09119946..1bc61c4c227 100644 --- a/gdb/config/v850/tm-v850.h +++ b/gdb/config/v850/tm-v850.h @@ -85,16 +85,18 @@ extern void v850_frame_find_saved_regs PARAMS ((struct frame_info *fi, struct fr extern CORE_ADDR v850_frame_chain PARAMS ((struct frame_info *fi)); #define FRAME_CHAIN(fi) v850_frame_chain (fi) +#define FRAME_CHAIN_VALID(FP, FI) generic_frame_chain_valid (FP, FI) extern CORE_ADDR v850_find_callers_reg PARAMS ((struct frame_info *fi, int regnum)); -#define FRAME_SAVED_PC(fi) (v850_find_callers_reg (fi, RP_REGNUM)) +extern CORE_ADDR v850_frame_saved_pc PARAMS ((struct frame_info *)); +#define FRAME_SAVED_PC(FI) (v850_frame_saved_pc (FI)) #define EXTRACT_RETURN_VALUE(TYPE, REGBUF, VALBUF) \ memcpy (VALBUF, REGBUF + REGISTER_BYTE (V0_REGNUM), TYPE_LENGTH (TYPE)) #define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \ - (extract_address (REGBUF + REGISTER_BYTE (V0_REGNUM), \ - REGISTER_RAW_SIZE (V0_REGNUM))) + extract_address (REGBUF + REGISTER_BYTE (V0_REGNUM), \ + REGISTER_RAW_SIZE (V0_REGNUM)) #define STORE_RETURN_VALUE(TYPE, VALBUF) \ write_register_bytes(REGISTER_BYTE (V0_REGNUM), VALBUF, TYPE_LENGTH (TYPE)); @@ -108,23 +110,41 @@ extern CORE_ADDR v850_skip_prologue PARAMS ((CORE_ADDR pc)); #define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) #define FRAME_NUM_ARGS(val, fi) ((val) = -1) -extern struct frame_info *v850_pop_frame PARAMS ((struct frame_info *frame)); +extern void v850_pop_frame PARAMS ((struct frame_info *frame)); #define POP_FRAME v850_pop_frame (get_current_frame ()) -#define CALL_DUMMY { 0 } - -#define CALL_DUMMY_START_OFFSET (0) - +#if 0 +/* Use these defines if, for whatever reason, you want to use a + genuine call_dummy sequence (A sequence of machine instructions + that GDB will write into the target address space, usually on the + stack, for calling a function in the inferior): + + This sequence of words defines the instructions: + + jarl , r31 + trap +*/ +#define CALL_DUMMY { 0x0000ff80, 0xffffffff } +#define CALL_DUMMY_LENGTH (8) +#define CALL_DUMMY_START_OFFSET (0) +#define CALL_DUMMY_BREAKPOINT_OFFSET (4) +#define CALL_DUMMY_LOCATION ON_STACK +#define FIX_CALL_DUMMY(DUMMY, START, FUNADDR, NARGS, ARGS, TYPE, GCCP) \ + v850_fix_call_dummy (DUMMY, START, FUNADDR, NARGS, ARGS, TYPE, GCCP); + +#else /* These defines write NO instructions into the inferior process, + and are therefore preferred because they make target calls faster. */ +#define CALL_DUMMY {0} +#define CALL_DUMMY_START_OFFSET (0) #define CALL_DUMMY_BREAKPOINT_OFFSET (0) +#define CALL_DUMMY_LOCATION AT_ENTRY_POINT +#define FIX_CALL_DUMMY(DUMMY, START, FUNADDR, NARGS, ARGS, TYPE, GCCP) +#define CALL_DUMMY_ADDRESS() entry_point_address () +extern CORE_ADDR v850_push_return_address PARAMS ((CORE_ADDR, CORE_ADDR)); +#define PUSH_RETURN_ADDRESS(PC, SP) v850_push_return_address (PC, SP) +#endif -extern void v850_push_dummy_frame PARAMS ((void)); -#define PUSH_DUMMY_FRAME v850_push_dummy_frame () - -#define FIX_CALL_DUMMY(DUMMY1, START_SP, FUNADDR, NARGS, ARGS, VALUE_TYPE, USING_GCC) - -#define CALL_DUMMY_LOCATION AT_ENTRY_POINT - -#define STACK_ALIGN(x) ((x + 3) & ~3) +#define PUSH_DUMMY_FRAME generic_push_dummy_frame () extern CORE_ADDR v850_push_arguments PARAMS ((int nargs, struct value **args, CORE_ADDR sp, @@ -135,14 +155,16 @@ v850_push_arguments PARAMS ((int nargs, struct value **args, CORE_ADDR sp, #define STORE_STRUCT_RETURN(STRUCT_ADDR, SP) -#define CALL_DUMMY_ADDRESS() (entry_point_address ()) -extern int v850_pc_in_call_dummy PARAMS ((CORE_ADDR pc)); -#define PC_IN_CALL_DUMMY(PC, SP, FP) v850_pc_in_call_dummy (PC) +#define PC_IN_CALL_DUMMY(PC, SP, FP) generic_pc_in_call_dummy (PC, SP) #define USE_STRUCT_CONVENTION(GCC_P, TYPE) \ (TYPE_NFIELDS (TYPE) > 1 || TYPE_LENGTH (TYPE) > 4) +/* override the default get_saved_register function with + one that takes account of generic CALL_DUMMY frames */ +#define GET_SAVED_REGISTER + /* Define this for Wingdb */ #define TARGET_V850 diff --git a/gdb/h8300-tdep.c b/gdb/h8300-tdep.c index e172e3a7be7..df179bb377d 100644 --- a/gdb/h8300-tdep.c +++ b/gdb/h8300-tdep.c @@ -33,6 +33,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gdb_string.h" #include "value.h" +extern int h8300hmode, h8300smode; #undef NUM_REGS #define NUM_REGS 11 @@ -54,7 +55,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ static CORE_ADDR examine_prologue (); static void set_machine_hook PARAMS ((char *filename)); -void frame_find_saved_regs (); +void h8300_frame_find_saved_regs (); + CORE_ADDR h8300_skip_prologue (start_pc) CORE_ADDR start_pc; @@ -150,7 +152,14 @@ CORE_ADDR h8300_frame_chain (thisframe) struct frame_info *thisframe; { - frame_find_saved_regs (thisframe, (struct frame_saved_regs *) 0); + if (PC_IN_CALL_DUMMY(thisframe->pc, thisframe->frame, thisframe->frame)) + { /* initialize the from_pc now */ + thisframe->from_pc = generic_read_register_dummy (thisframe->pc, + thisframe->frame, + PC_REGNUM); + return thisframe->frame; + } + h8300_frame_find_saved_regs (thisframe, (struct frame_saved_regs *) 0); return thisframe->fsr->regs[SP_REGNUM]; } @@ -164,7 +173,7 @@ h8300_frame_chain (thisframe) it is fairly expensive. */ void -frame_find_saved_regs (fi, fsr) +h8300_frame_find_saved_regs (fi, fsr) struct frame_info *fi; struct frame_saved_regs *fsr; { @@ -183,6 +192,12 @@ frame_find_saved_regs (fi, fsr) fi->fsr = cache_fsr; + if (PC_IN_CALL_DUMMY(fi->pc, fi->frame, fi->frame)) + { /* no more to do. */ + if (fsr) + *fsr = *fi->fsr; + return; + } /* Find the start and end of the function prologue. If the PC is in the function prologue, we only consider the part that has executed already. */ @@ -378,7 +393,7 @@ examine_prologue (ip, limit, after_prolog_fp, fsr, fi) /* Rememeber any others too */ in_frame[PC_REGNUM] = 0; - + if (have_fp) /* We keep the old FP in the SP spot */ fsr->regs[SP_REGNUM] = read_memory_unsigned_integer (fsr->regs[6], BINWORD); @@ -389,7 +404,7 @@ examine_prologue (ip, limit, after_prolog_fp, fsr, fi) } void -init_extra_frame_info (fromleaf, fi) +h8300_init_extra_frame_info (fromleaf, fi) int fromleaf; struct frame_info *fi; { @@ -397,6 +412,10 @@ init_extra_frame_info (fromleaf, fi) fi->args_pointer = 0; /* Unknown */ fi->locals_pointer = 0; /* Unknown */ fi->from_pc = 0; + if (PC_IN_CALL_DUMMY(fi->pc, fi->frame, fi->frame)) + { /* anything special to do? */ + return; + } } /* Return the saved PC from this frame. @@ -405,16 +424,21 @@ init_extra_frame_info (fromleaf, fi) just use the register SRP_REGNUM itself. */ CORE_ADDR -frame_saved_pc (frame) +h8300_frame_saved_pc (frame) struct frame_info *frame; { - return frame->from_pc; + if (PC_IN_CALL_DUMMY(frame->pc, frame->frame, frame->frame)) + return generic_read_register_dummy (frame->pc, frame->frame, PC_REGNUM); + else + return frame->from_pc; } CORE_ADDR frame_locals_address (fi) struct frame_info *fi; { + if (PC_IN_CALL_DUMMY(fi->pc, fi->frame, fi->frame)) + return (CORE_ADDR) 0; /* Not sure what else to do... */ if (!fi->locals_pointer) { struct frame_saved_regs ignore; @@ -432,6 +456,8 @@ CORE_ADDR frame_args_address (fi) struct frame_info *fi; { + if (PC_IN_CALL_DUMMY(fi->pc, fi->frame, fi->frame)) + return (CORE_ADDR) 0; /* Not sure what else to do... */ if (!fi->args_pointer) { struct frame_saved_regs ignore; @@ -443,6 +469,166 @@ frame_args_address (fi) return fi->args_pointer; } +/* Function: push_arguments + Setup the function arguments for calling a function in the inferior. + + On the Hitachi H8/300 architecture, there are three registers (R0 to R2) + which are dedicated for passing function arguments. Up to the first + three arguments (depending on size) may go into these registers. + The rest go on the stack. + + Arguments that are smaller than WORDSIZE bytes will still take up a + whole register or a whole WORDSIZE word on the stack, and will be + right-justified in the register or the stack word. This includes + chars and small aggregate types. Note that WORDSIZE depends on the + cpu type. + + Arguments that are larger than WORDSIZE bytes will be split between + two or more registers as available, but will NOT be split between a + register and the stack. + + An exceptional case exists for struct arguments (and possibly other + aggregates such as arrays) -- if the size is larger than WORDSIZE + bytes but not a multiple of WORDSIZE bytes. In this case the + argument is never split between the registers and the stack, but + instead is copied in its entirety onto the stack, AND also copied + into as many registers as there is room for. In other words, space + in registers permitting, two copies of the same argument are passed + in. As far as I can tell, only the one on the stack is used, + although that may be a function of the level of compiler + optimization. I suspect this is a compiler bug. Arguments of + these odd sizes are left-justified within the word (as opposed to + arguments smaller than WORDSIZE bytes, which are right-justified). + + If the function is to return an aggregate type such as a struct, + the caller must allocate space into which the callee will copy the + return value. In this case, a pointer to the return value location + is passed into the callee in register R0, which displaces one of + the other arguments passed in via registers R0 to R2. */ + +CORE_ADDR +h8300_push_arguments(nargs, args, sp, struct_return, struct_addr) + int nargs; + struct value **args; + CORE_ADDR sp; + unsigned char struct_return; + CORE_ADDR struct_addr; +{ + int stack_align, stack_alloc, stack_offset; + int wordsize; + int argreg; + int argnum; + struct type *type; + CORE_ADDR regval; + char *val; + char valbuf[4]; + int len; + + if (h8300hmode || h8300smode) + { + stack_align = 3; + wordsize = 4; + } + else + { + stack_align = 1; + wordsize = 2; + } + + /* first force sp to a n-byte alignment */ + sp = sp & ~stack_align; + + /* Now make sure there's space on the stack */ + for (argnum = 0, stack_alloc = 0; + argnum < nargs; argnum++) + stack_alloc += ((TYPE_LENGTH(VALUE_TYPE(args[argnum])) + stack_align) + & ~stack_align); + sp -= stack_alloc; /* make room on stack for args */ + /* we may over-allocate a little here, but that won't hurt anything */ + + argreg = ARG0_REGNUM; + if (struct_return) /* "struct return" pointer takes up one argreg */ + { + write_register (argreg++, struct_addr); + } + + /* Now load as many as possible of the first arguments into + registers, and push the rest onto the stack. There are 3N bytes + in three registers available. Loop thru args from first to last. */ + + for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++) + { + type = VALUE_TYPE (args[argnum]); + len = TYPE_LENGTH (type); + memset(valbuf, 0, sizeof(valbuf)); + if (len < wordsize) + { + /* the purpose of this is to right-justify the value within the word */ + memcpy(valbuf + (wordsize - len), + (char *) VALUE_CONTENTS (args[argnum]), len); + val = valbuf; + } + else + val = (char *) VALUE_CONTENTS (args[argnum]); + + if (len > (ARGLAST_REGNUM+1 - argreg) * REGISTER_RAW_SIZE(ARG0_REGNUM) || + (len > wordsize && (len & stack_align) != 0)) + { /* passed on the stack */ + write_memory (sp + stack_offset, val, + len < wordsize ? wordsize : len); + stack_offset += (len + stack_align) & ~stack_align; + } + /* NOTE WELL!!!!! This is not an "else if" clause!!! + That's because some *&^%$ things get passed on the stack + AND in the registers! */ + if (len <= (ARGLAST_REGNUM+1 - argreg) * REGISTER_RAW_SIZE(ARG0_REGNUM)) + while (len > 0) + { /* there's room in registers */ + regval = extract_address (val, wordsize); + write_register (argreg, regval); + len -= wordsize; + val += wordsize; + argreg++; + } + } + return sp; +} + +/* Function: push_return_address + Setup the return address for a dummy frame, as called by + call_function_by_hand. Only necessary when you are using an + empty CALL_DUMMY, ie. the target will not actually be executing + a JSR/BSR instruction. */ + +CORE_ADDR +h8300_push_return_address (pc, sp) + CORE_ADDR pc; + CORE_ADDR sp; +{ + unsigned char buf[4]; + int wordsize; + + if (h8300hmode || h8300smode) + wordsize = 4; + else + wordsize = 2; + +#if CALL_DUMMY_LOCATION != AT_ENTRY_POINT + pc = pc - CALL_DUMMY_START_OFFSET + CALL_DUMMY_BREAKPOINT_OFFSET; +#else + pc = CALL_DUMMY_ADDRESS (); +#endif /* CALL_DUMMY_LOCATION */ + sp -= wordsize; + store_unsigned_integer (buf, wordsize, pc); + write_memory (sp, buf, wordsize); + return sp; +} + +/* Function: pop_frame + Restore the machine to the state it had before the current frame + was created. Usually used either by the "RETURN" command, or by + call_function_by_hand after the dummy_frame is finished. */ + void h8300_pop_frame () { @@ -450,23 +636,129 @@ h8300_pop_frame () struct frame_saved_regs fsr; struct frame_info *frame = get_current_frame (); - get_frame_saved_regs (frame, &fsr); - - for (regnum = 0; regnum < 8; regnum++) + if (PC_IN_CALL_DUMMY(frame->pc, frame->frame, frame->frame)) { - /* Don't forget SP_REGNUM is a frame_saved_regs struct is the - actual value we want, not the address of the value we want. */ - if (fsr.regs[regnum] && regnum != SP_REGNUM) - write_register (regnum, read_memory_integer(fsr.regs[regnum], BINWORD)); - else if (fsr.regs[regnum] && regnum == SP_REGNUM) - write_register (regnum, fsr.regs[regnum]); + generic_pop_dummy_frame(); } + else + { + get_frame_saved_regs (frame, &fsr); - /* Don't forget the update the PC too! */ - write_pc (frame->from_pc); + for (regnum = 0; regnum < 8; regnum++) + { + /* Don't forget SP_REGNUM is a frame_saved_regs struct is the + actual value we want, not the address of the value we want. */ + if (fsr.regs[regnum] && regnum != SP_REGNUM) + write_register (regnum, + read_memory_integer(fsr.regs[regnum], BINWORD)); + else if (fsr.regs[regnum] && regnum == SP_REGNUM) + write_register (regnum, frame->frame + 2 * BINWORD); + } + + /* Don't forget the update the PC too! */ + write_pc (frame->from_pc); + } flush_cached_frames (); } +/* Function: extract_return_value + Figure out where in REGBUF the called function has left its return value. + Copy that into VALBUF. Be sure to account for CPU type. */ + +void +h8300_extract_return_value (type, regbuf, valbuf) + struct type *type; + char *regbuf; + char *valbuf; +{ + int wordsize, len; + + if (h8300smode || h8300hmode) + wordsize = 4; + else + wordsize = 2; + + len = TYPE_LENGTH(type); + + switch (len) { + case 1: /* (char) */ + case 2: /* (short), (int) */ + memcpy (valbuf, regbuf + REGISTER_BYTE(0) + (wordsize - len), len); + break; + case 4: /* (long), (float) */ + if (h8300smode || h8300hmode) + { + memcpy (valbuf, regbuf + REGISTER_BYTE(0), 4); + } + else + { + memcpy (valbuf, regbuf + REGISTER_BYTE(0), 2); + memcpy (valbuf+2, regbuf + REGISTER_BYTE(1), 2); + } + break; + case 8: /* (double) (doesn't seem to happen, which is good, + because this almost certainly isn't right. */ + error ("I don't know how a double is returned."); + break; + } +} + +/* Function: store_return_value + Place the appropriate value in the appropriate registers. + Primarily used by the RETURN command. */ + +void +h8300_store_return_value (type, valbuf) + struct type *type; + char *valbuf; +{ + int wordsize, len, regval; + + if (h8300hmode || h8300smode) + wordsize = 4; + else + wordsize = 2; + + len = TYPE_LENGTH(type); + switch (len) { + case 1: /* char */ + case 2: /* short, int */ + regval = extract_address(valbuf, len); + write_register (0, regval); + break; + case 4: /* long, float */ + regval = extract_address(valbuf, len); + if (h8300smode || h8300hmode) + { + write_register (0, regval); + } + else + { + write_register (0, regval >> 16); + write_register (1, regval & 0xffff); + } + break; + case 8: /* presumeably double, but doesn't seem to happen */ + error ("I don't know how to return a double."); + break; + } +} + +/* Function: get_saved_register + Just call the generic_get_saved_register function. */ + +void +get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) + char *raw_buffer; + int *optimized; + CORE_ADDR *addrp; + struct frame_info *frame; + int regnum; + enum lval_type *lval; +{ + generic_get_saved_register (raw_buffer, optimized, addrp, + frame, regnum, lval); +} struct cmd_list_element *setmemorylist; @@ -537,7 +829,8 @@ void _initialize_h8300m () { add_prefix_cmd ("machine", no_class, set_machine, - "set the machine type", &setmemorylist, "set machine ", 0, + "set the machine type", + &setmemorylist, "set machine ", 0, &setlist); add_cmd ("h8300", class_support, h8300_command, diff --git a/gdb/m32r-tdep.c b/gdb/m32r-tdep.c index 1e6ec8d7dfb..c9dd5dfa9b7 100644 --- a/gdb/m32r-tdep.c +++ b/gdb/m32r-tdep.c @@ -28,26 +28,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gdbcore.h" #include "symfile.h" -struct dummy_frame -{ - struct dummy_frame *next; - - CORE_ADDR fp; - CORE_ADDR sp; - CORE_ADDR rp; - CORE_ADDR pc; -}; +/* Function: frame_find_saved_regs + Return the frame_saved_regs structure for the frame. + Doesn't really work for dummy frames, but it does pass back + an empty frame_saved_regs, so I guess that's better than total failure */ void m32r_frame_find_saved_regs PARAMS ((struct frame_info *fi, struct frame_saved_regs *regaddr)) { - *regaddr = fi->fsr; + memcpy(regaddr, &fi->fsr, sizeof(struct frame_saved_regs)); } -static struct dummy_frame *dummy_frame_stack = NULL; - -/* Find end of function prologue */ +/* Function: skip_prologue + Find end of function prologue */ CORE_ADDR m32r_skip_prologue (pc) @@ -75,11 +69,11 @@ m32r_skip_prologue (pc) return pc; } -/* This function decodes the target function prologue to determine +/* Function: scan_prologue + This function decodes the target function prologue to determine 1) the size of the stack frame, and 2) which registers are saved on it. It saves the offsets of saved regs in the frame_saved_regs argument, - and returns the frame size. -*/ + and returns the frame size. */ static unsigned long m32r_scan_prologue (fi, fsr) @@ -156,12 +150,12 @@ m32r_scan_prologue (fi, fsr) return framesize; } -/* This function actually figures out the frame address for a given pc and +/* Function: init_extra_frame_info + This function actually figures out the frame address for a given pc and sp. This is tricky on the m32r because we sometimes don't use an explicit frame pointer, and the previous stack pointer isn't necessarily recorded on the stack. The only reliable way to get this info is to - examine the prologue. -*/ + examine the prologue. */ void m32r_init_extra_frame_info (fi) @@ -173,73 +167,77 @@ m32r_init_extra_frame_info (fi) fi->pc = FRAME_SAVED_PC (fi->next); memset (fi->fsr.regs, '\000', sizeof fi->fsr.regs); - fi->using_frame_pointer = 0; - fi->framesize = m32r_scan_prologue (fi, &fi->fsr); -#if 0 - if (PC_IN_CALL_DUMMY (fi->pc, NULL, NULL)) - fi->frame = dummy_frame_stack->sp; + + if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) + { + /* We need to setup fi->frame here because run_stack_dummy gets it wrong + by assuming it's always FP. */ + fi->frame = generic_read_register_dummy (fi->pc, fi->frame, SP_REGNUM); + fi->framesize = 0; + return; + } else -#endif - if (!fi->next) - if (fi->using_frame_pointer) - fi->frame = read_register (FP_REGNUM); - else - fi->frame = read_register (SP_REGNUM); - else /* fi->next means this is not the innermost frame */ - if (fi->using_frame_pointer) /* we have an FP */ - if (fi->next->fsr.regs[FP_REGNUM] != 0) /* caller saved our FP */ - fi->frame = read_memory_integer (fi->next->fsr.regs[FP_REGNUM], 4); - - for (reg = 0; reg < NUM_REGS; reg++) - if (fi->fsr.regs[reg] != 0) - fi->fsr.regs[reg] = fi->frame + fi->framesize - fi->fsr.regs[reg]; + { + fi->using_frame_pointer = 0; + fi->framesize = m32r_scan_prologue (fi, &fi->fsr); + + if (!fi->next) + if (fi->using_frame_pointer) + fi->frame = read_register (FP_REGNUM); + else + fi->frame = read_register (SP_REGNUM); + else /* fi->next means this is not the innermost frame */ + if (fi->using_frame_pointer) /* we have an FP */ + if (fi->next->fsr.regs[FP_REGNUM] != 0) /* caller saved our FP */ + fi->frame = read_memory_integer (fi->next->fsr.regs[FP_REGNUM], 4); + for (reg = 0; reg < NUM_REGS; reg++) + if (fi->fsr.regs[reg] != 0) + fi->fsr.regs[reg] = fi->frame + fi->framesize - fi->fsr.regs[reg]; + } } -/* Find the caller of this frame. We do this by seeing if RP_REGNUM is saved - in the stack anywhere, otherwise we get it from the registers. */ +/* Function: find_callers_reg + Find REGNUM on the stack. Otherwise, it's in an active register. One thing + we might want to do here is to check REGNUM against the clobber mask, and + somehow flag it as invalid if it isn't saved on the stack somewhere. This + would provide a graceful failure mode when trying to get the value of + caller-saves registers for an inner frame. */ CORE_ADDR m32r_find_callers_reg (fi, regnum) struct frame_info *fi; int regnum; { -#if 0 - /* XXX - Won't work if multiple dummy frames are active */ - if (PC_IN_CALL_DUMMY (fi->pc, NULL, NULL)) - switch (regnum) - { - case SP_REGNUM: - return dummy_frame_stack->sp; - break; - case FP_REGNUM: - return dummy_frame_stack->fp; - break; - case RP_REGNUM: - return dummy_frame_stack->pc; - break; - case PC_REGNUM: - return dummy_frame_stack->pc; - break; - } - -#endif for (; fi; fi = fi->next) - if (fi->fsr.regs[regnum] != 0) - return read_memory_integer (fi->fsr.regs[regnum], 4); + if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) + return generic_read_register_dummy (fi->pc, fi->frame, regnum); + else if (fi->fsr.regs[regnum] != 0) + return read_memory_integer (fi->fsr.regs[regnum], + REGISTER_RAW_SIZE(regnum)); return read_register (regnum); } -/* Given a GDB frame, determine the address of the calling function's frame. +/* Function: frame_chain + Given a GDB frame, determine the address of the calling function's frame. This will be used to create a new GDB frame struct, and then INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame. - For m32r, we save the frame size when we initialize the frame_info. - */ + For m32r, we save the frame size when we initialize the frame_info. */ CORE_ADDR m32r_frame_chain (fi) struct frame_info *fi; { - CORE_ADDR fn_start; + CORE_ADDR fn_start, callers_pc, fp; + + /* is this a dummy frame? */ + if (PC_IN_CALL_DUMMY(fi->pc, fi->frame, fi->frame)) + return fi->frame; /* dummy frame same as caller's frame */ + + /* is caller-of-this a dummy frame? */ + callers_pc = FRAME_SAVED_PC(fi); /* find out who called us: */ + fp = m32r_find_callers_reg (fi, FP_REGNUM); + if (PC_IN_CALL_DUMMY(callers_pc, fp, fp)) + return fp; /* dummy frame's frame may bear no relation to ours */ if (find_pc_partial_function (fi->pc, 0, &fn_start, 0)) if (fn_start == entry_point_address ()) @@ -247,41 +245,28 @@ m32r_frame_chain (fi) return fi->frame + fi->framesize; } -/* All we do here is record SP and FP on the call dummy stack */ - -void -m32r_push_dummy_frame () -{ - struct dummy_frame *dummy_frame; - - dummy_frame = xmalloc (sizeof (struct dummy_frame)); - - dummy_frame->fp = read_register (FP_REGNUM); - dummy_frame->sp = read_register (SP_REGNUM); - dummy_frame->rp = read_register (RP_REGNUM); - dummy_frame->pc = read_register (PC_REGNUM); - dummy_frame->next = dummy_frame_stack; - dummy_frame_stack = dummy_frame; -} - -/* - * MISSING FUNCTION HEADER COMMENT - */ +/* Function: push_return_address (pc) + Set up the return address for the inferior function call. + Necessary for targets that don't actually execute a JSR/BSR instruction + (ie. when using an empty CALL_DUMMY) */ -int -m32r_pc_in_call_dummy (pc) +CORE_ADDR +m32r_push_return_address (pc, sp) CORE_ADDR pc; + CORE_ADDR sp; { -#if 0 - return dummy_frame_stack - && pc >= CALL_DUMMY_ADDRESS () - && pc <= CALL_DUMMY_ADDRESS () + DECR_PC_AFTER_BREAK; +#if CALL_DUMMY_LOCATION != AT_ENTRY_POINT + pc = pc - CALL_DUMMY_START_OFFSET + CALL_DUMMY_BREAKPOINT_OFFSET; #else - return 0; + pc = CALL_DUMMY_ADDRESS (); #endif + write_register (RP_REGNUM, pc); + return sp; } -/* Discard from the stack the innermost frame, + +/* Function: pop_frame + Discard from the stack the innermost frame, restoring all saved registers. */ struct frame_info * @@ -290,57 +275,70 @@ m32r_pop_frame (frame) { int regnum; -#if 0 - if (PC_IN_CALL_DUMMY (frame->pc, NULL, NULL)) + if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)) + generic_pop_dummy_frame (); + else { - struct dummy_frame *dummy_frame; - - dummy_frame = dummy_frame_stack; - if (!dummy_frame) - error ("Can't pop dummy frame!"); - - dummy_frame_stack = dummy_frame->next; - - write_register (FP_REGNUM, dummy_frame->fp); - write_register (SP_REGNUM, dummy_frame->sp); - write_register (RP_REGNUM, dummy_frame->rp); - write_register (PC_REGNUM, dummy_frame->pc); - - free (dummy_frame); - - flush_cached_frames (); - - return NULL; + for (regnum = 0; regnum < NUM_REGS; regnum++) + if (frame->fsr.regs[regnum] != 0) + write_register (regnum, + read_memory_integer (frame->fsr.regs[regnum], 4)); + + write_register (PC_REGNUM, FRAME_SAVED_PC (frame)); + write_register (SP_REGNUM, read_register (FP_REGNUM)); + if (read_register (PSW_REGNUM) & 0x80) + write_register (SPU_REGNUM, read_register (SP_REGNUM)); + else + write_register (SPI_REGNUM, read_register (SP_REGNUM)); } - -#endif - write_register (PC_REGNUM, FRAME_SAVED_PC (frame)); - - for (regnum = 0; regnum < NUM_REGS; regnum++) - if (frame->fsr.regs[regnum] != 0) - write_register (regnum, - read_memory_integer (frame->fsr.regs[regnum], 4)); - - write_register (SP_REGNUM, read_register (FP_REGNUM)); - if (read_register (PSW_REGNUM) & 0x80) - write_register (SPU_REGNUM, read_register (SP_REGNUM)); - else - write_register (SPI_REGNUM, read_register (SP_REGNUM)); - /* registers_changed (); */ flush_cached_frames (); - return NULL; } -/* Put arguments in the right places, and setup return address register (RP) to - point at a convenient place to put a breakpoint. First four args go in - R6->R9, subsequent args go into sp + 16 -> sp + ... Structs are passed by - reference. 64 bit quantities (doubles and long longs) may be split between - the regs and the stack. When calling a function that returns a struct, a - pointer to the struct is passed in as a secret first argument (always in R6). +/* Function: frame_saved_pc + Find the caller of this frame. We do this by seeing if RP_REGNUM is saved + in the stack anywhere, otherwise we get it from the registers. */ - By the time we get here, stack space has been allocated for the args, but - not for the struct return pointer. */ +CORE_ADDR +m32r_frame_saved_pc (fi) + struct frame_info *fi; +{ + if (PC_IN_CALL_DUMMY(fi->pc, fi->frame, fi->frame)) + return generic_read_register_dummy(fi->pc, fi->frame, PC_REGNUM); + else + return m32r_find_callers_reg (fi, RP_REGNUM); +} + +/* Function: push_arguments + Setup the function arguments for calling a function in the inferior. + + On the Mitsubishi M32R architecture, there are four registers (R0 to R3) + which are dedicated for passing function arguments. Up to the first + four arguments (depending on size) may go into these registers. + The rest go on the stack. + + Arguments that are smaller than 4 bytes will still take up a whole + register or a whole 32-bit word on the stack, and will be + right-justified in the register or the stack word. This includes + chars, shorts, and small aggregate types. + + Arguments of 8 bytes size are split between two registers, if + available. If only one register is available, the argument will + be split between the register and the stack. Otherwise it is + passed entirely on the stack. Aggregate types with sizes between + 4 and 8 bytes are passed entirely on the stack, and are left-justified + within the double-word (as opposed to aggregates smaller than 4 bytes + which are right-justified). + + Aggregates of greater than 8 bytes are first copied onto the stack, + and then a pointer to the copy is passed in the place of the normal + argument (either in a register if available, or on the stack). + + Functions that must return an aggregate type can return it in the + normal return value registers (R0 and R1) if its size is 8 bytes or + less. For larger return values, the caller must allocate space for + the callee to copy the return value to. A pointer to this space is + passed as an implicit first argument, always in R0. */ CORE_ADDR m32r_push_arguments (nargs, args, sp, struct_return, struct_addr) @@ -350,67 +348,135 @@ m32r_push_arguments (nargs, args, sp, struct_return, struct_addr) unsigned char struct_return; CORE_ADDR struct_addr; { + int stack_offset, stack_alloc; int argreg; int argnum; - - argreg = ARG0_REGNUM; - -#if 0 + struct type *type; + CORE_ADDR regval; + char *val; + char valbuf[4]; + int len; + int odd_sized_struct; + + /* first force sp to a 4-byte alignment */ + sp = sp & ~3; + + argreg = ARG0_REGNUM; + /* The "struct return pointer" pseudo-argument goes in R0 */ if (struct_return) - { write_register (argreg++, struct_addr); - sp -= 4; - } - - for (argnum = 0; argnum < nargs; argnum++) + + /* Now make sure there's space on the stack */ + for (argnum = 0, stack_alloc = 0; + argnum < nargs; argnum++) + stack_alloc += ((TYPE_LENGTH(VALUE_TYPE(args[argnum])) + 3) & ~3); + sp -= stack_alloc; /* make room on stack for args */ + + + /* Now load as many as possible of the first arguments into + registers, and push the rest onto the stack. There are 16 bytes + in four registers available. Loop thru args from first to last. */ + + argreg = ARG0_REGNUM; + for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++) { - int len; - char *val; - char valbuf[4]; - - if (TYPE_CODE (VALUE_TYPE (*args)) == TYPE_CODE_STRUCT - && TYPE_LENGTH (VALUE_TYPE (*args)) > 8) - { - store_address (valbuf, 4, VALUE_ADDRESS (*args)); - len = 4; - val = valbuf; - } + type = VALUE_TYPE (args[argnum]); + len = TYPE_LENGTH (type); + memset(valbuf, 0, sizeof(valbuf)); + if (len < 4) + { /* value gets right-justified in the register or stack word */ + memcpy(valbuf + (4 - len), + (char *) VALUE_CONTENTS (args[argnum]), len); + val = valbuf; + } else - { - len = TYPE_LENGTH (VALUE_TYPE (*args)); - val = (char *)VALUE_CONTENTS (*args); - } - + val = (char *) VALUE_CONTENTS (args[argnum]); + + if (len > 4 && (len & 3) != 0) + odd_sized_struct = 1; /* such structs go entirely on stack */ + else + odd_sized_struct = 0; while (len > 0) - if (argreg <= ARGLAST_REGNUM) - { - CORE_ADDR regval; + { + if (argreg > ARGLAST_REGNUM || odd_sized_struct) + { /* must go on the stack */ + write_memory (sp + stack_offset, val, 4); + stack_offset += 4; + } + /* NOTE WELL!!!!! This is not an "else if" clause!!! + That's because some *&^%$ things get passed on the stack + AND in the registers! */ + if (argreg <= ARGLAST_REGNUM) + { /* there's room in a register */ + regval = extract_address (val, REGISTER_RAW_SIZE(argreg)); + write_register (argreg++, regval); + } + /* Store the value 4 bytes at a time. This means that things + larger than 4 bytes may go partly in registers and partly + on the stack. */ + len -= REGISTER_RAW_SIZE(argreg); + val += REGISTER_RAW_SIZE(argreg); + } + } + return sp; +} - regval = extract_address (val, REGISTER_RAW_SIZE (argreg)); - write_register (argreg, regval); +/* Function: fix_call_dummy + If there is real CALL_DUMMY code (eg. on the stack), this function + has the responsability to insert the address of the actual code that + is the target of the target function call. */ - len -= REGISTER_RAW_SIZE (argreg); - val += REGISTER_RAW_SIZE (argreg); - argreg++; - } - else - { - write_memory (sp + argnum * 4, val, 4); +int +m32r_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p) + char *dummy; + CORE_ADDR pc; + CORE_ADDR fun; + int nargs; + value_ptr *args; + struct type *type; + int gcc_p; +{ + /* ld24 r8, <(imm24) fun> */ + *(unsigned long *) (dummy) = (fun & 0x00ffffff) | 0xe8000000; +} - len -= 4; - val += 4; - } - args++; - } +/* Function: get_saved_register + Just call the generic_get_saved_register function. */ - write_register (RP_REGNUM, entry_point_address ()); +void +get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) + char *raw_buffer; + int *optimized; + CORE_ADDR *addrp; + struct frame_info *frame; + int regnum; + enum lval_type *lval; +{ + generic_get_saved_register (raw_buffer, optimized, addrp, + frame, regnum, lval); +} -#endif - return sp; + +/* Function: m32r_write_sp + Because SP is really a read-only register that mirrors either SPU or SPI, + we must actually write one of those two as well, depending on PSW. */ + +void +m32r_write_sp (val) + CORE_ADDR val; +{ + unsigned long psw = read_register (PSW_REGNUM); + + if (psw & 0x80) /* stack mode: user or interrupt */ + write_register (SPU_REGNUM, val); + else + write_register (SPI_REGNUM, val); + write_register (SP_REGNUM, val); } - + void _initialize_m32r_tdep () { tm_print_insn = print_insn_m32r; } + diff --git a/gdb/sh-tdep.c b/gdb/sh-tdep.c index d8af915be43..d088f44b670 100644 --- a/gdb/sh-tdep.c +++ b/gdb/sh-tdep.c @@ -185,7 +185,7 @@ sh_find_callers_reg (fi, regnum) if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) /* When the caller requests PR from the dummy frame, we return PC because that's where the previous routine appears to have done a call from. */ - return generic_read_register_dummy (fi, regnum); + return generic_read_register_dummy (fi->pc, fi->frame, regnum); else { FRAME_FIND_SAVED_REGS(fi, fsr); @@ -202,10 +202,6 @@ sh_find_callers_reg (fi, regnum) ways in the stack frame. sp is even more special: the address we return for it IS the sp for the next frame. */ -/* FIXME! A lot of this should be abstracted out into a sh_scan_prologue - function, and the struct frame_info should have a frame_saved_regs - embedded in it, so we would only have to do this once. */ - void sh_frame_find_saved_regs (fi, fsr) struct frame_info *fi; @@ -219,7 +215,7 @@ sh_frame_find_saved_regs (fi, fsr) int opc; int insn; int r3_val = 0; - char * dummy_regs = generic_find_dummy_frame (fi->pc, fi->frame, fi->frame); + char * dummy_regs = generic_find_dummy_frame (fi->pc, fi->frame); if (dummy_regs) { @@ -339,8 +335,10 @@ sh_init_extra_frame_info (fromleaf, fi) { /* We need to setup fi->frame here because run_stack_dummy gets it wrong by assuming it's always FP. */ - fi->frame = generic_read_register_dummy (fi, SP_REGNUM); - fi->return_pc = generic_read_register_dummy (fi, PC_REGNUM); + fi->frame = generic_read_register_dummy (fi->pc, fi->frame, + SP_REGNUM); + fi->return_pc = generic_read_register_dummy (fi->pc, fi->frame, + PC_REGNUM); fi->f_offset = -(CALL_DUMMY_LENGTH + 4); fi->leaf_function = 0; return; @@ -433,14 +431,15 @@ sh_push_arguments (nargs, args, sp, struct_return, struct_addr) unsigned char struct_return; CORE_ADDR struct_addr; { + int stack_offset, stack_alloc; int argreg; int argnum; + struct type *type; CORE_ADDR regval; char *val; char valbuf[4]; int len; - int push[4]; /* some of the first 4 args may not need to be pushed - onto the stack, because they can go in registers */ + int odd_sized_struct; /* first force sp to a 4-byte alignment */ sp = sp & ~3; @@ -450,97 +449,123 @@ sh_push_arguments (nargs, args, sp, struct_return, struct_addr) if (struct_return) write_register (STRUCT_RETURN_REGNUM, struct_addr); - /* Now load as many as possible of the first arguments into registers. - There are 16 bytes in four registers available. - Loop thru args from first to last. */ - push[0] = push[1] = push[2] = push[3] = 0; - for (argnum = 0, argreg = ARG0_REGNUM; - argnum < nargs && argreg <= ARGLAST_REGNUM; - argnum++) + /* Now make sure there's space on the stack */ + for (argnum = 0, stack_alloc = 0; + argnum < nargs; argnum++) + stack_alloc += ((TYPE_LENGTH(VALUE_TYPE(args[argnum])) + 3) & ~3); + sp -= stack_alloc; /* make room on stack for args */ + + + /* Now load as many as possible of the first arguments into + registers, and push the rest onto the stack. There are 16 bytes + in four registers available. Loop thru args from first to last. */ + + argreg = ARG0_REGNUM; + for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++) { - struct type *type = VALUE_TYPE (args[argnum]); - - len = TYPE_LENGTH (type); - - switch (TYPE_CODE(type)) { - case TYPE_CODE_STRUCT: - case TYPE_CODE_UNION: - /* case TYPE_CODE_ARRAY: case TYPE_CODE_STRING: */ - if (len <= 4 || (len & ~3) == 0) - push[argnum] = 0; /* doesn't get pushed onto stack */ - else - push[argnum] = len; /* does get pushed onto stack */ - break; - default: - push[argnum] = 0; /* doesn't get pushed onto stack */ - } + type = VALUE_TYPE (args[argnum]); + len = TYPE_LENGTH (type); + memset(valbuf, 0, sizeof(valbuf)); if (len < 4) - { /* value gets right-justified in the register */ - memcpy(valbuf + (4 - len), + { /* value gets right-justified in the register or stack word */ + memcpy(valbuf + (4 - len), (char *) VALUE_CONTENTS (args[argnum]), len); - val = valbuf; - } + val = valbuf; + } else - val = (char *) VALUE_CONTENTS (args[argnum]); + val = (char *) VALUE_CONTENTS (args[argnum]); + if (len > 4 && (len & 3) != 0) + odd_sized_struct = 1; /* such structs go entirely on stack */ + else + odd_sized_struct = 0; while (len > 0) { - regval = extract_address (val, REGISTER_RAW_SIZE (argreg)); - write_register (argreg, regval); - - len -= REGISTER_RAW_SIZE (argreg); - val += REGISTER_RAW_SIZE (argreg); - argreg++; - if (argreg > ARGLAST_REGNUM) - { - push[argnum] = len; /* ran out of arg passing registers! */ - break; /* len bytes remain to go onto stack */ + if (argreg > ARGLAST_REGNUM || odd_sized_struct) + { /* must go on the stack */ + write_memory (sp + stack_offset, val, 4); + stack_offset += 4; } + /* NOTE WELL!!!!! This is not an "else if" clause!!! + That's because some *&^%$ things get passed on the stack + AND in the registers! */ + if (argreg <= ARGLAST_REGNUM) + { /* there's room in a register */ + regval = extract_address (val, REGISTER_RAW_SIZE(argreg)); + write_register (argreg++, regval); + } + /* Store the value 4 bytes at a time. This means that things + larger than 4 bytes may go partly in registers and partly + on the stack. */ + len -= REGISTER_RAW_SIZE(argreg); + val += REGISTER_RAW_SIZE(argreg); } } + return sp; +} - /* Now push as many as necessary of the remaining arguments onto the stack. - For args 0 to 3, the arg may have been passed in a register. - Loop thru args from last to first. */ - for (argnum = nargs-1; argnum >= 0; --argnum) - { - if (argnum < 4 && push[argnum] == 0) - continue; /* no need to push this arg */ +/* Function: push_return_address (pc) + Set up the return address for the inferior function call. + Needed for targets where we don't actually execute a JSR/BSR instruction */ - len = TYPE_LENGTH (VALUE_TYPE (args[argnum])); - if (len < 4) - { - memcpy(valbuf + (4 - len), - (char *) VALUE_CONTENTS (args[argnum]), len); - val = valbuf; - } - else - val = (char *) VALUE_CONTENTS (args[argnum]); +CORE_ADDR +sh_push_return_address (pc, sp) + CORE_ADDR pc; + CORE_ADDR sp; +{ +#if CALL_DUMMY_LOCATION != AT_ENTRY_POINT + pc = pc - CALL_DUMMY_START_OFFSET + CALL_DUMMY_BREAKPOINT_OFFSET; +#else + pc = CALL_DUMMY_ADDRESS (); +#endif /* CALL_DUMMY_LOCATION */ + write_register (PR_REGNUM, pc); + return sp; +} - if (argnum < 4) - if (len > push[argnum]) /* some part may already be in a reg */ - { - val += (len - push[argnum]); - len = push[argnum]; - } +/* Function: fix_call_dummy + Poke the callee function's address into the destination part of + the CALL_DUMMY. The address is actually stored in a data word + following the actualy CALL_DUMMY instructions, which will load + it into a register using PC-relative addressing. This function + expects the CALL_DUMMY to look like this: - sp -= (len + 3) & ~3; - write_memory (sp, val, len); - } - return sp; + mov.w @(2,PC), R8 + jsr @R8 + nop + trap + + */ + +int +sh_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p) + char *dummy; + CORE_ADDR pc; + CORE_ADDR fun; + int nargs; + value_ptr *args; + struct type *type; + int gcc_p; +{ + *(unsigned long *) (dummy + 8) = fun; } -/* Function: push_return_address (pc) - Set up the return address for the inferior function call. - Necessary for targets where we don't actually execute a JSR/BSR instruction */ +/* Function: get_saved_register + Just call the generic_get_saved_register function. */ void -sh_push_return_address (pc) - CORE_ADDR pc; +get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) + char *raw_buffer; + int *optimized; + CORE_ADDR *addrp; + struct frame_info *frame; + int regnum; + enum lval_type *lval; { - write_register (PR_REGNUM, entry_point_address ()); + generic_get_saved_register (raw_buffer, optimized, addrp, + frame, regnum, lval); } + /* Command to set the processor type. */ void @@ -645,6 +670,10 @@ sh_show_regs (args, from_tty) read_register (15)); } +/* Function: extract_return_value + Find a function's return value in the appropriate registers (in regbuf), + and copy it into valbuf. */ + void sh_extract_return_value (type, regbuf, valbuf) struct type *type; @@ -688,192 +717,3 @@ Set this to be able to access processor-type-specific registers.\n\ remote_write_size = 300; } -/* - * DUMMY FRAMES - * - * The following code serves to maintain the dummy stack frames for - * inferior function calls (ie. when gdb calls into the inferior via - * call_function_by_hand). This code saves the machine state before - * the call in host memory, so it must maintain an independant stack - * and keep it consistant etc. I am attempting to make this code - * generic enough to be used by many targets. - * - * The cheapest and most generic way to do CALL_DUMMY on a new target - * is probably to define CALL_DUMMY to be empty, CALL_DUMMY_LENGTH to zero, - * and CALL_DUMMY_LOCATION to AT_ENTRY. Then you must remember to define - * PUSH_RETURN_ADDRESS, because there won't be a call instruction to do it. - */ - -/* Dummy frame. This saves the processor state just prior to setting up the - inferior function call. On most targets, the registers are saved on the - target stack, but that really slows down function calls. */ - -struct dummy_frame -{ - struct dummy_frame *next; - - CORE_ADDR pc; - CORE_ADDR fp; - CORE_ADDR sp; - char regs[REGISTER_BYTES]; -}; - -static struct dummy_frame *dummy_frame_stack = NULL; - -/* Function: find_dummy_frame(pc, fp, sp) - Search the stack of dummy frames for one matching the given PC, FP and SP. - This is the work-horse for pc_in_call_dummy and read_register_dummy */ - -char * -generic_find_dummy_frame (pc, fp, sp) - CORE_ADDR pc; - CORE_ADDR fp; - CORE_ADDR sp; -{ - struct dummy_frame * dummyframe; - CORE_ADDR bkpt_address; - extern CORE_ADDR text_end; - -#if CALL_DUMMY_LOCATION == AT_ENTRY_POINT - bkpt_address = entry_point_address () + CALL_DUMMY_BREAKPOINT_OFFSET; - if (pc != bkpt_address && - pc != bkpt_address + DECR_PC_AFTER_BREAK) - return 0; -#endif /* AT_ENTRY_POINT */ - -#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END - bkpt_address = text_end - CALL_DUMMY_LENGTH + CALL_DUMMY_BREAKPOINT_OFFSET; - if (pc != bkpt_address && - pc != bkpt_address + DECR_PC_AFTER_BREAK) - return 0; -#endif /* BEFORE_TEXT_END */ - -#if CALL_DUMMY_LOCATION == AFTER_TEXT_END - bkpt_address = text_end + CALL_DUMMY_BREAKPOINT_OFFSET; - if (pc != bkpt_address && - pc != bkpt_address + DECR_PC_AFTER_BREAK) - return 0; -#endif /* AFTER_TEXT_END */ - - for (dummyframe = dummy_frame_stack; - dummyframe; - dummyframe = dummyframe->next) - if (fp == dummyframe->fp || - sp == dummyframe->sp) - { -#if CALL_DUMMY_LOCATION == ON_STACK - CORE_ADDR bkpt_offset; /* distance from original frame ptr to bkpt */ - - if (1 INNER_THAN 2) - bkpt_offset = CALL_DUMMY_BREAK_OFFSET; - else - bkpt_offset = CALL_DUMMY_LENGTH - CALL_DUMMY_BREAK_OFFSET; - - if (pc + bkpt_offset == dummyframe->fp || - pc + bkpt_offset == dummyframe->sp || - pc + bkpt_offset + DECR_PC_AFTER_BREAK == dummyframe->fp || - pc + bkpt_offset + DECR_PC_AFTER_BREAK == dummyframe->sp) -#endif /* ON_STACK */ - return dummyframe->regs; - } - return 0; -} - -/* Function: pc_in_call_dummy (pc, fp, sp) - Return true if this is a dummy frame created by gdb for an inferior call */ - -int -generic_pc_in_call_dummy (pc, fp, sp) - CORE_ADDR pc; - CORE_ADDR fp; - CORE_ADDR sp; -{ - /* if find_dummy_frame succeeds, then PC is in a call dummy */ - return (generic_find_dummy_frame (pc, fp, sp) != 0); -} - -/* Function: read_register_dummy (pc, fp, sp, regno) - Find a saved register from before GDB calls a function in the inferior */ - -CORE_ADDR -generic_read_register_dummy (fi, regno) - struct frame_info *fi; - int regno; -{ - char *dummy_regs = generic_find_dummy_frame (fi->pc, fi->frame, NULL); - - if (dummy_regs) - return extract_address (&dummy_regs[REGISTER_BYTE (regno)], - REGISTER_RAW_SIZE(regno)); - else - return 0; -} - -/* Save all the registers on the dummy frame stack. Most ports save the - registers on the target stack. This results in lots of unnecessary memory - references, which are slow when debugging via a serial line. Instead, we - save all the registers internally, and never write them to the stack. The - registers get restored when the called function returns to the entry point, - where a breakpoint is laying in wait. */ - -void -generic_push_dummy_frame () -{ - struct dummy_frame *dummy_frame; - CORE_ADDR fp = read_register(FP_REGNUM); - - /* check to see if there are stale dummy frames, - perhaps left over from when a longjump took us out of a - function that was called by the debugger */ - - dummy_frame = dummy_frame_stack; - while (dummy_frame) - if (dummy_frame->fp INNER_THAN fp) /* stale -- destroy! */ - { - dummy_frame_stack = dummy_frame->next; - free (dummy_frame); - dummy_frame = dummy_frame_stack; - } - else - dummy_frame = dummy_frame->next; - - dummy_frame = xmalloc (sizeof (struct dummy_frame)); - - read_register_bytes (0, dummy_frame->regs, REGISTER_BYTES); - dummy_frame->pc = read_register (PC_REGNUM); - dummy_frame->fp = read_register (FP_REGNUM); - dummy_frame->sp = read_register (SP_REGNUM); - dummy_frame->next = dummy_frame_stack; - dummy_frame_stack = dummy_frame; -} - -/* Function: pop_dummy_frame - Restore the machine state from a saved dummy stack frame. */ - -void -generic_pop_dummy_frame () -{ - struct dummy_frame *dummy_frame = dummy_frame_stack; - - if (!dummy_frame) - error ("Can't pop dummy frame!"); - dummy_frame_stack = dummy_frame->next; - write_register_bytes (0, dummy_frame->regs, REGISTER_BYTES); - free (dummy_frame); -} - -/* Function: frame_chain_valid - Returns true for a user frame or a call_function_by_hand dummy frame, - and false for the CRT0 start-up frame. Purpose is to terminate backtrace */ - -int -generic_frame_chain_valid (fp, fi) - CORE_ADDR fp; - struct frame_info *fi; -{ - if (PC_IN_CALL_DUMMY(FRAME_SAVED_PC(fi), fp, fp)) - return 1; /* don't prune CALL_DUMMY frames */ - else /* fall back to default algorithm (see frame.h) */ - return (fp != 0 && !inside_entry_file (FRAME_SAVED_PC(fi))); -} - diff --git a/gdb/v850-tdep.c b/gdb/v850-tdep.c index 4559b137d34..1a5d69a8f6d 100644 --- a/gdb/v850-tdep.c +++ b/gdb/v850-tdep.c @@ -28,21 +28,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gdbcore.h" #include "symfile.h" -/* Dummy frame. This saves the processor state just prior to setting up the - inferior function call. On most targets, the registers are saved on the - target stack, but that really slows down function calls. */ - -struct dummy_frame -{ - struct dummy_frame *next; - - char regs[REGISTER_BYTES]; -}; - -static struct dummy_frame *dummy_frame_stack = NULL; - -static CORE_ADDR read_register_dummy PARAMS ((int regno)); - /* Info gleaned from scanning a function's prologue. */ struct pifsr /* Info about one saved reg */ @@ -60,18 +45,20 @@ struct prologue_info struct pifsr *pifsrs; }; -static CORE_ADDR scan_prologue PARAMS ((CORE_ADDR pc, struct prologue_info *fs)); +static CORE_ADDR v850_scan_prologue PARAMS ((CORE_ADDR pc, + struct prologue_info *fs)); -/* Scan the prologue of the function that contains PC, and record what we find - in PI. PI->fsr must be zeroed by the called. Returns the pc after the - prologue. Note that the addresses saved in pi->fsr are actually just frame - relative (negative offsets from the frame pointer). This is because we - don't know the actual value of the frame pointer yet. In some - circumstances, the frame pointer can't be determined till after we have - scanned the prologue. */ +/* Function: scan_prologue + Scan the prologue of the function that contains PC, and record what + we find in PI. PI->fsr must be zeroed by the called. Returns the + pc after the prologue. Note that the addresses saved in pi->fsr + are actually just frame relative (negative offsets from the frame + pointer). This is because we don't know the actual value of the + frame pointer yet. In some circumstances, the frame pointer can't + be determined till after we have scanned the prologue. */ static CORE_ADDR -scan_prologue (pc, pi) +v850_scan_prologue (pc, pi) CORE_ADDR pc; struct prologue_info *pi; { @@ -161,8 +148,9 @@ scan_prologue (pc, pi) return current_pc; } -/* Setup the frame frame pointer, pc, and frame addresses for saved registers. - Most of the work is done in scan_prologue(). +/* Function: init_extra_frame_info + Setup the frame's frame pointer, pc, and frame addresses for saved + registers. Most of the work is done in scan_prologue(). Note that when we are called for the last frame (currently active frame), that fi->pc and fi->frame will already be setup. However, fi->frame will @@ -171,8 +159,7 @@ scan_prologue (pc, pi) We can be called with the PC in the call dummy under two circumstances. First, during normal backtracing, second, while figuring out the frame - pointer just prior to calling the target function (see run_stack_dummy). - */ + pointer just prior to calling the target function (see run_stack_dummy). */ void v850_init_extra_frame_info (fi) @@ -189,17 +176,12 @@ v850_init_extra_frame_info (fi) /* The call dummy doesn't save any registers on the stack, so we can return now. */ - if (PC_IN_CALL_DUMMY (fi->pc, NULL, NULL)) - { - /* We need to setup fi->frame here because run_stack_dummy gets it wrong - by assuming it's always FP. */ - fi->frame = read_register_dummy (SP_REGNUM); + if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) return; - } pi.pifsrs = pifsrs; - scan_prologue (fi->pc, &pi); + v850_scan_prologue (fi->pc, &pi); if (!fi->next && pi.framereg == SP_REGNUM) fi->frame = read_register (pi.framereg) - pi.frameoffset; @@ -213,28 +195,32 @@ v850_init_extra_frame_info (fi) } } -/* Figure out the frame prior to FI. Unfortunately, this involves scanning the - prologue of the caller, which will also be done shortly by - v850_init_extra_frame_info. For the dummy frame, we just return the stack - pointer that was in use at the time the function call was made. */ +/* Function: frame_chain + Figure out the frame prior to FI. Unfortunately, this involves + scanning the prologue of the caller, which will also be done + shortly by v850_init_extra_frame_info. For the dummy frame, we + just return the stack pointer that was in use at the time the + function call was made. */ CORE_ADDR v850_frame_chain (fi) struct frame_info *fi; { - CORE_ADDR callers_pc; struct prologue_info pi; + CORE_ADDR callers_pc, fp; /* First, find out who called us */ - callers_pc = FRAME_SAVED_PC (fi); + /* If caller is a call-dummy, then our FP bears no relation to his FP! */ + fp = v850_find_callers_reg (fi, FP_REGNUM); + if (PC_IN_CALL_DUMMY(callers_pc, fp, fp)) + return fp; /* caller is call-dummy: return oldest value of FP */ - if (PC_IN_CALL_DUMMY (callers_pc, NULL, NULL)) - return read_register_dummy (SP_REGNUM); /* XXX Won't work if multiple dummy frames on stack! */ - + /* Caller is NOT a call-dummy, so everything else should just work. + Even if THIS frame is a call-dummy! */ pi.pifsrs = NULL; - scan_prologue (callers_pc, &pi); + v850_scan_prologue (callers_pc, &pi); if (pi.start_function) return 0; /* Don't chain beyond the start function */ @@ -245,33 +231,32 @@ v850_frame_chain (fi) return fi->frame - pi.frameoffset; } -/* Find REGNUM on the stack. Otherwise, it's in an active register. One thing - we might want to do here is to check REGNUM against the clobber mask, and - somehow flag it as invalid if it isn't saved on the stack somewhere. This - would provide a graceful failure mode when trying to get the value of - caller-saves registers for an inner frame. */ +/* Function: find_callers_reg + Find REGNUM on the stack. Otherwise, it's in an active register. + One thing we might want to do here is to check REGNUM against the + clobber mask, and somehow flag it as invalid if it isn't saved on + the stack somewhere. This would provide a graceful failure mode + when trying to get the value of caller-saves registers for an inner + frame. */ CORE_ADDR v850_find_callers_reg (fi, regnum) struct frame_info *fi; int regnum; { - /* XXX - Won't work if multiple dummy frames are active */ - /* When the caller requests RP from the dummy frame, we return PC because - that's where the previous routine appears to have done a call from. */ - if (PC_IN_CALL_DUMMY (fi->pc, NULL, NULL)) - if (regnum == RP_REGNUM) - regnum = PC_REGNUM; - for (; fi; fi = fi->next) - if (PC_IN_CALL_DUMMY (fi->pc, NULL, NULL)) - return read_register_dummy (regnum); + if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) + return generic_read_register_dummy (fi->pc, fi->frame, regnum); else if (fi->fsr.regs[regnum] != 0) - return read_memory_integer (fi->fsr.regs[regnum], 4); + return read_memory_unsigned_integer (fi->fsr.regs[regnum], + REGISTER_RAW_SIZE(regnum)); return read_register (regnum); } +/* Function: skip_prologue + Return the address of the first code past the prologue of the function. */ + CORE_ADDR v850_skip_prologue (pc) CORE_ADDR pc; @@ -299,68 +284,18 @@ v850_skip_prologue (pc) return pc; } -/* Save all the registers on the dummy frame stack. Most ports save the - registers on the target stack. This results in lots of unnecessary memory - references, which are slow when debugging via a serial line. Instead, we - save all the registers internally, and never write them to the stack. The - registers get restored when the called function returns to the entry point, - where a breakpoint is laying in wait. */ +/* Function: pop_frame + This routine gets called when either the user uses the `return' + command, or the call dummy breakpoint gets hit. */ void -v850_push_dummy_frame () -{ - struct dummy_frame *dummy_frame; - - dummy_frame = xmalloc (sizeof (struct dummy_frame)); - - read_register_bytes (0, dummy_frame->regs, REGISTER_BYTES); - - dummy_frame->next = dummy_frame_stack; - dummy_frame_stack = dummy_frame; -} - -/* Read registers from the topmost dummy frame. */ - -CORE_ADDR -read_register_dummy (regno) - int regno; -{ - return extract_address (&dummy_frame_stack->regs[REGISTER_BYTE (regno)], - REGISTER_RAW_SIZE(regno)); -} - -int -v850_pc_in_call_dummy (pc) - CORE_ADDR pc; -{ - return dummy_frame_stack - && pc >= CALL_DUMMY_ADDRESS () - && pc <= CALL_DUMMY_ADDRESS () + DECR_PC_AFTER_BREAK; -} - -/* This routine gets called when either the user uses the `return' command, or - the call dummy breakpoint gets hit. */ - -struct frame_info * v850_pop_frame (frame) struct frame_info *frame; { int regnum; - if (PC_IN_CALL_DUMMY (frame->pc, NULL, NULL)) - { - struct dummy_frame *dummy_frame; - - dummy_frame = dummy_frame_stack; - if (!dummy_frame) - error ("Can't pop dummy frame!"); - - dummy_frame_stack = dummy_frame->next; - - write_register_bytes (0, dummy_frame->regs, REGISTER_BYTES); - - free (dummy_frame); - } + if (PC_IN_CALL_DUMMY(frame->pc, frame->frame, frame->frame)) + generic_pop_dummy_frame (); else { write_register (PC_REGNUM, FRAME_SAVED_PC (frame)); @@ -368,24 +303,25 @@ v850_pop_frame (frame) for (regnum = 0; regnum < NUM_REGS; regnum++) if (frame->fsr.regs[regnum] != 0) write_register (regnum, - read_memory_integer (frame->fsr.regs[regnum], 4)); + read_memory_unsigned_integer (frame->fsr.regs[regnum], + REGISTER_RAW_SIZE(regnum))); write_register (SP_REGNUM, FRAME_FP (frame)); } flush_cached_frames (); - - return NULL; } -/* Setup arguments and RP for a call to the target. First four args go in - R6->R9, subsequent args go into sp + 16 -> sp + ... Structs are passed by - reference. 64 bit quantities (doubles and long longs) may be split between - the regs and the stack. When calling a function that returns a struct, a - pointer to the struct is passed in as a secret first argument (always in R6). +/* Function: push_arguments + Setup arguments and RP for a call to the target. First four args + go in R6->R9, subsequent args go into sp + 16 -> sp + ... Structs + are passed by reference. 64 bit quantities (doubles and long + longs) may be split between the regs and the stack. When calling a + function that returns a struct, a pointer to the struct is passed + in as a secret first argument (always in R6). - By the time we get here, stack space has been allocated for the args, but - not for the struct return pointer. */ + Stack space for the args has NOT been allocated: that job is up to us. + */ CORE_ADDR v850_push_arguments (nargs, args, sp, struct_return, struct_addr) @@ -397,20 +333,37 @@ v850_push_arguments (nargs, args, sp, struct_return, struct_addr) { int argreg; int argnum; + int len = 0; + int stack_offset; + /* First, just for safety, make sure stack is aligned */ + sp &= ~3; + + /* Now make space on the stack for the args. */ + for (argnum = 0; argnum < nargs; argnum++) + len += ((TYPE_LENGTH(VALUE_TYPE(args[argnum])) + 3) & ~3); + sp -= len; /* possibly over-allocating, but it works... */ + /* (you might think we could allocate 16 bytes */ + /* less, but the ABI seems to use it all! ) */ argreg = ARG0_REGNUM; + /* the struct_return pointer occupies the first parameter-passing reg */ if (struct_return) - { write_register (argreg++, struct_addr); - sp -= 4; - } + stack_offset = 16; + /* The offset onto the stack at which we will start copying parameters + (after the registers are used up) begins at 16 rather than at zero. + I don't really know why, that's just the way it seems to work. */ + + /* Now load as many as possible of the first arguments into + registers, and push the rest onto the stack. There are 16 bytes + in four registers available. Loop thru args from first to last. */ for (argnum = 0; argnum < nargs; argnum++) { int len; char *val; - char valbuf[4]; + char valbuf[REGISTER_RAW_SIZE(ARG0_REGNUM)]; if (TYPE_CODE (VALUE_TYPE (*args)) == TYPE_CODE_STRUCT && TYPE_LENGTH (VALUE_TYPE (*args)) > 8) @@ -439,21 +392,112 @@ v850_push_arguments (nargs, args, sp, struct_return, struct_addr) } else { - write_memory (sp + argnum * 4, val, 4); + write_memory (sp + stack_offset, val, 4); len -= 4; val += 4; + stack_offset += 4; } args++; } + return sp; +} - write_register (RP_REGNUM, entry_point_address ()); - +/* Function: push_return_address (pc) + Set up the return address for the inferior function call. + Needed for targets where we don't actually execute a JSR/BSR instruction */ + +#ifdef PUSH_RETURN_ADDRESS +CORE_ADDR +v850_push_return_address (pc, sp) + CORE_ADDR pc; + CORE_ADDR sp; +{ +#if CALL_DUMMY_LOCATION != AT_ENTRY_POINT + pc = pc - CALL_DUMMY_START_OFFSET + CALL_DUMMY_BREAKPOINT_OFFSET; +#else + pc = CALL_DUMMY_ADDRESS (); +#endif /* CALL_DUMMY_LOCATION */ + write_register (RP_REGNUM, pc); return sp; } - +#endif /* PUSH_RETURN_ADDRESS */ + +/* Function: frame_saved_pc + Find the caller of this frame. We do this by seeing if RP_REGNUM + is saved in the stack anywhere, otherwise we get it from the + registers. If the inner frame is a dummy frame, return its PC + instead of RP, because that's where "caller" of the dummy-frame + will be found. */ + +CORE_ADDR +v850_frame_saved_pc (fi) + struct frame_info *fi; +{ + if (PC_IN_CALL_DUMMY(fi->pc, fi->frame, fi->frame)) + return generic_read_register_dummy(fi->pc, fi->frame, PC_REGNUM); + else + return v850_find_callers_reg (fi, RP_REGNUM); +} + +void +get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval) + char *raw_buffer; + int *optimized; + CORE_ADDR *addrp; + struct frame_info *frame; + int regnum; + enum lval_type *lval; +{ + generic_get_saved_register (raw_buffer, optimized, addrp, + frame, regnum, lval); +} + + +/* Function: fix_call_dummy + Pokes the callee function's address into the CALL_DUMMY assembly stub. + Assumes that the CALL_DUMMY looks like this: + jarl , r31 + trap + */ + +int +v850_fix_call_dummy (dummy, sp, fun, nargs, args, type, gcc_p) + char *dummy; + CORE_ADDR sp; + CORE_ADDR fun; + int nargs; + value_ptr *args; + struct type *type; + int gcc_p; +{ + long offset24; + CORE_ADDR call_dummy_start; +#ifdef NEED_TEXT_START_END + extern CORE_ADDR text_end; +#endif + +#if (CALL_DUMMY_LOCATION == AT_ENTRY_POINT) + call_dummy_start = entry_point_address (); +#elif (CALL_DUMMY_LOCATION == AFTER_TEXT_END) + call_dummy_start = text_end; +#elif (CALL_DUMMY_LOCATION == BEFORE_TEXT_END) + call_dummy_start = (text_end - CALL_DUMMY_LENGTH) & ~3; +#elif (CALL_DUMMY_LOCATION == ON_STACK) + call_dummy_start = sp; +#endif + + offset24 = (long) fun - (long) call_dummy_start; + offset24 &= 0x3fffff; + offset24 |= 0xff800000; /* jarl , r31 */ + + store_unsigned_integer ((unsigned int *)&dummy[2], 2, offset24 & 0xffff); + store_unsigned_integer ((unsigned int *)&dummy[0], 2, offset24 >> 16); + return 0; +} + void -_initialize_sparc_tdep () +_initialize_v850_tdep () { tm_print_insn = print_insn_v850; } diff --git a/gdb/valops.c b/gdb/valops.c index 273aa0e5432..b23d08b6f65 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -352,6 +352,20 @@ value_at (type, addr) val = allocate_value (type); +/* start-sanitize-d10v */ +#ifdef GDB_TARGET_IS_D10V + if (TYPE_TARGET_TYPE(type) && TYPE_CODE(TYPE_TARGET_TYPE(type)) == TYPE_CODE_FUNC) + { + int num; + short snum; + read_memory (addr, (char *)&snum, 2); + num = D10V_MAKE_IADDR(snum); + memcpy( VALUE_CONTENTS_RAW (val), &num, 4); + } + else +#endif +/* end-sanitize-d10v */ + read_memory (addr, VALUE_CONTENTS_RAW (val), TYPE_LENGTH (type)); VALUE_LVAL (val) = lval_memory; @@ -400,6 +414,21 @@ value_fetch_lazy (val) CORE_ADDR addr = VALUE_ADDRESS (val) + VALUE_OFFSET (val); int length = TYPE_LENGTH (VALUE_TYPE (val)); +/* start-sanitize-d10v */ +#ifdef GDB_TARGET_IS_D10V + struct type *type = VALUE_TYPE(val); + if (TYPE_TARGET_TYPE(type) && TYPE_CODE(TYPE_TARGET_TYPE(type)) == TYPE_CODE_FUNC) + { + int num; + short snum; + read_memory (addr, (char *)&snum, 2); + num = D10V_MAKE_IADDR(snum); + memcpy( VALUE_CONTENTS_RAW (val), &num, 4); + } + else +#endif +/* end-sanitize-d10v */ + if (length) read_memory (addr, VALUE_CONTENTS_RAW (val), length); VALUE_LAZY (val) = 0; @@ -633,7 +662,7 @@ Can't handle bitfield which doesn't fit in a single register."); && (VALUE_BITSIZE (toval) < 8 * (int) sizeof (LONGEST))) { LONGEST fieldval = value_as_long (fromval); - LONGEST valmask = (((unsigned LONGEST) 1) << VALUE_BITSIZE (toval)) - 1; + LONGEST valmask = (((ULONGEST) 1) << VALUE_BITSIZE (toval)) - 1; fieldval &= valmask; if (!TYPE_UNSIGNED (type) && (fieldval & (valmask ^ (valmask >> 1)))) @@ -683,25 +712,24 @@ value_of_variable (var, b) value_ptr val; struct frame_info *frame; - if (b == NULL) - /* Use selected frame. */ - frame = NULL; - else + if (!b) + frame = NULL; /* Use selected frame. */ + else if (symbol_read_needs_frame (var)) { frame = block_innermost_frame (b); - if (frame == NULL && symbol_read_needs_frame (var)) - { - if (BLOCK_FUNCTION (b) != NULL - && SYMBOL_NAME (BLOCK_FUNCTION (b)) != NULL) - error ("No frame is currently executing in block %s.", - SYMBOL_NAME (BLOCK_FUNCTION (b))); - else - error ("No frame is currently executing in specified block"); - } + if (!frame) + if (BLOCK_FUNCTION (b) + && SYMBOL_NAME (BLOCK_FUNCTION (b))) + error ("No frame is currently executing in block %s.", + SYMBOL_NAME (BLOCK_FUNCTION (b))); + else + error ("No frame is currently executing in specified block"); } + val = read_var_value (var, frame); - if (val == 0) + if (!val) error ("Address of symbol \"%s\" is unknown.", SYMBOL_SOURCE_NAME (var)); + return val; } @@ -815,7 +843,7 @@ value_ind (arg1) CORE_ADDR push_word (sp, word) CORE_ADDR sp; - unsigned LONGEST word; + ULONGEST word; { register int len = REGISTER_SIZE; char buffer[MAX_REGISTER_RAW_SIZE]; @@ -1032,10 +1060,10 @@ call_function_by_hand (function, nargs, args) CORE_ADDR start_sp; /* CALL_DUMMY is an array of words (REGISTER_SIZE), but each word is in host byte order. Before calling FIX_CALL_DUMMY, we byteswap it - and remove any extra bytes which might exist because unsigned LONGEST is + and remove any extra bytes which might exist because ULONGEST is bigger than REGISTER_SIZE. */ - static unsigned LONGEST dummy[] = CALL_DUMMY; - char dummy1[REGISTER_SIZE * sizeof dummy / sizeof (unsigned LONGEST)]; + static ULONGEST dummy[] = CALL_DUMMY; + char dummy1[REGISTER_SIZE * sizeof dummy / sizeof (ULONGEST)]; CORE_ADDR old_sp; struct type *value_type; unsigned char struct_return; @@ -1043,7 +1071,7 @@ call_function_by_hand (function, nargs, args) struct inferior_status inf_status; struct cleanup *old_chain; CORE_ADDR funaddr; - int using_gcc; + int using_gcc; /* Set to version of gcc in use, or zero if not gcc */ CORE_ADDR real_pc; struct type *ftype = check_typedef (SYMBOL_TYPE (function)); @@ -1073,8 +1101,8 @@ call_function_by_hand (function, nargs, args) { struct block *b = block_for_pc (funaddr); - /* If compiled without -g, assume GCC. */ - using_gcc = b == NULL ? 0 : BLOCK_GCC_COMPILED (b); + /* If compiled without -g, assume GCC 2. */ + using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b)); } /* Are we returning a value using a structure return or a normal @@ -1088,7 +1116,7 @@ call_function_by_hand (function, nargs, args) for (i = 0; i < (int) (sizeof (dummy) / sizeof (dummy[0])); i++) store_unsigned_integer (&dummy1[i * REGISTER_SIZE], REGISTER_SIZE, - (unsigned LONGEST)dummy[i]); + (ULONGEST)dummy[i]); #ifdef GDB_TARGET_IS_HPPA real_pc = FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args, @@ -1174,6 +1202,9 @@ call_function_by_hand (function, nargs, args) CORE_ADDR addr; int len = TYPE_LENGTH (arg_type); #ifdef STACK_ALIGN + /* MVS 11/22/96: I think at least some of this stack_align code is + really broken. Better to let PUSH_ARGUMENTS adjust the stack in + a target-defined manner. */ int aligned_len = STACK_ALIGN (len); #else int aligned_len = len; @@ -1210,6 +1241,9 @@ call_function_by_hand (function, nargs, args) { int len = TYPE_LENGTH (value_type); #ifdef STACK_ALIGN + /* MVS 11/22/96: I think at least some of this stack_align code is + really broken. Better to let PUSH_ARGUMENTS adjust the stack in + a target-defined manner. */ len = STACK_ALIGN (len); #endif #if 1 INNER_THAN 2 @@ -1221,9 +1255,12 @@ call_function_by_hand (function, nargs, args) #endif } -#ifdef STACK_ALIGN - /* If stack grows down, we must leave a hole at the top. */ +#if defined(STACK_ALIGN) && (1 INNER_THAN 2) + /* MVS 11/22/96: I think at least some of this stack_align code is + really broken. Better to let PUSH_ARGUMENTS adjust the stack in + a target-defined manner. */ { + /* If stack grows down, we must leave a hole at the top. */ int len = 0; for (i = nargs - 1; i >= 0; i--) @@ -1231,11 +1268,7 @@ call_function_by_hand (function, nargs, args) #ifdef CALL_DUMMY_STACK_ADJUST len += CALL_DUMMY_STACK_ADJUST; #endif -#if 1 INNER_THAN 2 sp -= STACK_ALIGN (len) - len; -#else - sp += STACK_ALIGN (len) - len; -#endif } #endif /* STACK_ALIGN */ @@ -1246,11 +1279,38 @@ call_function_by_hand (function, nargs, args) sp = value_push (sp, args[i]); #endif /* !PUSH_ARGUMENTS */ +#ifdef PUSH_RETURN_ADDRESS /* for targets that use no CALL_DUMMY */ + /* There are a number of targets now which actually don't write any + CALL_DUMMY instructions into the target, but instead just save the + machine state, push the arguments, and jump directly to the callee + function. Since this doesn't actually involve executing a JSR/BSR + instruction, the return address must be set up by hand, either by + pushing onto the stack or copying into a return-address register + as appropriate. Formerly this has been done in PUSH_ARGUMENTS, + but that's overloading its functionality a bit, so I'm making it + explicit to do it here. */ + sp = PUSH_RETURN_ADDRESS(real_pc, sp); +#endif /* PUSH_RETURN_ADDRESS */ + +#if defined(STACK_ALIGN) && !(1 INNER_THAN 2) + { + /* If stack grows up, we must leave a hole at the bottom, note + that sp already has been advanced for the arguments! */ +#ifdef CALL_DUMMY_STACK_ADJUST + sp += CALL_DUMMY_STACK_ADJUST; +#endif + sp = STACK_ALIGN (sp); + } +#endif /* STACK_ALIGN */ + +/* XXX This seems wrong. For stacks that grow down we shouldn't do + anything here! */ + /* MVS 11/22/96: I think at least some of this stack_align code is + really broken. Better to let PUSH_ARGUMENTS adjust the stack in + a target-defined manner. */ #ifdef CALL_DUMMY_STACK_ADJUST #if 1 INNER_THAN 2 sp -= CALL_DUMMY_STACK_ADJUST; -#else - sp += CALL_DUMMY_STACK_ADJUST; #endif #endif /* CALL_DUMMY_STACK_ADJUST */