📄 i960-tdep.c
字号:
/* Target-machine dependent code for the Intel 960 Copyright (C) 1991 Free Software Foundation, Inc. Contributed by Intel Corporation. examine_prologue and other parts contributed by Wind River Systems.This file is part of GDB.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Miscellaneous i80960-dependent routines. Most are called from macros defined in "tm-i960.h". */#include "defs.h"#include <signal.h>#include "symtab.h"#include "value.h"#include "frame.h"#include "ieee-float.h"/* Structure of i960 extended floating point format. */const struct ext_format ext_format_i960 = {/* tot sbyte smask expbyte manbyte */ 12, 9, 0x80, 9,8, 4,0, /* i960 */};/* gdb960 is always running on a non-960 host. Check its characteristics. This routine must be called as part of gdb initialization. */static voidcheck_host(){ int i; static struct typestruct { int hostsize; /* Size of type on host */ int i960size; /* Size of type on i960 */ char *typename; /* Name of type, for error msg */ } types[] = { { sizeof(short), 2, "short" }, { sizeof(int), 4, "int" }, { sizeof(long), 4, "long" }, { sizeof(float), 4, "float" }, { sizeof(double), 8, "double" }, { sizeof(char *), 4, "pointer" }, };#define TYPELEN (sizeof(types) / sizeof(struct typestruct)) /* Make sure that host type sizes are same as i960 */ for ( i = 0; i < TYPELEN; i++ ){ if ( types[i].hostsize != types[i].i960size ){ printf("sizeof(%s) != %d: PROCEED AT YOUR OWN RISK!\n", types[i].typename, types[i].i960size ); } }}/* Examine an i960 function prologue, recording the addresses at which registers are saved explicitly by the prologue code, and returning the address of the first instruction after the prologue (but not after the instruction at address LIMIT, as explained below). LIMIT places an upper bound on addresses of the instructions to be examined. If the prologue code scan reaches LIMIT, the scan is aborted and LIMIT is returned. This is used, when examining the prologue for the current frame, to keep examine_prologue () from claiming that a given register has been saved when in fact the instruction that saves it has not yet been executed. LIMIT is used at other times to stop the scan when we hit code after the true function prologue (e.g. for the first source line) which might otherwise be mistaken for function prologue. The format of the function prologue matched by this routine is derived from examination of the source to gcc960 1.21, particularly the routine i960_function_prologue (). A "regular expression" for the function prologue is given below: (lda LRn, g14 mov g14, g[0-7] (mov 0, g14) | (lda 0, g14))? (mov[qtl]? g[0-15], r[4-15])* ((addo [1-31], sp, sp) | (lda n(sp), sp))? (st[qtl]? g[0-15], n(fp))* (cmpobne 0, g14, LFn mov sp, g14 lda 0x30(sp), sp LFn: stq g0, (g14) stq g4, 0x10(g14) stq g8, 0x20(g14))? (st g14, n(fp))? (mov g13,r[4-15])?*//* Macros for extracting fields from i960 instructions. */#define BITMASK(pos, width) (((0x1 << (width)) - 1) << (pos))#define EXTRACT_FIELD(val, pos, width) ((val) >> (pos) & BITMASK (0, width))#define REG_SRC1(insn) EXTRACT_FIELD (insn, 0, 5)#define REG_SRC2(insn) EXTRACT_FIELD (insn, 14, 5)#define REG_SRCDST(insn) EXTRACT_FIELD (insn, 19, 5)#define MEM_SRCDST(insn) EXTRACT_FIELD (insn, 19, 5)#define MEMA_OFFSET(insn) EXTRACT_FIELD (insn, 0, 12)/* Fetch the instruction at ADDR, returning 0 if ADDR is beyond LIM or is not the address of a valid instruction, the address of the next instruction beyond ADDR otherwise. *PWORD1 receives the first word of the instruction, and (for two-word instructions), *PWORD2 receives the second. */#define NEXT_PROLOGUE_INSN(addr, lim, pword1, pword2) \ (((addr) < (lim)) ? next_insn (addr, pword1, pword2) : 0)static CORE_ADDRexamine_prologue (ip, limit, frame_addr, fsr) register CORE_ADDR ip; register CORE_ADDR limit; FRAME_ADDR frame_addr; struct frame_saved_regs *fsr;{ register CORE_ADDR next_ip; register int src, dst; register unsigned int *pcode; unsigned int insn1, insn2; int size; int within_leaf_prologue; CORE_ADDR save_addr; static unsigned int varargs_prologue_code [] = { 0x3507a00c, /* cmpobne 0x0, g14, LFn */ 0x5cf01601, /* mov sp, g14 */ 0x8c086030, /* lda 0x30(sp), sp */ 0xb2879000, /* LFn: stq g0, (g14) */ 0xb2a7a010, /* stq g4, 0x10(g14) */ 0xb2c7a020 /* stq g8, 0x20(g14) */ }; /* Accept a leaf procedure prologue code fragment if present. Note that ip might point to either the leaf or non-leaf entry point; we look for the non-leaf entry point first: */ within_leaf_prologue = 0; if ((next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2)) && ((insn1 & 0xfffff000) == 0x8cf00000 /* lda LRx, g14 (MEMA) */ || (insn1 & 0xfffffc60) == 0x8cf03000)) /* lda LRx, g14 (MEMB) */ { within_leaf_prologue = 1; next_ip = NEXT_PROLOGUE_INSN (next_ip, limit, &insn1, &insn2); } /* Now look for the prologue code at a leaf entry point: */ if (next_ip && (insn1 & 0xff87ffff) == 0x5c80161e /* mov g14, gx */ && REG_SRCDST (insn1) <= G0_REGNUM + 7) { within_leaf_prologue = 1; if ((next_ip = NEXT_PROLOGUE_INSN (next_ip, limit, &insn1, &insn2)) && (insn1 == 0x8cf00000 /* lda 0, g14 */ || insn1 == 0x5cf01e00)) /* mov 0, g14 */ { ip = next_ip; next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); within_leaf_prologue = 0; } } /* If something that looks like the beginning of a leaf prologue has been seen, but the remainder of the prologue is missing, bail. We don't know what we've got. */ if (within_leaf_prologue) return (ip); /* Accept zero or more instances of "mov[qtl]? gx, ry", where y >= 4. This may cause us to mistake the moving of a register parameter to a local register for the saving of a callee-saved register, but that can't be helped, since with the "-fcall-saved" flag, any register can be made callee-saved. */ while (next_ip && (insn1 & 0xfc802fb0) == 0x5c000610 && (dst = REG_SRCDST (insn1)) >= (R0_REGNUM + 4)) { src = REG_SRC1 (insn1); size = EXTRACT_FIELD (insn1, 24, 2) + 1; save_addr = frame_addr + ((dst - R0_REGNUM) * 4); while (size--) { fsr->regs[src++] = save_addr; save_addr += 4; } ip = next_ip; next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); } /* Accept an optional "addo n, sp, sp" or "lda n(sp), sp". */ if (next_ip && ((insn1 & 0xffffffe0) == 0x59084800 /* addo n, sp, sp */ || (insn1 & 0xfffff000) == 0x8c086000 /* lda n(sp), sp (MEMA) */ || (insn1 & 0xfffffc60) == 0x8c087400)) /* lda n(sp), sp (MEMB) */ { ip = next_ip; next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); } /* Accept zero or more instances of "st[qtl]? gx, n(fp)". This may cause us to mistake the copying of a register parameter to the frame for the saving of a callee-saved register, but that can't be helped, since with the "-fcall-saved" flag, any register can be made callee-saved. We can, however, refuse to accept a save of register g14, since that is matched explicitly below. */ while (next_ip && ((insn1 & 0xf787f000) == 0x9287e000 /* stl? gx, n(fp) (MEMA) */ || (insn1 & 0xf787fc60) == 0x9287f400 /* stl? gx, n(fp) (MEMB) */ || (insn1 & 0xef87f000) == 0xa287e000 /* st[tq] gx, n(fp) (MEMA) */ || (insn1 & 0xef87fc60) == 0xa287f400) /* st[tq] gx, n(fp) (MEMB) */ && ((src = MEM_SRCDST (insn1)) != G14_REGNUM)) { save_addr = frame_addr + ((insn1 & BITMASK (12, 1)) ? insn2 : MEMA_OFFSET (insn1)); size = (insn1 & BITMASK (29, 1)) ? ((insn1 & BITMASK (28, 1)) ? 4 : 3) : ((insn1 & BITMASK (27, 1)) ? 2 : 1); while (size--) { fsr->regs[src++] = save_addr; save_addr += 4; } ip = next_ip; next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); } /* Accept the varargs prologue code if present. */ size = sizeof (varargs_prologue_code) / sizeof (int); pcode = varargs_prologue_code; while (size-- && next_ip && *pcode++ == insn1) { ip = next_ip; next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); } /* Accept an optional "st g14, n(fp)". */ if (next_ip && ((insn1 & 0xfffff000) == 0x92f7e000 /* st g14, n(fp) (MEMA) */ || (insn1 & 0xfffffc60) == 0x92f7f400)) /* st g14, n(fp) (MEMB) */ { fsr->regs[G14_REGNUM] = frame_addr + ((insn1 & BITMASK (12, 1)) ? insn2 : MEMA_OFFSET (insn1)); ip = next_ip; next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2); } /* Accept zero or one instance of "mov g13, ry", where y >= 4. This is saving the address where a struct should be returned. */ if (next_ip && (insn1 & 0xff802fbf) == 0x5c00061d && (dst = REG_SRCDST (insn1)) >= (R0_REGNUM + 4)) { save_addr = frame_addr + ((dst - R0_REGNUM) * 4); fsr->regs[G0_REGNUM+13] = save_addr; ip = next_ip;#if 0 /* We'll need this once there is a subsequent instruction examined. */ next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn1, &insn2);#endif } return (ip);}/* Given an ip value corresponding to the start of a function, return the ip of the first instruction after the function prologue. */CORE_ADDRskip_prologue (ip) CORE_ADDR (ip);{ struct frame_saved_regs saved_regs_dummy; struct symtab_and_line sal; CORE_ADDR limit; sal = find_pc_line (ip, 0); limit = (sal.end) ? sal.end : 0xffffffff; return (examine_prologue (ip, limit, (FRAME_ADDR) 0, &saved_regs_dummy));}/* 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. We cache the result of doing this in the frame_cache_obstack, since it is fairly expensive. */voidframe_find_saved_regs (fi, fsr) struct frame_info *fi;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -