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