diff options
Diffstat (limited to 'gdb/m32r-tdep.c')
-rw-r--r-- | gdb/m32r-tdep.c | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/gdb/m32r-tdep.c b/gdb/m32r-tdep.c new file mode 100644 index 0000000..a449223 --- /dev/null +++ b/gdb/m32r-tdep.c @@ -0,0 +1,380 @@ +/* Target-dependent code for the Mitsubishi m32r for GDB, the GNU debugger. + Copyright 1996, Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "obstack.h" +#include "target.h" +#include "value.h" +#include "bfd.h" +#include "gdb_string.h" +#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; +}; + +void +m32r_frame_find_saved_regs PARAMS ((struct frame_info *fi, + struct frame_saved_regs *regaddr)) +{ + *regaddr = fi->fsr; +} + +static struct dummy_frame *dummy_frame_stack = NULL; + +/* Find end of function prologue */ + +CORE_ADDR +m32r_skip_prologue (pc) + CORE_ADDR pc; +{ + CORE_ADDR func_addr, func_end; + struct symtab_and_line sal; + + /* See what the symbol table says */ + + if (find_pc_partial_function (pc, NULL, &func_addr, &func_end)) + { + sal = find_pc_line (func_addr, 0); + + if (sal.line != 0 && sal.end < func_end) + return sal.end; + else + /* Either there's no line info, or the line after the prologue is after + the end of the function. In this case, there probably isn't a + prologue. */ + return pc; + } + + /* We can't find the start of this function, so there's nothing we can do. */ + return pc; +} + +/* 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. +*/ + +static unsigned long +m32r_scan_prologue (fi, fsr) + struct frame_info *fi; + struct frame_saved_regs *fsr; +{ + struct symtab_and_line sal; + CORE_ADDR prologue_start, prologue_end, current_pc; + unsigned long framesize; + + /* this code essentially duplicates skip_prologue, + but we need the start address below. */ + + if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end)) + { + sal = find_pc_line (prologue_start, 0); + + if (sal.line == 0) /* no line info, use current PC */ + prologue_end = fi->pc; + else if (sal.end < prologue_end) /* next line begins after fn end */ + prologue_end = sal.end; /* (probably means no prologue) */ + } + else + prologue_end = prologue_start + 100; /* We're in the boondocks */ + + prologue_end = min (prologue_end, fi->pc); + + /* Now, search the prologue looking for instructions that setup fp, save + rp (and other regs), adjust sp and such. */ + + framesize = 0; + memset (fsr->regs, '\000', sizeof fsr->regs); + + for (current_pc = prologue_start; current_pc < prologue_end; current_pc += 2) + { + int insn; + int regno; + + insn = read_memory_unsigned_integer (current_pc, 2); + if (insn & 0x80) /* Four byte instruction? */ + current_pc += 2; + + if ((insn & 0xf0ff) == 0x207f) { /* st reg, @-sp */ + framesize += 4; + regno = ((insn >> 8) & 0xf); + fsr->regs[regno] = framesize; + } + else if ((insn >> 8) == 0x4f) { /* addi sp */ + framesize += -((char) (insn & 0xff)); /* offset */ + break; /* end of stack adjustments */ + } + } + return framesize; +} + +/* This function actually figures out the frame address for a given pc and + sp. This is tricky on the v850 because we only use an explicit frame + pointer when using alloca(). The only reliable way to get this info is to + examine the prologue. +*/ + +void +m32r_init_extra_frame_info (fi) + struct frame_info *fi; +{ + int reg; + int framesize; + + if (fi->next) + fi->pc = FRAME_SAVED_PC (fi->next); + + framesize = m32r_scan_prologue (fi, &fi->fsr); + + if (PC_IN_CALL_DUMMY (fi->pc, NULL, NULL)) + fi->frame = dummy_frame_stack->sp; + else if (!fi->next) + fi->frame = read_register (SP_REGNUM); + + for (reg = 0; reg < NUM_REGS; reg++) + if (fi->fsr.regs[reg] != 0) + fi->fsr.regs[reg] = fi->frame + 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. */ + +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); + return read_register (regnum); +} + +/* 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, simply get the saved FP off the stack. + */ + +CORE_ADDR +m32r_frame_chain (fi) + struct frame_info *fi; +{ + CORE_ADDR saved_fp = fi->fsr.regs[FP_REGNUM]; + + if (saved_fp == 0) + return 0; /* frameless assembly language fn (such as _start) */ + + return read_memory_integer (saved_fp, 4); +} + +/* 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 + */ + +int +m32r_pc_in_call_dummy (pc) + CORE_ADDR pc; +{ + return dummy_frame_stack + && pc >= CALL_DUMMY_ADDRESS () + && pc <= CALL_DUMMY_ADDRESS () + DECR_PC_AFTER_BREAK; +} + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ + +struct frame_info * +m32r_pop_frame (frame) + struct frame_info *frame; +{ + int regnum; + +#if 0 + 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 (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; + } + +#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). + + By the time we get here, stack space has been allocated for the args, but + not for the struct return pointer. */ + +CORE_ADDR +m32r_push_arguments (nargs, args, sp, struct_return, struct_addr) + int nargs; + value_ptr *args; + CORE_ADDR sp; + unsigned char struct_return; + CORE_ADDR struct_addr; +{ + int argreg; + int argnum; + + argreg = ARG0_REGNUM; + +#if 0 + if (struct_return) + { + write_register (argreg++, struct_addr); + sp -= 4; + } + + for (argnum = 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; + } + else + { + len = TYPE_LENGTH (VALUE_TYPE (*args)); + val = (char *)VALUE_CONTENTS (*args); + } + + while (len > 0) + if (argreg <= ARGLAST_REGNUM) + { + CORE_ADDR regval; + + regval = extract_address (val, REGISTER_RAW_SIZE (argreg)); + write_register (argreg, regval); + + len -= REGISTER_RAW_SIZE (argreg); + val += REGISTER_RAW_SIZE (argreg); + argreg++; + } + else + { + write_memory (sp + argnum * 4, val, 4); + + len -= 4; + val += 4; + } + args++; + } + + write_register (RP_REGNUM, entry_point_address ()); + +#endif + return sp; +} + +void +_initialize_m32r_tdep () +{ + tm_print_insn = print_insn_m32r; +} |