xref: /minix3/minix/commands/swifi/db_sym.c (revision 875abb872412bde4d3ba5da66423f55431e19dcf)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * Mach Operating System
3433d6423SLionel Sambuc  * Copyright (c) 1991,1990 Carnegie Mellon University
4433d6423SLionel Sambuc  * All Rights Reserved.
5433d6423SLionel Sambuc  *
6433d6423SLionel Sambuc  * Permission to use, copy, modify and distribute this software and its
7433d6423SLionel Sambuc  * documentation is hereby granted, provided that both the copyright
8433d6423SLionel Sambuc  * notice and this permission notice appear in all copies of the
9433d6423SLionel Sambuc  * software, derivative works or modified versions, and any portions
10433d6423SLionel Sambuc  * thereof, and that both notices appear in supporting documentation.
11433d6423SLionel Sambuc  *
12433d6423SLionel Sambuc  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13433d6423SLionel Sambuc  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14433d6423SLionel Sambuc  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15433d6423SLionel Sambuc  *
16433d6423SLionel Sambuc  * Carnegie Mellon requests users of this software to return to
17433d6423SLionel Sambuc  *
18433d6423SLionel Sambuc  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19433d6423SLionel Sambuc  *  School of Computer Science
20433d6423SLionel Sambuc  *  Carnegie Mellon University
21433d6423SLionel Sambuc  *  Pittsburgh PA 15213-3890
22433d6423SLionel Sambuc  *
23433d6423SLionel Sambuc  * any improvements or extensions that they make and grant Carnegie the
24433d6423SLionel Sambuc  * rights to redistribute these changes.
25433d6423SLionel Sambuc  */
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc /*
28433d6423SLionel Sambuc  * 	Author: David B. Golub, Carnegie Mellon University
29433d6423SLionel Sambuc  *	Date:	7/90
30433d6423SLionel Sambuc  */
31433d6423SLionel Sambuc #include "ddb.h"
32433d6423SLionel Sambuc #include "db_sym.h"
33433d6423SLionel Sambuc #include "swifi.h"
34433d6423SLionel Sambuc 
35433d6423SLionel Sambuc #include "extra.h"
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc /*
38433d6423SLionel Sambuc  * Multiple symbol tables
39433d6423SLionel Sambuc  */
40433d6423SLionel Sambuc #ifndef MAXNOSYMTABS
41433d6423SLionel Sambuc #define	MAXNOSYMTABS	3	/* mach, ux, emulator */
42433d6423SLionel Sambuc #endif
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc unsigned int	db_maxoff = 0x10000;
45433d6423SLionel Sambuc unsigned long modAddr = 0;
46433d6423SLionel Sambuc 
47433d6423SLionel Sambuc /* NWT: fault injection routine only.
48433d6423SLionel Sambuc  * figure out start of function address given an address (off) in kernel text.
49433d6423SLionel Sambuc  * 	name = function name
50433d6423SLionel Sambuc  *	value = function address
51433d6423SLionel Sambuc  *  d = difference between off and function address
52433d6423SLionel Sambuc  * input is the desired address off and fault type
53433d6423SLionel Sambuc  * returns closest instruction address (if found), NULL otherwise
54433d6423SLionel Sambuc  */
55433d6423SLionel Sambuc unsigned long
find_faulty_instr(db_expr_t off,int type,int * instr_len)56433d6423SLionel Sambuc find_faulty_instr(db_expr_t off, int type, int *instr_len)
57433d6423SLionel Sambuc {
58433d6423SLionel Sambuc   db_expr_t       d;
59433d6423SLionel Sambuc   char            *name;
60433d6423SLionel Sambuc   db_expr_t       value, cur_value, prev_value = 0;
61433d6423SLionel Sambuc   int		verbose=0, found=0;
62433d6423SLionel Sambuc   const char * mod_name = NULL;
63433d6423SLionel Sambuc   unsigned long mod_start;
64433d6423SLionel Sambuc   unsigned long mod_end;
65433d6423SLionel Sambuc   const char * sec_name = NULL;
66433d6423SLionel Sambuc   unsigned long sec_start;
67433d6423SLionel Sambuc   unsigned long sec_end;
68433d6423SLionel Sambuc   const char * sym_name = NULL;
69433d6423SLionel Sambuc   unsigned long sym_start;
70433d6423SLionel Sambuc   unsigned long sym_end;
71433d6423SLionel Sambuc 
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc   *instr_len = 0;
74433d6423SLionel Sambuc   if (kallsyms_address_to_symbol(off,
75433d6423SLionel Sambuc 				 &mod_name, &mod_start, &mod_end,
76433d6423SLionel Sambuc 				 &sec_name, &sec_start, &sec_end,
77433d6423SLionel Sambuc 				 &sym_name, &sym_start, &sym_end) == 0) {
78433d6423SLionel Sambuc     return(0);
79433d6423SLionel Sambuc   }
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc   value = (db_expr_t) sym_start;
82433d6423SLionel Sambuc   d = off - sym_start;
83433d6423SLionel Sambuc   name = (char *) sym_name;
84433d6423SLionel Sambuc 
85433d6423SLionel Sambuc   if (name == 0) {
86433d6423SLionel Sambuc     value = off;
87433d6423SLionel Sambuc   }
88433d6423SLionel Sambuc 
89433d6423SLionel Sambuc   if (value >= DB_SMALL_VALUE_MIN && value <= DB_SMALL_VALUE_MAX) {
90433d6423SLionel Sambuc     printk("0x%x", off);
91433d6423SLionel Sambuc     return 0;
92433d6423SLionel Sambuc   }
93433d6423SLionel Sambuc 
94433d6423SLionel Sambuc   if (name == 0 || d >= db_maxoff) {
95433d6423SLionel Sambuc     printk("0x%x", off);
96433d6423SLionel Sambuc     return 0 ;
97433d6423SLionel Sambuc   }
98433d6423SLionel Sambuc   /* 2) backup to start of function (SOF)
99433d6423SLionel Sambuc    * 3) delineate instruction boundaries, find instruction length too.
100433d6423SLionel Sambuc    */
101433d6423SLionel Sambuc 
102433d6423SLionel Sambuc   if(verbose) {
103433d6423SLionel Sambuc     printk("function %s", sym_name);
104433d6423SLionel Sambuc   }
105433d6423SLionel Sambuc 
106433d6423SLionel Sambuc   /* 4)  skip instructions until we get to our faulty address */
107433d6423SLionel Sambuc   cur_value = value;
108433d6423SLionel Sambuc   while(cur_value < sec_end) {
109433d6423SLionel Sambuc     if(verbose) {
110433d6423SLionel Sambuc #if 0
111433d6423SLionel Sambuc       //	db_printsym(cur_value, DB_STGY_PROC);
112433d6423SLionel Sambuc       //	printk(":\t");
113433d6423SLionel Sambuc #endif
114433d6423SLionel Sambuc     }
115433d6423SLionel Sambuc     prev_value=cur_value;
116433d6423SLionel Sambuc     modAddr=0;
117433d6423SLionel Sambuc     if(verbose) {
118433d6423SLionel Sambuc #if 0
119433d6423SLionel Sambuc       //cur_value=db_disasm(prev_value, FALSE);
120433d6423SLionel Sambuc #endif
121433d6423SLionel Sambuc     } else {
122433d6423SLionel Sambuc       cur_value=my_disasm(prev_value, FALSE);
123433d6423SLionel Sambuc     }
124433d6423SLionel Sambuc 
125433d6423SLionel Sambuc     /* 4a) bail out if instruction is leave (0xc9) */
126433d6423SLionel Sambuc     if(cur_value-prev_value == 1) {
127433d6423SLionel Sambuc       unsigned char *c;
128433d6423SLionel Sambuc       c=(unsigned char *) prev_value;
129433d6423SLionel Sambuc       if(text_read_ub(c)==0xc9)	{
130433d6423SLionel Sambuc 	if(verbose) printk("bailing out as we hit a leave\n");
131433d6423SLionel Sambuc 	found=0;
132433d6423SLionel Sambuc 	break;
133433d6423SLionel Sambuc       }
134433d6423SLionel Sambuc     }
135433d6423SLionel Sambuc     /* 5a) init fault: from SOF, look for movl $X, -Y(%ebp),
136433d6423SLionel Sambuc      *     (C645Fxxx or C745Fxxx) and replace with nop.
137433d6423SLionel Sambuc      */
138433d6423SLionel Sambuc     if(type==INIT_FAULT) {
139433d6423SLionel Sambuc       unsigned char *c;
140433d6423SLionel Sambuc       c=(unsigned char *) prev_value;
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc       if(*c==0x66 || *c==0x67)
143433d6423SLionel Sambuc 	c++;	/* override prefix */
144433d6423SLionel Sambuc 
145433d6423SLionel Sambuc       if(*c==0xC6 || *c==0xC7)
146433d6423SLionel Sambuc 	c++;	/* movb or movl imm */
147433d6423SLionel Sambuc       else
148433d6423SLionel Sambuc 	continue;
149433d6423SLionel Sambuc 
150433d6423SLionel Sambuc       if(*c==0x45)
151433d6423SLionel Sambuc 	c++;				/* [ebp]	*/
152433d6423SLionel Sambuc       else
153433d6423SLionel Sambuc 	continue;
154433d6423SLionel Sambuc 
155433d6423SLionel Sambuc       if(*c & 0x80)
156433d6423SLionel Sambuc 	found=1;			/* negative displacement */
157433d6423SLionel Sambuc       else
158433d6423SLionel Sambuc 	continue;
159433d6423SLionel Sambuc 
160433d6423SLionel Sambuc       found=1;
161433d6423SLionel Sambuc       break;
162*875abb87SDavid van Moolenbroek     } else if(type==NOP_FAULT || type==STOP_FAULT) {
163433d6423SLionel Sambuc       /* 5b) nop*: replace instruction with nop */
164433d6423SLionel Sambuc       if(cur_value> off) {
165433d6423SLionel Sambuc 	found=1;
166433d6423SLionel Sambuc 	break;
167433d6423SLionel Sambuc       }
168433d6423SLionel Sambuc     } else if(type==DST_FAULT || type==SRC_FAULT) {
169433d6423SLionel Sambuc       /* 5c) dst/src: flip bits in mod/rm, sib, disp or imm fields */
170433d6423SLionel Sambuc       if(cur_value>off && (cur_value-prev_value) > 1) {
171433d6423SLionel Sambuc 	found=1;
172433d6423SLionel Sambuc 	break;
173433d6423SLionel Sambuc       }
174433d6423SLionel Sambuc     } else if(type==BRANCH_FAULT || type==LOOP_FAULT) {
175433d6423SLionel Sambuc       /* 5e) brc*: search forward utnil we hit a Jxx or rep (F3 or F2).
176433d6423SLionel Sambuc        *     replace instr with nop.
177433d6423SLionel Sambuc        */
178433d6423SLionel Sambuc       unsigned char *c;
179433d6423SLionel Sambuc 
180433d6423SLionel Sambuc       c=(unsigned char *) prev_value;
181433d6423SLionel Sambuc 
182433d6423SLionel Sambuc       /* look for repX prefix */
183433d6423SLionel Sambuc 
184433d6423SLionel Sambuc       if(text_read_ub(c)==0xf3 || text_read_ub(c)==0xf2) {
185433d6423SLionel Sambuc 	if(verbose)
186433d6423SLionel Sambuc 	  printk("found repX prefix\n");
187433d6423SLionel Sambuc 	/* take out repX prefix only */
188433d6423SLionel Sambuc 	found=1;
189433d6423SLionel Sambuc 	cur_value=prev_value+1;
190433d6423SLionel Sambuc 	break;
191433d6423SLionel Sambuc       } else if( (text_read_ub(c)&0xf0)==0x70 ||
192433d6423SLionel Sambuc 		(text_read_ub(c)>=0xe0 && text_read_ub(c)<=0xe2) ) {
193433d6423SLionel Sambuc 	/* look for jXX 8 (7X), loop,jcx (e0-3), jXX 16/32 (0f 8X) */
194433d6423SLionel Sambuc 	found=1;
195433d6423SLionel Sambuc 	if(verbose)
196433d6423SLionel Sambuc 	  printk("found jXX rel8, loop or jcx\n");
197433d6423SLionel Sambuc 	break;
198433d6423SLionel Sambuc       } else if(text_read_ub(c)==0x66 ||
199433d6423SLionel Sambuc 		text_read_ub(c)==0x67)	{ 	/* override prefix */
200433d6423SLionel Sambuc 	c++;
201433d6423SLionel Sambuc       } else if(text_read_ub(c++)==0xf && (text_read_ub(c)&0xf0)==0x80 ) {
202433d6423SLionel Sambuc 	found=1;	/* 0x0f 0x8X */
203433d6423SLionel Sambuc 	if(verbose) printk("found branch!\n");
204433d6423SLionel Sambuc 	break;
205433d6423SLionel Sambuc       }
206433d6423SLionel Sambuc     } else if(type==PTR_FAULT) {
207433d6423SLionel Sambuc       /* 5f) ptr: if instruction has regmodrm byte (i_has_modrm),
208433d6423SLionel Sambuc        *     and mod field has address ([eyy]dispxx), eyy!=ebp
209433d6423SLionel Sambuc        *     flip 1 bit in lower byte (0x0f) or any bit in following
210433d6423SLionel Sambuc        *     bytes (sib, imm or disp).
211433d6423SLionel Sambuc        */
212433d6423SLionel Sambuc       if(cur_value>off && modAddr) {
213433d6423SLionel Sambuc 	unsigned char *c;
214433d6423SLionel Sambuc 	c=(unsigned char *) modAddr;
215433d6423SLionel Sambuc 	if( text_read_ub(c)>0x3f && text_read_ub(c)<0xc0 &&
216433d6423SLionel Sambuc 		(text_read_ub(c)&7)!=5 ) {
217433d6423SLionel Sambuc 	  found=1;
218433d6423SLionel Sambuc 	  break;
219433d6423SLionel Sambuc 	}
220433d6423SLionel Sambuc       }
221433d6423SLionel Sambuc     } else if(type==INTERFACE_FAULT) {
222433d6423SLionel Sambuc       /* 5f) i/f: look for movl XX(ebp), reg or movb XX(ebp), reg,
223433d6423SLionel Sambuc        *     where XX is positive. replace instr with nop.
224433d6423SLionel Sambuc        *     movl=0x8a, movb=0x8b, mod=01XXX101 (disp8[ebp]), disp>0
225433d6423SLionel Sambuc        */
226433d6423SLionel Sambuc       unsigned char *c;
227433d6423SLionel Sambuc       c=(unsigned char *) prev_value;
228433d6423SLionel Sambuc       if( text_read_ub(c)==0x8a || text_read_ub(c)==0x8b) {
229433d6423SLionel Sambuc 	c++;
230433d6423SLionel Sambuc 	if( ((text_read_ub(c++))&0xc7)==0x45 && (text_read_ub(c)&0x80)==0 ) {
231433d6423SLionel Sambuc 	  /* 75% chance that we'll choose the next arg */
232433d6423SLionel Sambuc 	  if(random()&0x3) {
233433d6423SLionel Sambuc 	    found=1;
234433d6423SLionel Sambuc 	    break;
235433d6423SLionel Sambuc 	  } else {
236433d6423SLionel Sambuc 	    if(verbose) printk("skipped...\n");
237433d6423SLionel Sambuc 	  }
238433d6423SLionel Sambuc 	}
239433d6423SLionel Sambuc       }
240433d6423SLionel Sambuc     }else if(type==IRQ_FAULT) {
241433d6423SLionel Sambuc       /* 5g) i/f: look for push reg or offset(reg) / popf,
242433d6423SLionel Sambuc        *     where XX is positive. replace instr with nop.
243433d6423SLionel Sambuc        *     movl=0x8a, movb=0x8b, mod=01XXX101 (disp8[ebp]), disp>0
244433d6423SLionel Sambuc        */
245433d6423SLionel Sambuc       unsigned char *c;
246433d6423SLionel Sambuc       c=(unsigned char *) prev_value;
247433d6423SLionel Sambuc       if (((text_read_ub(c) & 0xf8) == 0x50) ||
248433d6423SLionel Sambuc 	  (text_read_ub(c) == 0xff)) {
249433d6423SLionel Sambuc 	if (text_read_ub(c) == 0xff) {
250433d6423SLionel Sambuc 	  c++;
251433d6423SLionel Sambuc #if 0
252433d6423SLionel Sambuc 	  //
253433d6423SLionel Sambuc 	  // Look for push x(ebp)
254433d6423SLionel Sambuc #endif
255433d6423SLionel Sambuc 	  if ((text_read_ub(c) & 0x78) != 0x70) {
256433d6423SLionel Sambuc 	    continue;
257433d6423SLionel Sambuc 	  }
258433d6423SLionel Sambuc 	  /*
259433d6423SLionel Sambuc 	  // Skip the offset
260433d6423SLionel Sambuc 	  */
261433d6423SLionel Sambuc 	  c++;
262433d6423SLionel Sambuc 	}
263433d6423SLionel Sambuc 	c++;
264433d6423SLionel Sambuc 	if (text_read_ub(c) == 0x9d) {
265433d6423SLionel Sambuc 	  /*
266433d6423SLionel Sambuc 	  // Increment cur_value to include the
267433d6423SLionel Sambuc 	  // popf instruction
268433d6423SLionel Sambuc 	  */
269433d6423SLionel Sambuc 	  cur_value++;
270433d6423SLionel Sambuc 	  found = 1;
271433d6423SLionel Sambuc 	  break;
272433d6423SLionel Sambuc 	}
273433d6423SLionel Sambuc       }
274433d6423SLionel Sambuc 
275433d6423SLionel Sambuc     }
276433d6423SLionel Sambuc   }
277433d6423SLionel Sambuc   /* if we're doing nop fault, then we're done.
278433d6423SLionel Sambuc    */
279433d6423SLionel Sambuc   if(found) {
280433d6423SLionel Sambuc     *instr_len=cur_value-prev_value;
281433d6423SLionel Sambuc     off=prev_value;
282433d6423SLionel Sambuc     if(verbose) {
283433d6423SLionel Sambuc       printk("%s", name);
284433d6423SLionel Sambuc       if (d) printk("+0x%x", d);
285433d6423SLionel Sambuc       printk(" @ %x, ", value);
286433d6423SLionel Sambuc       printk("instr @ %x, len=%d, ", off, *instr_len);
287433d6423SLionel Sambuc     }
288433d6423SLionel Sambuc     return off;
289433d6423SLionel Sambuc   } else {
290433d6423SLionel Sambuc     if(verbose) printk("cannot locate instruction in function\n");
291433d6423SLionel Sambuc     *instr_len=0;
292433d6423SLionel Sambuc     return 0;
293433d6423SLionel Sambuc   }
294433d6423SLionel Sambuc }
295