📄 smash_insts.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * *//* * smashinst.c * * A function to be called from tcl when it is time to * smash an instruction at a given address for fault injection * experiments. * * We do this in C since we need to decompose instructions to * figure out what to do. * * Let tcl pass us the address to smash and the random number that * controls what we do, so the experiments are repeatable if needed. */#include <stdlib.h>#include "simtypes.h"#include "cpu.h"#include "cpu_interface.h"#include "mips_arch.h"#include "stdio.h"#include "sim_error.h"#include "string.h"#include "math.h"/* how random number is interpreted. * modify dest of ALU op: change register * modify dest of branch op: change < to <= */struct randomsmash { uint fill : 23; uint regnum : 5; /* random register number */ uint modify_or_delete : 2; /* 1,2,3 = modify instr, 0 = delete it */ uint source_or_dest : 1; /* 1 = modify source, 0 = modify dest */ uint rs_or_rt : 1; /* 1 = modify source rs, 0 = mod source rt */};#define DELETE_INST 0#define MODIFY_DEST 0#define MODIFY_SOURCE 0typedef enum {change_none, change_rs, change_rt, change_rd} changetype;#if !defined __alpha && !defined __linuxextern long random(void);#endifResultsmashinst(int dosmash, int cpunum, VA addr, int rnd, char* errbuf){ uint op; /* extracted instruction opcode */ uint nreg; Inst instr = 0; #ifdef PRINT_INSTRUCTIONS Inst orig_instr = 0;#endif Result r = SUCCESS; struct randomsmash* smashtype = (struct randomsmash*) &rnd; changetype ct = change_none; uint64 field0; char fnamebuf[64]; strncpy(fnamebuf, errbuf, 63); r = CPUVec.GetMemory(cpunum, addr, INST_SIZE, (char*) &instr);#ifdef PRINT_INSTRUCTIONS orig_instr = instr;#endif if (r != SUCCESS) { sprintf(errbuf, "Can't read instruction at address 0x%llx", (Reg64)addr); return FAILURE; } if (instr == 0) { /* can't do anything to a nop */ goto retry; } if (smashtype->modify_or_delete == DELETE_INST) { instr = 0; goto writeback; } /* going to modify the inst if possible */ op = MAJOR_OP(instr); if (op == spec_op) { uint specialFunc = FUNC(instr); switch(specialFunc) { case add_op: case addu_op: case and_op: case nor_op: case or_op: case sll_op: case sllv_op: case slt_op: case sltu_op: case sra_op: case srav_op: case srl_op: case srlv_op: case sub_op: case subu_op: case xor_op: if (smashtype->source_or_dest == MODIFY_DEST) ct = change_rd; else ct = (smashtype->rs_or_rt) ? change_rs : change_rt; break; case div_op: case divu_op: case mult_op: case multu_op: ct = (smashtype->rs_or_rt) ? change_rs : change_rt; break; case mfhi_op: case mflo_op: ct = change_rd; break; case mthi_op: case mtlo_op: ct = change_rs; break; case break_op: case sync_op: case jr_op: case jalr_op: case syscall_op: goto retry; default: CPUWarning("Illegal inst at %#x on CPU %d\n", addr, cpunum); ASSERT(0); break; } } else { /* Not SPECIAL */ if (op == bcond_op) { if (smashtype->source_or_dest == MODIFY_SOURCE) { ct = change_rs; } else { uint bcondFunc = RT(instr); int newop = -1; switch(bcondFunc) { case bgez_op: newop = bgtz_op; break; case bgezl_op: newop = bgtzl_op; break; case bltz_op: newop = blez_op; break; case bltzl_op: newop = blezl_op; break; /* there are no off-by-one branch-and-link. Luckily * the kernel doesn't use these ops much */ case bgezal_op: bcondFunc = bltzal_op; break; case bgezall_op: bcondFunc = bltzall_op; break; case bltzal_op: bcondFunc = bgezal_op; break; case bltzall_op: bcondFunc = bgezall_op; break; default: CPUWarning("Illegal inst at %#x on CPU %d\n", addr, cpunum); ASSERT(0); break; } if (newop != -1) { instr = (newop << 26) | RS(instr) | IMMED(instr); } else { instr = (bcond_op << 26) | (RS(instr) << 21) | (bcondFunc << 16) | IMMED(instr); } } } else { /* Not a SPECIAL or REGIMM instruction */ switch(op) { case addi_op: case addiu_op: case andi_op: case slti_op: case sltiu_op: case xori_op: ct = (smashtype->source_or_dest == MODIFY_DEST) ? change_rt : change_rs; break; case beq_op: if ((RS(instr) == 0) && (RT(instr) == 0)) { /* this is a b in disguise */ goto retry; } /* FALL THROUGH */ case beql_op: case bne_op: case bnel_op: if (smashtype->source_or_dest == MODIFY_SOURCE) { ct = (smashtype->rs_or_rt) ? change_rs : change_rt; } else { uint newop = 0; switch (op) { case beq_op: newop = bne_op; break; case beql_op: newop = bnel_op; break; case bne_op: newop = beq_op; break; case bnel_op: newop = beql_op; break; } instr = (newop << 26) | TARGET(instr); } break; case bgtz_op: case bgtzl_op: case blez_op: case blezl_op: if (smashtype->source_or_dest == MODIFY_SOURCE) { ct = change_rs; } else { uint bcondFunc = 0; switch (op) { case bgtz_op: bcondFunc = bgez_op; break; case bgtzl_op: bcondFunc = bgezl_op; break; case blez_op: bcondFunc = bltz_op; break; case blezl_op: bcondFunc = bltzl_op; break; } instr = (bcond_op << 26) | (RS(instr) << 21) | (bcondFunc << 16) | IMMED(instr); } break; case cache_op: case j_op: case jal_op: case pref_op: case lui_op: case ori_op: goto retry; /* pointer base register in rs, dest is rt */ case lb_op: case lbu_op: case lh_op: case lhu_op: case ll_op: case lw_op: case ld_op: case ldc2_op: case lwl_op: case lwr_op: goto retry; /* don't handle loads/stores yet */ /* rs is base, rt is dest in coprocessor 1 */ case lwc1_op: case ldc1_op: goto retry; /* rs is base, rt is source of data to store */ case sb_op: case sh_op: case sc_op: case sw_op: case sd_op: case sdc2_op: case swc2_op: case swl_op: case swr_op: goto retry; /* rs is base, rt is source in coproc 1 */ case sdc1_op: case swc1_op: goto retry; case cop0_op: case cop1_op: goto retry; } } } nreg = smashtype->regnum; switch (ct) { case change_none: break; case change_rs: if (nreg == RS(instr)) { nreg = (nreg + 1) % 32; } instr = (MAJOR_OP(instr) << 26) | (nreg << 21) | (RT(instr) << 16) | IMMED(instr); break; case change_rt: if (nreg == RT(instr)) { nreg = (nreg + 1) % 32; } instr = (MAJOR_OP(instr) << 26) | (RS(instr) << 21) | (nreg << 16) | IMMED(instr); break; case change_rd: if (nreg == RD(instr)) { nreg = (nreg + 1) % 32; } instr = (MAJOR_OP(instr) << 26) | (RS(instr) << 21) | (RT(instr) << 16) | (nreg << 11) | (instr & 0x7ff); break; }writeback: if (dosmash) { r = CPUVec.PutMemory(cpunum, addr, INST_SIZE, (char*) &instr); if (r != SUCCESS) { sprintf(errbuf, "Can't write instruction at address 0x%llx", (Reg64)addr); return FAILURE; } field0 = CPUVec.CycleCount(cpunum); } else { field0 = random(); }#ifdef PRINT_INSTRUCTIONS { extern void SprintInstruction(Inst inst, char* buf); sprintf(errbuf, "0x%x 0x%x %s (", addr, rnd, fnamebuf); SprintInstruction(orig_instr, errbuf+strlen(errbuf)); sprintf(errbuf+strlen(errbuf), ") -> ("); SprintInstruction(instr, errbuf+strlen(errbuf)); CPUPrint("%lld %s %s)\n", field0, dosmash ? "SMASH" : "testSMASH", errbuf); }#else CPUPrint("%lld %s 0x%x 0x%x %s\n", field0, dosmash ? "SMASH" : "testSMASH", addr, rnd, fnamebuf);#endif sprintf(errbuf, "OK"); return SUCCESS;retry: /* no modification possible on this instr. tell TCL no go. */ sprintf(errbuf, "RETRY"); return FAILURE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -