xref: /minix/minix/commands/swifi/db_sym.c (revision 83ee113e)
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