📄 mips-tdep.c
字号:
/* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger. Copyright 1988, 1989, 1990, 1991, 1992 Free Software Foundation, Inc. Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.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. */#include "defs.h"#include "target.h"#include "frame.h"#include "inferior.h"#include "symtab.h"#include "value.h"#include "gdbcmd.h"#include "language.h"#ifdef USG#include <sys/types.h>#endif#include <sys/param.h>#include <sys/dir.h>#include <signal.h>#include <sys/ioctl.h>#include "gdbcore.h"#include "symfile.h"#include "objfiles.h"#ifndef MIPSMAGIC#ifdef MIPSEL#define MIPSMAGIC MIPSELMAGIC#else#define MIPSMAGIC MIPSEBMAGIC#endif#endif#define VM_MIN_ADDRESS (unsigned)0x400000#include <sys/user.h> /* After a.out.h */#include <sys/file.h>#include <sys/stat.h>#ifdef KERNELDEBUGextern int kernel_debugging;#endif/* * The MIPS architecture does not provide a trace bit. However, most * (if not all) OS's that run on the MIPS emulate single stepping in * the kernel. This unfortunately does not work for the kernel debugger. * Thus, we duplicate the functionality here. *//* * For the instruction INSN at PC, if it is a control transfer, return the * target address, otherwise return 0. * * Instruction decoding per "MIPS RISC Architecture" by Gerry Kane * and Joe Heinrich, Prentice Hall, 1992. Fig. A-3, Page A-143. */CORE_ADDRbranchtarget(insn, pc) u_long insn; CORE_ADDR pc;{ int opcode = (insn >> 26) & 0x3f; u_long v; switch (opcode) { case 0x00: /* SPECIAL */ v = insn & 0x3f; if (v == 8 || v == 9) { int rs = (insn >> 21) & 0x1f; return (read_register(rs)); } return (0); case 0x01: /* REGIMM */ v = (insn >> 16) & 0x1f; switch (v) { default: return (0); case 0x00: /* BLTZ */ case 0x01: /* BGEZ */ case 0x02: /* BLTZL */ case 0x03: /* BGEZL */ case 0x10: /* BLTZAL */ case 0x11: /* BGEZAL */ case 0x12: /* BLTZALL */ case 0x13: /* BGEZALL */ break; } /* fall through */ case 0x04: /* BEQ */ case 0x05: /* BNE */ case 0x06: /* BLEZ */ case 0x07: /* GTRZ */ v = insn & 0xffff; if (v & 0x8000) v |= 0xffff0000; v <<= 2; return (pc + 4 + v); case 0x02: /* J */ case 0x03: /* JAL */ v = (insn & 0x03ffffff) << 2; return (((pc + 4) & 0xf0000000) | v); case 0x10: /* COP0 */ case 0x11: /* COP1 */ case 0x12: /* COP2 */ case 0x13: /* COP3 */ v = (insn >> 21) & 0x1f; if (v == 8) { v = insn & 0xffff; if (v & 0x8000) v |= 0xffff0000; v <<= 2; return (pc + 4 + v); } } return (0);}intis_call_insn(insn) u_long insn;{ int opcode = (insn >> 26) & 0x3f; if (opcode == 3) /* JAL */ return (1); if (opcode == 0) { /* SPECIAL */ int v = insn & 0x3f; /* JALR */ return (v == 9); } if (opcode == 1) { /* REGIMM */ int v = (insn >> 19) & 3; /* BLTZAL etc. */ return (v == 2); } return (0);}/* * Non-zero if we just simulated a single-step ptrace call. This is * needed because we cannot remove the breakpoints in the inferior * process until after the `wait' in `wait_for_inferior'. * Used for sun4. */int one_stepped;/* * single_step() is called just before we want to resume the inferior, * if we want to single-step it but there is no hardware or kernel single-step * support (as on all SPARCs). We find all the possible targets of the * coming instruction and breakpoint them. * * single_step is also called just after the inferior stops. If we had * set up a simulated single-step, we undo our damage. * * Code written by Gary Beihl (beihl@mcc.com); modified by Steven McCanne * (mccanne@ee.lbl.gov). */voidsingle_step(signal) int signal;{ CORE_ADDR pc; u_long insn; /* * Storage for temporary breakpoints. XXX There should be a uniform * interface for breakpoints, so that we could just set one then * clear it. Note that we need only two outstanding breakpoints, * since there can be at most two possiblilities for control flow. */ static CORE_ADDR target0; static CORE_ADDR target1; static char shadow0[4]; static char shadow1[4]; pc = read_register(PC_REGNUM); insn = read_memory_integer(pc, 4); if (!one_stepped) { /* * This is a hack to special case call instructions. * If we are stepping over subroutines, find each call * and trap on return, rather than single step until * wait_for_inferior() discovers that we hit a new routine. * The reason is that stepping over functions in a remote * kernel can have bad results when the function being * stepped over is used by the kernel in between traps. * (i.e., a trap instruction gets poked into the function * being stepped over). */ if (step_over_calls > 0 && is_call_insn(insn)) { target0 = pc + 8; target1 = 0; } else { target0 = pc + 4; target1 = branchtarget(insn, pc); if (target1 != 0) { /* * Punt on stepping through delay slot. * On the sparc, this is easy because of * npc; on the mips, it's trickier * because we'd have to keep track * of when we're in the delay slot (and * gdb will get confused because the * cpu leaves the epc pointing to the * previous instruction). Moreover, the * architecture would require that we * interpret the branch intruction if * we want to set a breakpoint in the * delay slot. */ target0 += 4; } if (target1 == target0) target1 = 0; } target_insert_breakpoint(target0, shadow0); if (target1) target_insert_breakpoint(target1, shadow1); one_stepped = 1; } else { /* Remove breakpoints */ if (target1) target_remove_breakpoint(target1, shadow1); target_remove_breakpoint(target0, shadow0); one_stepped = 0; }}#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */#define PROC_HIGH_ADDR(proc) ((proc)->pdr.iline) /* upper address bound */#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset)#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg)#define PROC_REG_MASK(proc) ((proc)->pdr.regmask)#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask)#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset)#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset)#define PROC_PC_REG(proc) ((proc)->pdr.pcreg)#define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->pdr.isym)#define _PROC_MAGIC_ 0x0F0F0F0F#define PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym == _PROC_MAGIC_)#define SET_PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym = _PROC_MAGIC_)struct linked_proc_info{ struct mips_extra_func_info info; struct linked_proc_info *next;} *linked_proc_desc_table = NULL;#define READ_FRAME_REG(fi, regno) read_next_frame_reg((fi)->next, regno)static intread_next_frame_reg(fi, regno) FRAME fi; int regno;{#define SIGFRAME_BASE sizeof(struct sigcontext)#define SIGFRAME_PC_OFF (-SIGFRAME_BASE+ 2*sizeof(int))#define SIGFRAME_SP_OFF (-SIGFRAME_BASE+32*sizeof(int))#define SIGFRAME_RA_OFF (-SIGFRAME_BASE+34*sizeof(int)) for (; fi; fi = fi->next) {#ifdef KERNELDEBUG if (kernel_debugging && in_trap_handler(fi->pc)) { int offset; if (regno == PC_REGNUM) offset = 40; else if (regno == RA_REGNUM) offset = 34; else if (regno == SP_REGNUM) offset = 32; else return 0; return read_memory_integer(fi->frame + 4 * offset, 4); }#endif if (in_sigtramp(fi->pc, 0)) { /* No idea if this code works. --PB. */ int offset; if (regno == PC_REGNUM) offset = SIGFRAME_PC_OFF; else if (regno == RA_REGNUM) offset = SIGFRAME_RA_OFF; else if (regno == SP_REGNUM) offset = SIGFRAME_SP_OFF; else return 0; return read_memory_integer(fi->frame + offset, 4); } else if (regno == SP_REGNUM) return fi->frame; else if (fi->saved_regs->regs[regno]) return read_memory_integer(fi->saved_regs->regs[regno], 4); } return read_register(regno);}intmips_frame_saved_pc(frame) FRAME frame;{ mips_extra_func_info_t proc_desc = frame->proc_desc; int pcreg = proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM;#ifdef KERNELDEBUG if (kernel_debugging && in_trap_handler(frame->pc)) return read_memory_integer(frame->frame + 4 * 40, 4);#endif if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc)) return read_memory_integer(frame->frame - 4, 4); return read_next_frame_reg(frame, pcreg);}static struct mips_extra_func_info temp_proc_desc;static struct frame_saved_regs temp_saved_regs;static CORE_ADDRheuristic_proc_start(pc) CORE_ADDR pc;{ CORE_ADDR start_pc = pc; CORE_ADDR fence = start_pc - 200; if (start_pc == 0) return 0; if (fence < VM_MIN_ADDRESS) fence = VM_MIN_ADDRESS; /* search back for previous return */ for (start_pc -= 4; ; start_pc -= 4) if (start_pc < fence) return 0; else if (ABOUT_TO_RETURN(start_pc)) break; start_pc += 8; /* skip return, and its delay slot */#if 0 /* skip nops (usually 1) 0 - is this */ while (start_pc < pc && read_memory_integer (start_pc, 4) == 0) start_pc += 4;#endif return start_pc;}static mips_extra_func_info_theuristic_proc_desc(start_pc, limit_pc, next_frame) CORE_ADDR start_pc, limit_pc; FRAME next_frame;{ CORE_ADDR sp = next_frame ? next_frame->frame : read_register (SP_REGNUM); CORE_ADDR cur_pc; int frame_size; int has_frame_reg = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -