Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / commands / swifi / fault_model.c
blob09c9864ee7c62e85a89fb995b681ab9f70563713
1 /*
2 * fault-model.c -- fault injection code for drivers
4 * Copyright (C) 2003 Mike Swift
5 * Copyright (c) 1999 Wee Teck Ng
7 * The source code in this file can be freely used, adapted,
8 * and redistributed in source or binary form, so long as an
9 * acknowledgment appears in derived source files. No warranty
10 * is attached; we cannot take responsibility for errors or
11 * fitness for use.
17 * Fault injector for testing the usefulness of NOOKS
19 * Adapted from the SWIFI tools used by Wee Teck Ng to evaluate the RIO
20 * file cache at the University of Michigan
25 * This tool can inject faults into modules, whether they are loaded into a
26 * nook or loaded into the kernel (for comparison testing).
28 * There are several classes of faults emulated:
29 * - Corruption of text
30 * - corruption
31 * - simulated programming faults
32 * - skip initialization (immediate write to EBP-x)
33 * - remove instruction (replace with NOP)
34 * - incorrect source/destination (corrupted)
35 * - remove jmp or rep instruction
36 * - change address computation for memory access (not stack)
37 * - change termination condition for loop (change repeat to repeat
38 * while equal, change condition to !condition)
39 * - remove instructions loading registers from arguments (ebp+x)
42 #include <stdio.h>
43 #include <assert.h>
45 #include "ddb.h"
46 #include "db_sym.h"
47 #include "swifi.h"
49 #include "extra.h"
51 #define PDEBUG(args) /* (printf args) */
53 #define NOP 0x90
55 static int text_fault(int type, unsigned long btext, unsigned long text_size);
57 static int randomFaults[] = {
58 TEXT_FAULT,
59 NOP_FAULT,
60 SRC_FAULT,
61 DST_FAULT,
62 PTR_FAULT,
63 LOOP_FAULT,
64 INTERFACE_FAULT
67 void
68 swifi_inject_fault(char * module_name,
69 unsigned long faultType,
70 unsigned long randomSeed,
71 unsigned long numFaults)
73 unsigned long btext, etext, text_size;
74 int type;
76 /* default number of faults is 5 */
77 if (numFaults == 0) numFaults = 5;
79 srandom(randomSeed);
81 load_nlist(module_name, &btext, &etext);
83 text_size = etext - btext;
85 PDEBUG(("text=%lx-%lx, size=%lx\n", btext, etext, text_size));
87 while (numFaults) {
88 if ((type = faultType) == RANDOM_FAULT)
89 type = randomFaults[random() %
90 (sizeof(randomFaults) / sizeof(randomFaults[0]))];
92 if (text_fault(type, btext, text_size))
93 numFaults--;
97 static int text_fault(int type, unsigned long btext, unsigned long text_size)
99 unsigned long *addr, taddr;
100 int j, flip_bit, len, prefix;
101 unsigned char *c;
103 /* inject faults into text space */
105 addr = (unsigned long *)
106 (btext + ((unsigned long) (random()&~0xf) % text_size));
108 /* now the tricky part */
110 taddr=(unsigned long) addr;
111 if (type != TEXT_FAULT) {
112 addr = (unsigned long *) find_faulty_instr(taddr, type, &len);
113 /* do it over again if we can't find the right instruction */
114 if (!addr || !len)
115 return FALSE;
118 PDEBUG(("target addr=%lx, instr addr=%p, %lx=>", taddr, addr,
119 text_read_ul(addr)));
121 switch (type) {
122 case TEXT_FAULT:
123 flip_bit = random() & 0x1f;
124 PDEBUG(("flip bit %d => ", flip_bit));
125 flip_bit = 1 << flip_bit;
127 text_write_ul(addr, text_read_ul(addr)^flip_bit);
129 break;
131 case NOP_FAULT:
132 case INIT_FAULT:
133 case BRANCH_FAULT:
134 case INTERFACE_FAULT:
135 case IRQ_FAULT:
136 c = (unsigned char *) addr;
138 for (j = 0; j < len; j++) {
139 /* replace these bytes with NOP (*c=NOP) */
140 text_write_ub(c, NOP);
142 c++;
145 break;
147 case DST_FAULT:
148 case SRC_FAULT:
149 /* skip thru the prefix and opcode, and flip bits in following bytes */
150 c=(unsigned char *) addr;
151 do {
152 switch (text_read_ub(c)) {
153 case 0x66: case 0x67: case 0x26: case 0x36:
154 case 0x2e: case 0x3e: case 0x64: case 0x65:
155 case 0xf0: case 0xf2: case 0xf3:
156 prefix = 1;
157 break;
158 default:
159 prefix = 0;
160 break;
162 if (prefix) {
163 c++;
165 } while (prefix);
166 if(text_read_ub(c)>=0xd8 && text_read_ub(c)<=0xdf) {
167 /* don't mess with fp instruction, yet */
168 PDEBUG(("floating point instruction, bailing out\n"));
169 return FALSE;
171 if(text_read_ub(c)==0x0f) {
172 c++;
174 if(text_read_ub(c)==0x0f) {
175 c++;
177 c++;
178 len = len-((long) c - (long) addr);
179 if (len == 0)
181 PDEBUG(("text_fault: len = %d\n", len));
182 return FALSE;
184 flip_bit = random() % (len*8);
185 PDEBUG(("flip bit %d (len=%d) => ", flip_bit, len));
186 for(j=0; j<len; j++) {
187 /* go to the right byte */
188 if(flip_bit<8) {
189 flip_bit = 1 << flip_bit;
191 text_write_ub(c, (text_read_ub(c)^flip_bit));
193 j=len;
195 c++;
196 flip_bit = flip_bit-8;
199 break;
201 case PTR_FAULT:
202 /* 5f) ptr: if instruction has regmodrm byte (i_has_modrm),
203 * flip 1 bit in lower byte (0x0f) or any bit in following
204 * bytes (sib, imm or disp).
206 c=(unsigned char *) addr;
207 do {
208 switch (text_read_ub(c)) {
209 case 0x66: case 0x67: case 0x26: case 0x36:
210 case 0x2e: case 0x3e: case 0x64: case 0x65:
211 case 0xf0: case 0xf2: case 0xf3:
212 prefix = 1;
213 break;
214 default:
215 prefix = 0;
216 break;
218 if (prefix) {
219 c++;
221 } while (prefix);
222 if(text_read_ub(c)>=0xd8 && text_read_ub(c)<=0xdf) {
223 /* don't mess with fp instruction, yet */
224 PDEBUG(("floating point instruction, bailing out\n"));
225 return FALSE;
227 if(text_read_ub(c)==0x0f) {
228 c++;
230 if(text_read_ub(c)==0x0f) {
231 c++;
233 c++;
234 len = len-((long) c - (long) addr);
235 flip_bit = random() % (len*8-4);
236 PDEBUG(("flip bit %d (len=%d) => ", flip_bit, len));
238 /* mod/rm byte is special */
240 if (flip_bit < 4) {
241 flip_bit = 1 << flip_bit;
243 text_write_ub(c, text_read_ub(c)^flip_bit);
245 c++;
246 flip_bit=flip_bit-4;
248 for(j=1; j<len; j++) {
249 /* go to the right byte */
250 if (flip_bit<8) {
251 flip_bit = 1 << flip_bit;
253 text_write_ub(c, text_read_ub(c)^flip_bit);
255 j=len;
257 c++;
258 flip_bit = flip_bit-8;
261 break;
263 case LOOP_FAULT:
264 c=(unsigned char *) addr;
265 /* replace rep with repe, and vice versa */
266 if(text_read_ub(c)==0xf3) {
267 text_write_ub(c, 0xf2);
268 } else if(text_read_ub(c)==0xf2) {
269 text_write_ub(c, 0xf3);
270 } else if( (text_read_ub(c)&0xf0)==0x70 ) {
271 /* if we've jxx imm8 instruction,
272 * incl even byte instruction, eg jo (70) to jno (71)
273 * decl odd byte instruction, eg jnle (7f) to jle (7e)
275 if(text_read_ub(c)%2 == 0) {
276 text_write_ub(c, text_read_ub(c)+1);
277 } else {
278 text_write_ub(c, text_read_ub(c)-1);
280 } else if(text_read_ub(c)==0x66 || text_read_ub(c)==0x67) {
281 /* override prefix */
282 c++;
283 } else if(text_read_ub(c++)==0xf && (text_read_ub(c)&0xf0)==0x80 ) {
284 /* if we've jxx imm16/32 instruction,
285 * incl even byte instruction, eg jo (80) to jno (81)
286 * decl odd byte instruction, eg jnle (8f) to jle (8e)
288 if(text_read_ub(c)%2 == 0) {
289 text_write_ub(c, text_read_ub(c)+1);
290 } else {
291 text_write_ub(c, text_read_ub(c)-1);
295 break;
297 case STOP_FAULT:
298 text_write_ub(addr, BKPT_INST);
300 break;
302 default:
303 assert(0);
306 return TRUE;