diff options
author | Michael Snyder <msnyder@vmware.com> | 1996-11-27 19:10:07 +0000 |
---|---|---|
committer | Michael Snyder <msnyder@vmware.com> | 1996-11-27 19:10:07 +0000 |
commit | dc1b349d39a95d3944428155d352ff04c3115963 (patch) | |
tree | 432c778d293c925ed3e29a2f838719dcd574022c /gdb/sh-tdep.c | |
parent | 3bb3fe44e0f0ace7fb3894ce1e37f542aa5f4d89 (diff) | |
download | gdb-dc1b349d39a95d3944428155d352ff04c3115963.zip gdb-dc1b349d39a95d3944428155d352ff04c3115963.tar.gz gdb-dc1b349d39a95d3944428155d352ff04c3115963.tar.bz2 |
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 <msnyder@cleaver.cygnus.com>
* 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.
Diffstat (limited to 'gdb/sh-tdep.c')
-rw-r--r-- | gdb/sh-tdep.c | 378 |
1 files changed, 109 insertions, 269 deletions
diff --git a/gdb/sh-tdep.c b/gdb/sh-tdep.c index d8af915..d088f44 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 + <destination> + */ + +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))); -} - |