1 /* 2 * Mach Operating System 3 * Copyright (c) 1991,1990 Carnegie Mellon University 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify and distribute this software and its 7 * documentation is hereby granted, provided that both the copyright 8 * notice and this permission notice appear in all copies of the 9 * software, derivative works or modified versions, and any portions 10 * thereof, and that both notices appear in supporting documentation. 11 * 12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15 * 16 * Carnegie Mellon requests users of this software to return to 17 * 18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19 * School of Computer Science 20 * Carnegie Mellon University 21 * Pittsburgh PA 15213-3890 22 * 23 * any improvements or extensions that they make and grant Carnegie the 24 * rights to redistribute these changes. 25 */ 26 27 /* 28 * Author: David B. Golub, Carnegie Mellon University 29 * Date: 7/90 30 */ 31 #include "ddb.h" 32 #include "db_sym.h" 33 #include "swifi.h" 34 35 #include "extra.h" 36 37 /* 38 * Multiple symbol tables 39 */ 40 #ifndef MAXNOSYMTABS 41 #define MAXNOSYMTABS 3 /* mach, ux, emulator */ 42 #endif 43 44 unsigned int db_maxoff = 0x10000; 45 unsigned long modAddr = 0; 46 47 /* NWT: fault injection routine only. 48 * figure out start of function address given an address (off) in kernel text. 49 * name = function name 50 * value = function address 51 * d = difference between off and function address 52 * input is the desired address off and fault type 53 * returns closest instruction address (if found), NULL otherwise 54 */ 55 unsigned long 56 find_faulty_instr(db_expr_t off, int type, int *instr_len) 57 { 58 db_expr_t d; 59 char *name; 60 db_expr_t value, cur_value, prev_value = 0; 61 int verbose=0, found=0; 62 const char * mod_name = NULL; 63 unsigned long mod_start; 64 unsigned long mod_end; 65 const char * sec_name = NULL; 66 unsigned long sec_start; 67 unsigned long sec_end; 68 const char * sym_name = NULL; 69 unsigned long sym_start; 70 unsigned long sym_end; 71 72 73 *instr_len = 0; 74 if (kallsyms_address_to_symbol(off, 75 &mod_name, &mod_start, &mod_end, 76 &sec_name, &sec_start, &sec_end, 77 &sym_name, &sym_start, &sym_end) == 0) { 78 return(0); 79 } 80 81 value = (db_expr_t) sym_start; 82 d = off - sym_start; 83 name = (char *) sym_name; 84 85 if (name == 0) { 86 value = off; 87 } 88 89 if (value >= DB_SMALL_VALUE_MIN && value <= DB_SMALL_VALUE_MAX) { 90 printk("0x%x", off); 91 return 0; 92 } 93 94 if (name == 0 || d >= db_maxoff) { 95 printk("0x%x", off); 96 return 0 ; 97 } 98 /* 2) backup to start of function (SOF) 99 * 3) delineate instruction boundaries, find instruction length too. 100 */ 101 102 if(verbose) { 103 printk("function %s", sym_name); 104 } 105 106 /* 4) skip instructions until we get to our faulty address */ 107 cur_value = value; 108 while(cur_value < sec_end) { 109 if(verbose) { 110 #if 0 111 // db_printsym(cur_value, DB_STGY_PROC); 112 // printk(":\t"); 113 #endif 114 } 115 prev_value=cur_value; 116 modAddr=0; 117 if(verbose) { 118 #if 0 119 //cur_value=db_disasm(prev_value, FALSE); 120 #endif 121 } else { 122 cur_value=my_disasm(prev_value, FALSE); 123 } 124 125 /* 4a) bail out if instruction is leave (0xc9) */ 126 if(cur_value-prev_value == 1) { 127 unsigned char *c; 128 c=(unsigned char *) prev_value; 129 if(text_read_ub(c)==0xc9) { 130 if(verbose) printk("bailing out as we hit a leave\n"); 131 found=0; 132 break; 133 } 134 } 135 /* 5a) init fault: from SOF, look for movl $X, -Y(%ebp), 136 * (C645Fxxx or C745Fxxx) and replace with nop. 137 */ 138 if(type==INIT_FAULT) { 139 unsigned char *c; 140 c=(unsigned char *) prev_value; 141 142 if(*c==0x66 || *c==0x67) 143 c++; /* override prefix */ 144 145 if(*c==0xC6 || *c==0xC7) 146 c++; /* movb or movl imm */ 147 else 148 continue; 149 150 if(*c==0x45) 151 c++; /* [ebp] */ 152 else 153 continue; 154 155 if(*c & 0x80) 156 found=1; /* negative displacement */ 157 else 158 continue; 159 160 found=1; 161 break; 162 } else if(type==NOP_FAULT || type==STOP_FAULT) { 163 /* 5b) nop*: replace instruction with nop */ 164 if(cur_value> off) { 165 found=1; 166 break; 167 } 168 } else if(type==DST_FAULT || type==SRC_FAULT) { 169 /* 5c) dst/src: flip bits in mod/rm, sib, disp or imm fields */ 170 if(cur_value>off && (cur_value-prev_value) > 1) { 171 found=1; 172 break; 173 } 174 } else if(type==BRANCH_FAULT || type==LOOP_FAULT) { 175 /* 5e) brc*: search forward utnil we hit a Jxx or rep (F3 or F2). 176 * replace instr with nop. 177 */ 178 unsigned char *c; 179 180 c=(unsigned char *) prev_value; 181 182 /* look for repX prefix */ 183 184 if(text_read_ub(c)==0xf3 || text_read_ub(c)==0xf2) { 185 if(verbose) 186 printk("found repX prefix\n"); 187 /* take out repX prefix only */ 188 found=1; 189 cur_value=prev_value+1; 190 break; 191 } else if( (text_read_ub(c)&0xf0)==0x70 || 192 (text_read_ub(c)>=0xe0 && text_read_ub(c)<=0xe2) ) { 193 /* look for jXX 8 (7X), loop,jcx (e0-3), jXX 16/32 (0f 8X) */ 194 found=1; 195 if(verbose) 196 printk("found jXX rel8, loop or jcx\n"); 197 break; 198 } else if(text_read_ub(c)==0x66 || 199 text_read_ub(c)==0x67) { /* override prefix */ 200 c++; 201 } else if(text_read_ub(c++)==0xf && (text_read_ub(c)&0xf0)==0x80 ) { 202 found=1; /* 0x0f 0x8X */ 203 if(verbose) printk("found branch!\n"); 204 break; 205 } 206 } else if(type==PTR_FAULT) { 207 /* 5f) ptr: if instruction has regmodrm byte (i_has_modrm), 208 * and mod field has address ([eyy]dispxx), eyy!=ebp 209 * flip 1 bit in lower byte (0x0f) or any bit in following 210 * bytes (sib, imm or disp). 211 */ 212 if(cur_value>off && modAddr) { 213 unsigned char *c; 214 c=(unsigned char *) modAddr; 215 if( text_read_ub(c)>0x3f && text_read_ub(c)<0xc0 && 216 (text_read_ub(c)&7)!=5 ) { 217 found=1; 218 break; 219 } 220 } 221 } else if(type==INTERFACE_FAULT) { 222 /* 5f) i/f: look for movl XX(ebp), reg or movb XX(ebp), reg, 223 * where XX is positive. replace instr with nop. 224 * movl=0x8a, movb=0x8b, mod=01XXX101 (disp8[ebp]), disp>0 225 */ 226 unsigned char *c; 227 c=(unsigned char *) prev_value; 228 if( text_read_ub(c)==0x8a || text_read_ub(c)==0x8b) { 229 c++; 230 if( ((text_read_ub(c++))&0xc7)==0x45 && (text_read_ub(c)&0x80)==0 ) { 231 /* 75% chance that we'll choose the next arg */ 232 if(random()&0x3) { 233 found=1; 234 break; 235 } else { 236 if(verbose) printk("skipped...\n"); 237 } 238 } 239 } 240 }else if(type==IRQ_FAULT) { 241 /* 5g) i/f: look for push reg or offset(reg) / popf, 242 * where XX is positive. replace instr with nop. 243 * movl=0x8a, movb=0x8b, mod=01XXX101 (disp8[ebp]), disp>0 244 */ 245 unsigned char *c; 246 c=(unsigned char *) prev_value; 247 if (((text_read_ub(c) & 0xf8) == 0x50) || 248 (text_read_ub(c) == 0xff)) { 249 if (text_read_ub(c) == 0xff) { 250 c++; 251 #if 0 252 // 253 // Look for push x(ebp) 254 #endif 255 if ((text_read_ub(c) & 0x78) != 0x70) { 256 continue; 257 } 258 /* 259 // Skip the offset 260 */ 261 c++; 262 } 263 c++; 264 if (text_read_ub(c) == 0x9d) { 265 /* 266 // Increment cur_value to include the 267 // popf instruction 268 */ 269 cur_value++; 270 found = 1; 271 break; 272 } 273 } 274 275 } 276 } 277 /* if we're doing nop fault, then we're done. 278 */ 279 if(found) { 280 *instr_len=cur_value-prev_value; 281 off=prev_value; 282 if(verbose) { 283 printk("%s", name); 284 if (d) printk("+0x%x", d); 285 printk(" @ %x, ", value); 286 printk("instr @ %x, len=%d, ", off, *instr_len); 287 } 288 return off; 289 } else { 290 if(verbose) printk("cannot locate instruction in function\n"); 291 *instr_len=0; 292 return 0; 293 } 294 } 295