diff options
author | Michael Snyder <msnyder@vmware.com> | 1996-10-31 02:27:58 +0000 |
---|---|---|
committer | Michael Snyder <msnyder@vmware.com> | 1996-10-31 02:27:58 +0000 |
commit | 70ab088d0825bc9f7cb8f5dc68459cbe0f5e3e8e (patch) | |
tree | 90a6ee9e484d582e24adc1a9c93ac4d847e0336a | |
parent | 1d3d059535100faba2a48f7428ab792185e45225 (diff) | |
download | fsf-binutils-gdb-70ab088d0825bc9f7cb8f5dc68459cbe0f5e3e8e.zip fsf-binutils-gdb-70ab088d0825bc9f7cb8f5dc68459cbe0f5e3e8e.tar.gz fsf-binutils-gdb-70ab088d0825bc9f7cb8f5dc68459cbe0f5e3e8e.tar.bz2 |
Wed Oct 30 18:14:14 1996 Michael Snyder <msnyder@cleaver.cygnus.com>
* m32r-tdep.c, m32r-rom.c: New files.
* config/m32r/m32r.mt: New file.
* config/m32r/tm-m32r.h: New file.
-rw-r--r-- | gdb/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/config/m32r/tm-m32r.h | 211 | ||||
-rw-r--r-- | gdb/m32r-tdep.c | 380 |
3 files changed, 600 insertions, 1 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4474faa..ba38cff 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,9 +1,17 @@ +start-sanitize-m32r +Wed Oct 30 18:14:14 1996 Michael Snyder <msnyder@cleaver.cygnus.com> + + * m32r-tdep.c, m32r-rom.c: New files. + * config/m32r/m32r.mt: New file. + * config/m32r/tm-m32r.h: New file. +end-sanitize-m32r + Tue Oct 29 16:56:01 1996 Geoffrey Noer <noer@cygnus.com> * config/i386/xm-cygwin32.h: * config/powerpc/xm-cygwin32.h: add #define LSEEK_NOT_LINEAR so source lines aren't unexpectedly - truncated + truncated. Tue Oct 29 18:36:43 1996 Michael Meissner <meissner@tiktok.cygnus.com> diff --git a/gdb/config/m32r/tm-m32r.h b/gdb/config/m32r/tm-m32r.h new file mode 100644 index 0000000..4dc04be --- /dev/null +++ b/gdb/config/m32r/tm-m32r.h @@ -0,0 +1,211 @@ +/* Parameters for execution on a Mitsubishi m32r processor. + 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. */ + +/* mvs_check TARGET_BYTE_ORDER BIG_ENDIAN */ +#define TARGET_BYTE_ORDER BIG_ENDIAN + +/* mvs_check REGISTER_NAMES */ +#define REGISTER_NAMES \ +{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "r10", "r11", "r12", "fp", "lr", "sp", \ + "psw", "cbr", "spi", "spu", "bpc", "pc", "accl", "acch", \ + /* "cond", "sm", "bsm", "ie", "bie", "bcarry", */ \ +} +/* mvs_check NUM_REGS */ +#define NUM_REGS 24 + +/* mvs_check REGISTER_SIZE */ +#define REGISTER_SIZE 4 +/* mvs_check MAX_REGISTER_RAW_SIZE */ +#define MAX_REGISTER_RAW_SIZE 4 + +/* mvs_check *_REGNUM */ +#define R0_REGNUM 0 +#define ARG0_REGNUM 0 +#define ARGLAST_REGNUM 3 +#define V0_REGNUM 0 +#define V1_REGNUM 1 +#define FP_REGNUM 13 +#define RP_REGNUM 14 +#define SP_REGNUM 15 +#define PSW_REGNUM 16 +#define CBR_REGNUM 17 +#define SPI_REGNUM 18 +#define SPU_REGNUM 19 +#define BPC_REGNUM 20 +#define PC_REGNUM 21 +#define ACCL_REGNUM 22 +#define ACCH_REGNUM 23 + +/* mvs_check REGISTER_BYTES */ +#define REGISTER_BYTES (NUM_REGS * 4) + +/* mvs_check REGISTER_VIRTUAL_TYPE */ +#define REGISTER_VIRTUAL_TYPE(REG) builtin_type_int + +/* mvs_check REGISTER_BYTE */ +#define REGISTER_BYTE(REG) ((REG) * 4) +/* mvs_check REGISTER_VIRTUAL_SIZE */ +#define REGISTER_VIRTUAL_SIZE(REG) 4 +/* mvs_check REGISTER_RAW_SIZE */ +#define REGISTER_RAW_SIZE(REG) 4 + +/* mvs_check MAX_REGISTER_VIRTUAL_SIZE */ +#define MAX_REGISTER_VIRTUAL_SIZE 4 + +/* mvs_check BREAKPOINT */ +#define BREAKPOINT {0x10, 0xf1} + +/* mvs_no_check FUNCTION_START_OFFSET */ +#define FUNCTION_START_OFFSET 0 + +/* mvs_check DECR_PC_AFTER_BREAK */ +#define DECR_PC_AFTER_BREAK 0 + +/* mvs_check INNER_THAN */ +#define INNER_THAN < + +/* mvs_check SAVED_PC_AFTER_CALL */ +#define SAVED_PC_AFTER_CALL(fi) read_register (RP_REGNUM) + +#ifdef __STDC__ +struct frame_info; +struct frame_saved_regs; +struct type; +struct value; +#endif + +/* #define EXTRA_FRAME_INFO struct frame_saved_regs fsr; */ +/* Define other aspects of the stack frame. + we keep a copy of the worked out return pc lying around, since it + is a useful bit of info */ + +/* mvs_check EXTRA_FRAME_INFO */ +#define EXTRA_FRAME_INFO struct frame_saved_regs fsr; + +extern void m32r_init_extra_frame_info PARAMS ((struct frame_info *fi)); +/* mvs_check INIT_EXTRA_FRAME_INFO */ +#define INIT_EXTRA_FRAME_INFO(fromleaf, fi) m32r_init_extra_frame_info (fi) +/* mvs_no_check INIT_FRAME_PC */ +#define INIT_FRAME_PC /* Not necessary */ + +extern void +m32r_frame_find_saved_regs PARAMS ((struct frame_info *fi, + struct frame_saved_regs *regaddr)); + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +/* mvs_check FRAME_FIND_SAVED_REGS */ +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ + m32r_frame_find_saved_regs(frame_info, &(frame_saved_regs)) + +extern CORE_ADDR m32r_frame_chain PARAMS ((struct frame_info *fi)); +/* mvs_check FRAME_CHAIN */ +#define FRAME_CHAIN(fi) m32r_frame_chain (fi) + +extern CORE_ADDR m32r_find_callers_reg PARAMS ((struct frame_info *fi, + int regnum)); +/* mvs_check FRAME_SAVED_PC */ +#define FRAME_SAVED_PC(fi) (m32r_find_callers_reg (fi, RP_REGNUM)) + +/* mvs_check EXTRACT_RETURN_VALUE */ +#define EXTRACT_RETURN_VALUE(TYPE, REGBUF, VALBUF) \ + memcpy ((VALBUF), \ + (char *)(REGBUF) + REGISTER_BYTE (V0_REGNUM) + \ + ((TYPE_LENGTH (TYPE) > 4 ? 8 : 4) - TYPE_LENGTH (TYPE)), \ + TYPE_LENGTH (TYPE)) + +/* mvs_check STORE_RETURN_VALUE */ +#define STORE_RETURN_VALUE(TYPE, VALBUF) \ + write_register_bytes(REGISTER_BYTE (V0_REGNUM) + \ + ((TYPE_LENGTH (TYPE) > 4 ? 8:4) - TYPE_LENGTH (TYPE)),\ + (VALBUF), TYPE_LENGTH (TYPE)); + +/* mvs_check EXTRACT_STRUCT_VALUE_ADDRESS */ +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \ + (extract_address (REGBUF + REGISTER_BYTE (V0_REGNUM), \ + REGISTER_RAW_SIZE (V0_REGNUM))) + +extern CORE_ADDR m32r_skip_prologue PARAMS ((CORE_ADDR pc)); +/* mvs_check SKIP_PROLOGUE */ +#define SKIP_PROLOGUE(pc) pc = m32r_skip_prologue (pc) + +/* mvs_no_check FRAME_ARGS_SKIP */ +#define FRAME_ARGS_SKIP 0 + +/* mvs_no_check FRAME_ARGS_ADDRESS */ +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) +/* mvs_no_check FRAME_LOCALS_ADDRESS */ +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) +/* mvs_no_check FRAME_NUM_ARGS */ +#define FRAME_NUM_ARGS(val, fi) ((val) = -1) + +extern struct frame_info *m32r_pop_frame PARAMS ((struct frame_info *frame)); +/* mvs_check POP_FRAME */ +#define POP_FRAME m32r_pop_frame (get_current_frame ()) + +/* mvs_no_check CALL_DUMMY */ +/* #define CALL_DUMMY { 0 } */ + +/* mvs_no_check CALL_DUMMY_START_OFFSET */ +#define CALL_DUMMY_START_OFFSET (0) + +/* mvs_no_check CALL_DUMMY_BREAKPOINT_OFFSET */ +#define CALL_DUMMY_BREAKPOINT_OFFSET (0) + +extern void m32r_push_dummy_frame PARAMS ((void)); +/* mvs_no_check PUSH_DUMMY_FRAME */ +#define PUSH_DUMMY_FRAME m32r_push_dummy_frame () + +/* mvs_no_check FIX_CALL_DUMMY */ +#define FIX_CALL_DUMMY(DUMMY1, START_SP, FUNADDR, NARGS, \ + ARGS, VALUE_TYPE, USING_GCC) + +/* mvs_no_check CALL_DUMMY_LOCATION_AT_ENTRY_POINT */ +#define CALL_DUMMY_LOCATION AT_ENTRY_POINT + +/* mvs_no_check STACK_ALIGN */ +#define STACK_ALIGN(x) ((x + 3) & ~3) + +extern CORE_ADDR +m32r_push_arguments PARAMS ((int nargs, struct value **args, CORE_ADDR sp, + unsigned char struct_return, + CORE_ADDR struct_addr)); +/* mvs_no_check PUSH_ARGUMENTS */ +#define PUSH_ARGUMENTS(NARGS, ARGS, SP, STRUCT_RETURN, STRUCT_ADDR) \ + (SP) = m32r_push_arguments (NARGS, ARGS, SP, STRUCT_RETURN, STRUCT_ADDR) + +/* mvs_no_check STORE_STRUCT_RETURN */ +#define STORE_STRUCT_RETURN(STRUCT_ADDR, SP) + +/* mvs_no_check CALL_DUMMY_ADDRESS */ +#define CALL_DUMMY_ADDRESS() (entry_point_address ()) + +extern int m32r_pc_in_call_dummy PARAMS ((CORE_ADDR pc)); +/* mvs_no_check PC_IN_CALL_DUMMY */ +#define PC_IN_CALL_DUMMY(PC, SP, FP) m32r_pc_in_call_dummy (PC) + +/* mvs_check USE_STRUCT_CONVENTION */ +#define USE_STRUCT_CONVENTION(GCC_P, TYPE) \ + (TYPE_LENGTH (TYPE) > 8) 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; +} |