From 659ab96c1fc416a910290212266181774170b847 Mon Sep 17 00:00:00 2001 From: Philip Homburg Date: Thu, 2 Oct 2008 13:43:32 +0000 Subject: [PATCH] Unmodified source of the software fault injection utility --- commands/simple/stat.c | 2 + commands/swifi/Makefile | 25 + commands/swifi/db_access.c | 90 ++ commands/swifi/db_access.h | 43 + commands/swifi/db_disasm.c | 1333 +++++++++++++++++++++++++++ commands/swifi/db_machdep.h | 99 ++ commands/swifi/db_sym.c | 583 ++++++++++++ commands/swifi/db_sym.h | 118 +++ commands/swifi/ddb.h | 161 ++++ commands/swifi/fault_model.c | 1201 ++++++++++++++++++++++++ commands/swifi/random.c | 72 ++ commands/swifi/swifi-2.4.18-a-patch | 980 ++++++++++++++++++++ commands/swifi/swifi-ksyms.c | 32 + commands/swifi/swifi-user.h | 46 + commands/swifi/swifi.h | 61 ++ 15 files changed, 4846 insertions(+) create mode 100644 commands/swifi/Makefile create mode 100644 commands/swifi/db_access.c create mode 100644 commands/swifi/db_access.h create mode 100644 commands/swifi/db_disasm.c create mode 100644 commands/swifi/db_machdep.h create mode 100644 commands/swifi/db_sym.c create mode 100644 commands/swifi/db_sym.h create mode 100644 commands/swifi/ddb.h create mode 100644 commands/swifi/fault_model.c create mode 100644 commands/swifi/random.c create mode 100644 commands/swifi/swifi-2.4.18-a-patch create mode 100644 commands/swifi/swifi-ksyms.c create mode 100644 commands/swifi/swifi-user.h create mode 100644 commands/swifi/swifi.h diff --git a/commands/simple/stat.c b/commands/simple/stat.c index be4d70d72..2a8311504 100755 --- a/commands/simple/stat.c +++ b/commands/simple/stat.c @@ -195,6 +195,7 @@ int main(int ac, char** av) continue; } #endif +fprintf(stderr, "stat: buffer at %p\n", &sbuf); if (!sym) err= stat(av[i], &sbuf); if (sym || (err != 0 && errno == ENOENT)) { err= lstat(av[i], &sbuf); @@ -244,6 +245,7 @@ int main(int ac, char** av) printf("%s: %s\n", av[i], sbuf); continue; } +fprintf(stderr, "stat: buffer at %p\n", &sbuf); if (!sym) err= stat(av[i], &sbuf); if (sym || (err != 0 && errno == ENOENT)) err= lstat(av[i], &sbuf); if (err != -1) { diff --git a/commands/swifi/Makefile b/commands/swifi/Makefile new file mode 100644 index 000000000..def034b7c --- /dev/null +++ b/commands/swifi/Makefile @@ -0,0 +1,25 @@ +# +# Makefile for the nooks. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := swifi.o + +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. + +export-objs = swifi-ksyms.o + +obj-$(CONFIG_SWIFI) += db_sym.o db_disasm.o db_access.o \ + random.o fault_model.o swifi-ksyms.o + +# db_interface.o + +include $(TOPDIR)/Rules.make + +fastdep: + diff --git a/commands/swifi/db_access.c b/commands/swifi/db_access.c new file mode 100644 index 000000000..d6a732a59 --- /dev/null +++ b/commands/swifi/db_access.c @@ -0,0 +1,90 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + * + * $Id: db_access.c,v 1.1 2003/01/15 21:50:58 mikesw Exp $ + */ + +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +#include "ddb.h" +#include "db_access.h" + +/* + * Access unaligned data items on aligned (longword) + * boundaries. + */ + +static unsigned db_extend[] = { /* table for sign-extending */ + 0, + 0xFFFFFF80U, + 0xFFFF8000U, + 0xFF800000U +}; + +void +db_read_bytes(addr, size, data) + vm_offset_t addr; + register int size; + register char *data; +{ + register char *src; + + src = (char *)addr; + while (--size >= 0) + *data++ = *src++; + +} + +db_expr_t +db_get_value(addr, size, is_signed) + db_addr_t addr; + register int size; + boolean_t is_signed; +{ + char data[sizeof(int)]; + register db_expr_t value; + register int i; + + db_read_bytes(addr, size, data); + + value = 0; +#if BYTE_MSF + for (i = 0; i < size; i++) +#else /* BYTE_LSF */ + for (i = size - 1; i >= 0; i--) +#endif + { + value = (value << 8) + (data[i] & 0xFF); + } + + if (size < 4) { + if (is_signed && (value & db_extend[size]) != 0) + value |= db_extend[size]; + } + return (value); +} + diff --git a/commands/swifi/db_access.h b/commands/swifi/db_access.h new file mode 100644 index 000000000..192fb40c2 --- /dev/null +++ b/commands/swifi/db_access.h @@ -0,0 +1,43 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + * + * $Id: db_access.h,v 1.1 2003/01/15 21:51:24 mikesw Exp $ + */ + +#ifndef _DDB_DB_ACCESS_H_ +#define _DDB_DB_ACCESS_H_ + +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +/* + * Data access functions for debugger. + */ +db_expr_t db_get_value __P((db_addr_t addr, int size, + boolean_t is_signed)); +void db_put_value __P((db_addr_t addr, int size, db_expr_t value)); + +#endif /* !_DDB_DB_ACCESS_H_ */ diff --git a/commands/swifi/db_disasm.c b/commands/swifi/db_disasm.c new file mode 100644 index 000000000..295377a02 --- /dev/null +++ b/commands/swifi/db_disasm.c @@ -0,0 +1,1333 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + * + * $Id: db_disasm.c,v 1.1 2003/01/15 21:50:58 mikesw Exp $ + */ + +/* + * Instruction disassembler. + */ + +#include +#include "ddb.h" + +#include "db_access.h" +#include "db_sym.h" + +/* + * Size attributes + */ +#define BYTE 0 +#define WORD 1 +#define LONG 2 +#define QUAD 3 +#define SNGL 4 +#define DBLR 5 +#define EXTR 6 +#define SDEP 7 +#define NONE 8 + +/* + * Addressing modes + */ +#define E 1 /* general effective address */ +#define Eind 2 /* indirect address (jump, call) */ +#define Ew 3 /* address, word size */ +#define Eb 4 /* address, byte size */ +#define R 5 /* register, in 'reg' field */ +#define Rw 6 /* word register, in 'reg' field */ +#define Ri 7 /* register in instruction */ +#define S 8 /* segment reg, in 'reg' field */ +#define Si 9 /* segment reg, in instruction */ +#define A 10 /* accumulator */ +#define BX 11 /* (bx) */ +#define CL 12 /* cl, for shifts */ +#define DX 13 /* dx, for IO */ +#define SI 14 /* si */ +#define DI 15 /* di */ +#define CR 16 /* control register */ +#define DR 17 /* debug register */ +#define TR 18 /* test register */ +#define I 19 /* immediate, unsigned */ +#define Is 20 /* immediate, signed */ +#define Ib 21 /* byte immediate, unsigned */ +#define Ibs 22 /* byte immediate, signed */ +#define Iw 23 /* word immediate, unsigned */ +#define O 25 /* direct address */ +#define Db 26 /* byte displacement from EIP */ +#define Dl 27 /* long displacement from EIP */ +#define o1 28 /* constant 1 */ +#define o3 29 /* constant 3 */ +#define OS 30 /* immediate offset/segment */ +#define ST 31 /* FP stack top */ +#define STI 32 /* FP stack */ +#define X 33 /* extended FP op */ +#define XA 34 /* for 'fstcw %ax' */ +#define El 35 /* address, long size */ +#define Ril 36 /* long register in instruction */ +#define Iba 37 /* byte immediate, don't print if 0xa */ + +struct inst { + const char * i_name; /* name */ + short i_has_modrm; /* has regmodrm byte */ + short i_size; /* operand size */ + int i_mode; /* addressing modes */ + const void * i_extra; /* pointer to extra opcode table */ +}; + +#define op1(x) (x) +#define op2(x,y) ((x)|((y)<<8)) +#define op3(x,y,z) ((x)|((y)<<8)|((z)<<16)) + +struct finst { + const char * f_name; /* name for memory instruction */ + int f_size; /* size for memory instruction */ + int f_rrmode; /* mode for rr instruction */ + const void * f_rrname; /* name for rr instruction + (or pointer to table) */ +}; + +static const char * const db_Grp6[] = { + "sldt", + "str", + "lldt", + "ltr", + "verr", + "verw", + "", + "" +}; + +static const char * const db_Grp7[] = { + "sgdt", + "sidt", + "lgdt", + "lidt", + "smsw", + "", + "lmsw", + "invlpg" +}; + +static const char * const db_Grp8[] = { + "", + "", + "", + "", + "bt", + "bts", + "btr", + "btc" +}; + +static const char * const db_Grp9[] = { + "", + "cmpxchg8b", + "", + "", + "", + "", + "", + "" +}; + +static const struct inst db_inst_0f0x[] = { +/*00*/ { "", TRUE, NONE, op1(Ew), db_Grp6 }, +/*01*/ { "", TRUE, NONE, op1(Ew), db_Grp7 }, +/*02*/ { "lar", TRUE, LONG, op2(E,R), 0 }, +/*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 }, +/*04*/ { "", FALSE, NONE, 0, 0 }, +/*05*/ { "", FALSE, NONE, 0, 0 }, +/*06*/ { "clts", FALSE, NONE, 0, 0 }, +/*07*/ { "", FALSE, NONE, 0, 0 }, + +/*08*/ { "invd", FALSE, NONE, 0, 0 }, +/*09*/ { "wbinvd",FALSE, NONE, 0, 0 }, +/*0a*/ { "", FALSE, NONE, 0, 0 }, +/*0b*/ { "", FALSE, NONE, 0, 0 }, +/*0c*/ { "", FALSE, NONE, 0, 0 }, +/*0d*/ { "", FALSE, NONE, 0, 0 }, +/*0e*/ { "", FALSE, NONE, 0, 0 }, +/*0f*/ { "", FALSE, NONE, 0, 0 }, +}; + +static const struct inst db_inst_0f2x[] = { +/*20*/ { "mov", TRUE, LONG, op2(CR,El), 0 }, +/*21*/ { "mov", TRUE, LONG, op2(DR,El), 0 }, +/*22*/ { "mov", TRUE, LONG, op2(El,CR), 0 }, +/*23*/ { "mov", TRUE, LONG, op2(El,DR), 0 }, +/*24*/ { "mov", TRUE, LONG, op2(TR,El), 0 }, +/*25*/ { "", FALSE, NONE, 0, 0 }, +/*26*/ { "mov", TRUE, LONG, op2(El,TR), 0 }, +/*27*/ { "", FALSE, NONE, 0, 0 }, + +/*28*/ { "", FALSE, NONE, 0, 0 }, +/*29*/ { "", FALSE, NONE, 0, 0 }, +/*2a*/ { "", FALSE, NONE, 0, 0 }, +/*2b*/ { "", FALSE, NONE, 0, 0 }, +/*2c*/ { "", FALSE, NONE, 0, 0 }, +/*2d*/ { "", FALSE, NONE, 0, 0 }, +/*2e*/ { "", FALSE, NONE, 0, 0 }, +/*2f*/ { "", FALSE, NONE, 0, 0 }, +}; + +static const struct inst db_inst_0f3x[] = { +/*30*/ { "wrmsr", FALSE, NONE, 0, 0 }, +/*31*/ { "rdtsc", FALSE, NONE, 0, 0 }, +/*32*/ { "rdmsr", FALSE, NONE, 0, 0 }, +/*33*/ { "rdpmc", FALSE, NONE, 0, 0 }, +/*34*/ { "", FALSE, NONE, 0, 0 }, +/*35*/ { "", FALSE, NONE, 0, 0 }, +/*36*/ { "", FALSE, NONE, 0, 0 }, +/*37*/ { "", FALSE, NONE, 0, 0 }, + +/*38*/ { "", FALSE, NONE, 0, 0 }, +/*39*/ { "", FALSE, NONE, 0, 0 }, +/*3a*/ { "", FALSE, NONE, 0, 0 }, +/*3b*/ { "", FALSE, NONE, 0, 0 }, +/*3c*/ { "", FALSE, NONE, 0, 0 }, +/*3d*/ { "", FALSE, NONE, 0, 0 }, +/*3e*/ { "", FALSE, NONE, 0, 0 }, +/*3f*/ { "", FALSE, NONE, 0, 0 }, +}; + +static const struct inst db_inst_0f8x[] = { +/*80*/ { "jo", FALSE, NONE, op1(Dl), 0 }, +/*81*/ { "jno", FALSE, NONE, op1(Dl), 0 }, +/*82*/ { "jb", FALSE, NONE, op1(Dl), 0 }, +/*83*/ { "jnb", FALSE, NONE, op1(Dl), 0 }, +/*84*/ { "jz", FALSE, NONE, op1(Dl), 0 }, +/*85*/ { "jnz", FALSE, NONE, op1(Dl), 0 }, +/*86*/ { "jbe", FALSE, NONE, op1(Dl), 0 }, +/*87*/ { "jnbe", FALSE, NONE, op1(Dl), 0 }, + +/*88*/ { "js", FALSE, NONE, op1(Dl), 0 }, +/*89*/ { "jns", FALSE, NONE, op1(Dl), 0 }, +/*8a*/ { "jp", FALSE, NONE, op1(Dl), 0 }, +/*8b*/ { "jnp", FALSE, NONE, op1(Dl), 0 }, +/*8c*/ { "jl", FALSE, NONE, op1(Dl), 0 }, +/*8d*/ { "jnl", FALSE, NONE, op1(Dl), 0 }, +/*8e*/ { "jle", FALSE, NONE, op1(Dl), 0 }, +/*8f*/ { "jnle", FALSE, NONE, op1(Dl), 0 }, +}; + +static const struct inst db_inst_0f9x[] = { +/*90*/ { "seto", TRUE, NONE, op1(Eb), 0 }, +/*91*/ { "setno", TRUE, NONE, op1(Eb), 0 }, +/*92*/ { "setb", TRUE, NONE, op1(Eb), 0 }, +/*93*/ { "setnb", TRUE, NONE, op1(Eb), 0 }, +/*94*/ { "setz", TRUE, NONE, op1(Eb), 0 }, +/*95*/ { "setnz", TRUE, NONE, op1(Eb), 0 }, +/*96*/ { "setbe", TRUE, NONE, op1(Eb), 0 }, +/*97*/ { "setnbe",TRUE, NONE, op1(Eb), 0 }, + +/*98*/ { "sets", TRUE, NONE, op1(Eb), 0 }, +/*99*/ { "setns", TRUE, NONE, op1(Eb), 0 }, +/*9a*/ { "setp", TRUE, NONE, op1(Eb), 0 }, +/*9b*/ { "setnp", TRUE, NONE, op1(Eb), 0 }, +/*9c*/ { "setl", TRUE, NONE, op1(Eb), 0 }, +/*9d*/ { "setnl", TRUE, NONE, op1(Eb), 0 }, +/*9e*/ { "setle", TRUE, NONE, op1(Eb), 0 }, +/*9f*/ { "setnle",TRUE, NONE, op1(Eb), 0 }, +}; + +static const struct inst db_inst_0fax[] = { +/*a0*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*a1*/ { "pop", FALSE, NONE, op1(Si), 0 }, +/*a2*/ { "cpuid", FALSE, NONE, 0, 0 }, +/*a3*/ { "bt", TRUE, LONG, op2(R,E), 0 }, +/*a4*/ { "shld", TRUE, LONG, op3(Ib,R,E), 0 }, +/*a5*/ { "shld", TRUE, LONG, op3(CL,R,E), 0 }, +/*a6*/ { "", FALSE, NONE, 0, 0 }, +/*a7*/ { "", FALSE, NONE, 0, 0 }, + +/*a8*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*a9*/ { "pop", FALSE, NONE, op1(Si), 0 }, +/*aa*/ { "rsm", FALSE, NONE, 0, 0 }, +/*ab*/ { "bts", TRUE, LONG, op2(R,E), 0 }, +/*ac*/ { "shrd", TRUE, LONG, op3(Ib,R,E), 0 }, +/*ad*/ { "shrd", TRUE, LONG, op3(CL,R,E), 0 }, +/*a6*/ { "", FALSE, NONE, 0, 0 }, +/*a7*/ { "imul", TRUE, LONG, op2(E,R), 0 }, +}; + +static const struct inst db_inst_0fbx[] = { +/*b0*/ { "cmpxchg",TRUE, BYTE, op2(R, E), 0 }, +/*b0*/ { "cmpxchg",TRUE, LONG, op2(R, E), 0 }, +/*b2*/ { "lss", TRUE, LONG, op2(E, R), 0 }, +/*b3*/ { "btr", TRUE, LONG, op2(R, E), 0 }, +/*b4*/ { "lfs", TRUE, LONG, op2(E, R), 0 }, +/*b5*/ { "lgs", TRUE, LONG, op2(E, R), 0 }, +/*b6*/ { "movzb", TRUE, LONG, op2(Eb, R), 0 }, +/*b7*/ { "movzw", TRUE, LONG, op2(Ew, R), 0 }, + +/*b8*/ { "", FALSE, NONE, 0, 0 }, +/*b9*/ { "", FALSE, NONE, 0, 0 }, +/*ba*/ { "", TRUE, LONG, op2(Ib, E), db_Grp8 }, +/*bb*/ { "btc", TRUE, LONG, op2(R, E), 0 }, +/*bc*/ { "bsf", TRUE, LONG, op2(E, R), 0 }, +/*bd*/ { "bsr", TRUE, LONG, op2(E, R), 0 }, +/*be*/ { "movsb", TRUE, LONG, op2(Eb, R), 0 }, +/*bf*/ { "movsw", TRUE, LONG, op2(Ew, R), 0 }, +}; + +static const struct inst db_inst_0fcx[] = { +/*c0*/ { "xadd", TRUE, BYTE, op2(R, E), 0 }, +/*c1*/ { "xadd", TRUE, LONG, op2(R, E), 0 }, +/*c2*/ { "", FALSE, NONE, 0, 0 }, +/*c3*/ { "", FALSE, NONE, 0, 0 }, +/*c4*/ { "", FALSE, NONE, 0, 0 }, +/*c5*/ { "", FALSE, NONE, 0, 0 }, +/*c6*/ { "", FALSE, NONE, 0, 0 }, +/*c7*/ { "", TRUE, NONE, op1(E), db_Grp9 }, +/*c8*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*c9*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*ca*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*cb*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*cc*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*cd*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*ce*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*cf*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +}; + +static const struct inst * const db_inst_0f[] = { + db_inst_0f0x, + 0, + db_inst_0f2x, + db_inst_0f3x, + 0, + 0, + 0, + 0, + db_inst_0f8x, + db_inst_0f9x, + db_inst_0fax, + db_inst_0fbx, + db_inst_0fcx, + 0, + 0, + 0 +}; + +static const char * const db_Esc92[] = { + "fnop", "", "", "", "", "", "", "" +}; +static const char * const db_Esc94[] = { + "fchs", "fabs", "", "", "ftst", "fxam", "", "" +}; +static const char * const db_Esc95[] = { + "fld1", "fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","" +}; +static const char * const db_Esc96[] = { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp", + "fincstp" +}; +static const char * const db_Esc97[] = { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos" +}; + +static const char * const db_Esca5[] = { + "", "fucompp","", "", "", "", "", "" +}; + +static const char * const db_Escb4[] = { + "fneni","fndisi", "fnclex","fninit","fsetpm", "", "", "" +}; + +static const char * const db_Esce3[] = { + "", "fcompp","", "", "", "", "", "" +}; + +static const char * const db_Escf4[] = { + "fnstsw","", "", "", "", "", "", "" +}; + +static const struct finst db_Esc8[] = { +/*0*/ { "fadd", SNGL, op2(STI,ST), 0 }, +/*1*/ { "fmul", SNGL, op2(STI,ST), 0 }, +/*2*/ { "fcom", SNGL, op2(STI,ST), 0 }, +/*3*/ { "fcomp", SNGL, op2(STI,ST), 0 }, +/*4*/ { "fsub", SNGL, op2(STI,ST), 0 }, +/*5*/ { "fsubr", SNGL, op2(STI,ST), 0 }, +/*6*/ { "fdiv", SNGL, op2(STI,ST), 0 }, +/*7*/ { "fdivr", SNGL, op2(STI,ST), 0 }, +}; + +static const struct finst db_Esc9[] = { +/*0*/ { "fld", SNGL, op1(STI), 0 }, +/*1*/ { "", NONE, op1(STI), "fxch" }, +/*2*/ { "fst", SNGL, op1(X), db_Esc92 }, +/*3*/ { "fstp", SNGL, 0, 0 }, +/*4*/ { "fldenv", NONE, op1(X), db_Esc94 }, +/*5*/ { "fldcw", NONE, op1(X), db_Esc95 }, +/*6*/ { "fnstenv",NONE, op1(X), db_Esc96 }, +/*7*/ { "fnstcw", NONE, op1(X), db_Esc97 }, +}; + +static const struct finst db_Esca[] = { +/*0*/ { "fiadd", LONG, 0, 0 }, +/*1*/ { "fimul", LONG, 0, 0 }, +/*2*/ { "ficom", LONG, 0, 0 }, +/*3*/ { "ficomp", LONG, 0, 0 }, +/*4*/ { "fisub", LONG, 0, 0 }, +/*5*/ { "fisubr", LONG, op1(X), db_Esca5 }, +/*6*/ { "fidiv", LONG, 0, 0 }, +/*7*/ { "fidivr", LONG, 0, 0 } +}; + +static const struct finst db_Escb[] = { +/*0*/ { "fild", LONG, 0, 0 }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fist", LONG, 0, 0 }, +/*3*/ { "fistp", LONG, 0, 0 }, +/*4*/ { "", WORD, op1(X), db_Escb4 }, +/*5*/ { "fld", EXTR, 0, 0 }, +/*6*/ { "", WORD, 0, 0 }, +/*7*/ { "fstp", EXTR, 0, 0 }, +}; + +static const struct finst db_Escc[] = { +/*0*/ { "fadd", DBLR, op2(ST,STI), 0 }, +/*1*/ { "fmul", DBLR, op2(ST,STI), 0 }, +/*2*/ { "fcom", DBLR, 0, 0 }, +/*3*/ { "fcomp", DBLR, 0, 0 }, +/*4*/ { "fsub", DBLR, op2(ST,STI), "fsubr" }, +/*5*/ { "fsubr", DBLR, op2(ST,STI), "fsub" }, +/*6*/ { "fdiv", DBLR, op2(ST,STI), "fdivr" }, +/*7*/ { "fdivr", DBLR, op2(ST,STI), "fdiv" }, +}; + +static const struct finst db_Escd[] = { +/*0*/ { "fld", DBLR, op1(STI), "ffree" }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fst", DBLR, op1(STI), 0 }, +/*3*/ { "fstp", DBLR, op1(STI), 0 }, +/*4*/ { "frstor", NONE, op1(STI), "fucom" }, +/*5*/ { "", NONE, op1(STI), "fucomp" }, +/*6*/ { "fnsave", NONE, 0, 0 }, +/*7*/ { "fnstsw", NONE, 0, 0 }, +}; + +static const struct finst db_Esce[] = { +/*0*/ { "fiadd", WORD, op2(ST,STI), "faddp" }, +/*1*/ { "fimul", WORD, op2(ST,STI), "fmulp" }, +/*2*/ { "ficom", WORD, 0, 0 }, +/*3*/ { "ficomp", WORD, op1(X), db_Esce3 }, +/*4*/ { "fisub", WORD, op2(ST,STI), "fsubrp" }, +/*5*/ { "fisubr", WORD, op2(ST,STI), "fsubp" }, +/*6*/ { "fidiv", WORD, op2(ST,STI), "fdivrp" }, +/*7*/ { "fidivr", WORD, op2(ST,STI), "fdivp" }, +}; + +static const struct finst db_Escf[] = { +/*0*/ { "fild", WORD, 0, 0 }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fist", WORD, 0, 0 }, +/*3*/ { "fistp", WORD, 0, 0 }, +/*4*/ { "fbld", NONE, op1(XA), db_Escf4 }, +/*5*/ { "fild", QUAD, 0, 0 }, +/*6*/ { "fbstp", NONE, 0, 0 }, +/*7*/ { "fistp", QUAD, 0, 0 }, +}; + +static const struct finst * const db_Esc_inst[] = { + db_Esc8, db_Esc9, db_Esca, db_Escb, + db_Escc, db_Escd, db_Esce, db_Escf +}; + +static const char * const db_Grp1[] = { + "add", + "or", + "adc", + "sbb", + "and", + "sub", + "xor", + "cmp" +}; + +static const char * const db_Grp2[] = { + "rol", + "ror", + "rcl", + "rcr", + "shl", + "shr", + "shl", + "sar" +}; + +static const struct inst db_Grp3[] = { + { "test", TRUE, NONE, op2(I,E), 0 }, + { "test", TRUE, NONE, op2(I,E), 0 }, + { "not", TRUE, NONE, op1(E), 0 }, + { "neg", TRUE, NONE, op1(E), 0 }, + { "mul", TRUE, NONE, op2(E,A), 0 }, + { "imul", TRUE, NONE, op2(E,A), 0 }, + { "div", TRUE, NONE, op2(E,A), 0 }, + { "idiv", TRUE, NONE, op2(E,A), 0 }, +}; + +static const struct inst db_Grp4[] = { + { "inc", TRUE, BYTE, op1(E), 0 }, + { "dec", TRUE, BYTE, op1(E), 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 } +}; + +static const struct inst db_Grp5[] = { + { "inc", TRUE, LONG, op1(E), 0 }, + { "dec", TRUE, LONG, op1(E), 0 }, + { "call", TRUE, LONG, op1(Eind),0 }, + { "lcall", TRUE, LONG, op1(Eind),0 }, + { "jmp", TRUE, LONG, op1(Eind),0 }, + { "ljmp", TRUE, LONG, op1(Eind),0 }, + { "push", TRUE, LONG, op1(E), 0 }, + { "", TRUE, NONE, 0, 0 } +}; + +static const struct inst db_inst_table[256] = { +/*00*/ { "add", TRUE, BYTE, op2(R, E), 0 }, +/*01*/ { "add", TRUE, LONG, op2(R, E), 0 }, +/*02*/ { "add", TRUE, BYTE, op2(E, R), 0 }, +/*03*/ { "add", TRUE, LONG, op2(E, R), 0 }, +/*04*/ { "add", FALSE, BYTE, op2(I, A), 0 }, +/*05*/ { "add", FALSE, LONG, op2(Is, A), 0 }, +/*06*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*07*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*08*/ { "or", TRUE, BYTE, op2(R, E), 0 }, +/*09*/ { "or", TRUE, LONG, op2(R, E), 0 }, +/*0a*/ { "or", TRUE, BYTE, op2(E, R), 0 }, +/*0b*/ { "or", TRUE, LONG, op2(E, R), 0 }, +/*0c*/ { "or", FALSE, BYTE, op2(I, A), 0 }, +/*0d*/ { "or", FALSE, LONG, op2(I, A), 0 }, +/*0e*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*0f*/ { "", FALSE, NONE, 0, 0 }, + +/*10*/ { "adc", TRUE, BYTE, op2(R, E), 0 }, +/*11*/ { "adc", TRUE, LONG, op2(R, E), 0 }, +/*12*/ { "adc", TRUE, BYTE, op2(E, R), 0 }, +/*13*/ { "adc", TRUE, LONG, op2(E, R), 0 }, +/*14*/ { "adc", FALSE, BYTE, op2(I, A), 0 }, +/*15*/ { "adc", FALSE, LONG, op2(Is, A), 0 }, +/*16*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*17*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*18*/ { "sbb", TRUE, BYTE, op2(R, E), 0 }, +/*19*/ { "sbb", TRUE, LONG, op2(R, E), 0 }, +/*1a*/ { "sbb", TRUE, BYTE, op2(E, R), 0 }, +/*1b*/ { "sbb", TRUE, LONG, op2(E, R), 0 }, +/*1c*/ { "sbb", FALSE, BYTE, op2(I, A), 0 }, +/*1d*/ { "sbb", FALSE, LONG, op2(Is, A), 0 }, +/*1e*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*1f*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*20*/ { "and", TRUE, BYTE, op2(R, E), 0 }, +/*21*/ { "and", TRUE, LONG, op2(R, E), 0 }, +/*22*/ { "and", TRUE, BYTE, op2(E, R), 0 }, +/*23*/ { "and", TRUE, LONG, op2(E, R), 0 }, +/*24*/ { "and", FALSE, BYTE, op2(I, A), 0 }, +/*25*/ { "and", FALSE, LONG, op2(I, A), 0 }, +/*26*/ { "", FALSE, NONE, 0, 0 }, +/*27*/ { "daa", FALSE, NONE, 0, 0 }, + +/*28*/ { "sub", TRUE, BYTE, op2(R, E), 0 }, +/*29*/ { "sub", TRUE, LONG, op2(R, E), 0 }, +/*2a*/ { "sub", TRUE, BYTE, op2(E, R), 0 }, +/*2b*/ { "sub", TRUE, LONG, op2(E, R), 0 }, +/*2c*/ { "sub", FALSE, BYTE, op2(I, A), 0 }, +/*2d*/ { "sub", FALSE, LONG, op2(Is, A), 0 }, +/*2e*/ { "", FALSE, NONE, 0, 0 }, +/*2f*/ { "das", FALSE, NONE, 0, 0 }, + +/*30*/ { "xor", TRUE, BYTE, op2(R, E), 0 }, +/*31*/ { "xor", TRUE, LONG, op2(R, E), 0 }, +/*32*/ { "xor", TRUE, BYTE, op2(E, R), 0 }, +/*33*/ { "xor", TRUE, LONG, op2(E, R), 0 }, +/*34*/ { "xor", FALSE, BYTE, op2(I, A), 0 }, +/*35*/ { "xor", FALSE, LONG, op2(I, A), 0 }, +/*36*/ { "", FALSE, NONE, 0, 0 }, +/*37*/ { "aaa", FALSE, NONE, 0, 0 }, + +/*38*/ { "cmp", TRUE, BYTE, op2(R, E), 0 }, +/*39*/ { "cmp", TRUE, LONG, op2(R, E), 0 }, +/*3a*/ { "cmp", TRUE, BYTE, op2(E, R), 0 }, +/*3b*/ { "cmp", TRUE, LONG, op2(E, R), 0 }, +/*3c*/ { "cmp", FALSE, BYTE, op2(I, A), 0 }, +/*3d*/ { "cmp", FALSE, LONG, op2(Is, A), 0 }, +/*3e*/ { "", FALSE, NONE, 0, 0 }, +/*3f*/ { "aas", FALSE, NONE, 0, 0 }, + +/*40*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*41*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*42*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*43*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*44*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*45*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*46*/ { "inc", FALSE, LONG, op1(Ri), 0 }, +/*47*/ { "inc", FALSE, LONG, op1(Ri), 0 }, + +/*48*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*49*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4a*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4b*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4c*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4d*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4e*/ { "dec", FALSE, LONG, op1(Ri), 0 }, +/*4f*/ { "dec", FALSE, LONG, op1(Ri), 0 }, + +/*50*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*51*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*52*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*53*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*54*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*55*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*56*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*57*/ { "push", FALSE, LONG, op1(Ri), 0 }, + +/*58*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*59*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5a*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5b*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5c*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5d*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5e*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5f*/ { "pop", FALSE, LONG, op1(Ri), 0 }, + +/*60*/ { "pusha", FALSE, LONG, 0, 0 }, +/*61*/ { "popa", FALSE, LONG, 0, 0 }, +/*62*/ { "bound", TRUE, LONG, op2(E, R), 0 }, +/*63*/ { "arpl", TRUE, NONE, op2(Rw,Ew), 0 }, + +/*64*/ { "", FALSE, NONE, 0, 0 }, +/*65*/ { "", FALSE, NONE, 0, 0 }, +/*66*/ { "", FALSE, NONE, 0, 0 }, +/*67*/ { "", FALSE, NONE, 0, 0 }, + +/*68*/ { "push", FALSE, LONG, op1(I), 0 }, +/*69*/ { "imul", TRUE, LONG, op3(I,E,R), 0 }, +/*6a*/ { "push", FALSE, LONG, op1(Ibs), 0 }, +/*6b*/ { "imul", TRUE, LONG, op3(Ibs,E,R),0 }, +/*6c*/ { "ins", FALSE, BYTE, op2(DX, DI), 0 }, +/*6d*/ { "ins", FALSE, LONG, op2(DX, DI), 0 }, +/*6e*/ { "outs", FALSE, BYTE, op2(SI, DX), 0 }, +/*6f*/ { "outs", FALSE, LONG, op2(SI, DX), 0 }, + +/*70*/ { "jo", FALSE, NONE, op1(Db), 0 }, +/*71*/ { "jno", FALSE, NONE, op1(Db), 0 }, +/*72*/ { "jb", FALSE, NONE, op1(Db), 0 }, +/*73*/ { "jnb", FALSE, NONE, op1(Db), 0 }, +/*74*/ { "jz", FALSE, NONE, op1(Db), 0 }, +/*75*/ { "jnz", FALSE, NONE, op1(Db), 0 }, +/*76*/ { "jbe", FALSE, NONE, op1(Db), 0 }, +/*77*/ { "jnbe", FALSE, NONE, op1(Db), 0 }, + +/*78*/ { "js", FALSE, NONE, op1(Db), 0 }, +/*79*/ { "jns", FALSE, NONE, op1(Db), 0 }, +/*7a*/ { "jp", FALSE, NONE, op1(Db), 0 }, +/*7b*/ { "jnp", FALSE, NONE, op1(Db), 0 }, +/*7c*/ { "jl", FALSE, NONE, op1(Db), 0 }, +/*7d*/ { "jnl", FALSE, NONE, op1(Db), 0 }, +/*7e*/ { "jle", FALSE, NONE, op1(Db), 0 }, +/*7f*/ { "jnle", FALSE, NONE, op1(Db), 0 }, + +/*80*/ { "", TRUE, BYTE, op2(I, E), db_Grp1 }, +/*81*/ { "", TRUE, LONG, op2(I, E), db_Grp1 }, +/*82*/ { "", TRUE, BYTE, op2(I, E), db_Grp1 }, +/*83*/ { "", TRUE, LONG, op2(Ibs,E), db_Grp1 }, +/*84*/ { "test", TRUE, BYTE, op2(R, E), 0 }, +/*85*/ { "test", TRUE, LONG, op2(R, E), 0 }, +/*86*/ { "xchg", TRUE, BYTE, op2(R, E), 0 }, +/*87*/ { "xchg", TRUE, LONG, op2(R, E), 0 }, + +/*88*/ { "mov", TRUE, BYTE, op2(R, E), 0 }, +/*89*/ { "mov", TRUE, LONG, op2(R, E), 0 }, +/*8a*/ { "mov", TRUE, BYTE, op2(E, R), 0 }, +/*8b*/ { "mov", TRUE, LONG, op2(E, R), 0 }, +/*8c*/ { "mov", TRUE, NONE, op2(S, Ew), 0 }, +/*8d*/ { "lea", TRUE, LONG, op2(E, R), 0 }, +/*8e*/ { "mov", TRUE, NONE, op2(Ew, S), 0 }, +/*8f*/ { "pop", TRUE, LONG, op1(E), 0 }, + +/*90*/ { "nop", FALSE, NONE, 0, 0 }, +/*91*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*92*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*93*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*94*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*95*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*96*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*97*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, + +/*98*/ { "cbw", FALSE, SDEP, 0, "cwde" }, /* cbw/cwde */ +/*99*/ { "cwd", FALSE, SDEP, 0, "cdq" }, /* cwd/cdq */ +/*9a*/ { "lcall", FALSE, NONE, op1(OS), 0 }, +/*9b*/ { "wait", FALSE, NONE, 0, 0 }, +/*9c*/ { "pushf", FALSE, LONG, 0, 0 }, +/*9d*/ { "popf", FALSE, LONG, 0, 0 }, +/*9e*/ { "sahf", FALSE, NONE, 0, 0 }, +/*9f*/ { "lahf", FALSE, NONE, 0, 0 }, + +/*a0*/ { "mov", FALSE, BYTE, op2(O, A), 0 }, +/*a1*/ { "mov", FALSE, LONG, op2(O, A), 0 }, +/*a2*/ { "mov", FALSE, BYTE, op2(A, O), 0 }, +/*a3*/ { "mov", FALSE, LONG, op2(A, O), 0 }, +/*a4*/ { "movs", FALSE, BYTE, op2(SI,DI), 0 }, +/*a5*/ { "movs", FALSE, LONG, op2(SI,DI), 0 }, +/*a6*/ { "cmps", FALSE, BYTE, op2(SI,DI), 0 }, +/*a7*/ { "cmps", FALSE, LONG, op2(SI,DI), 0 }, + +/*a8*/ { "test", FALSE, BYTE, op2(I, A), 0 }, +/*a9*/ { "test", FALSE, LONG, op2(I, A), 0 }, +/*aa*/ { "stos", FALSE, BYTE, op1(DI), 0 }, +/*ab*/ { "stos", FALSE, LONG, op1(DI), 0 }, +/*ac*/ { "lods", FALSE, BYTE, op1(SI), 0 }, +/*ad*/ { "lods", FALSE, LONG, op1(SI), 0 }, +/*ae*/ { "scas", FALSE, BYTE, op1(SI), 0 }, +/*af*/ { "scas", FALSE, LONG, op1(SI), 0 }, + +/*b0*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b1*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b2*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b3*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b4*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b5*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b6*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b7*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, + +/*b8*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*b9*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*ba*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bb*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bc*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bd*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*be*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, +/*bf*/ { "mov", FALSE, LONG, op2(I, Ri), 0 }, + +/*c0*/ { "", TRUE, BYTE, op2(Ib, E), db_Grp2 }, +/*c1*/ { "", TRUE, LONG, op2(Ib, E), db_Grp2 }, +/*c2*/ { "ret", FALSE, NONE, op1(Iw), 0 }, +/*c3*/ { "ret", FALSE, NONE, 0, 0 }, +/*c4*/ { "les", TRUE, LONG, op2(E, R), 0 }, +/*c5*/ { "lds", TRUE, LONG, op2(E, R), 0 }, +/*c6*/ { "mov", TRUE, BYTE, op2(I, E), 0 }, +/*c7*/ { "mov", TRUE, LONG, op2(I, E), 0 }, + +/*c8*/ { "enter", FALSE, NONE, op2(Iw, Ib), 0 }, +/*c9*/ { "leave", FALSE, NONE, 0, 0 }, +/*ca*/ { "lret", FALSE, NONE, op1(Iw), 0 }, +/*cb*/ { "lret", FALSE, NONE, 0, 0 }, +/*cc*/ { "int", FALSE, NONE, op1(o3), 0 }, +/*cd*/ { "int", FALSE, NONE, op1(Ib), 0 }, +/*ce*/ { "into", FALSE, NONE, 0, 0 }, +/*cf*/ { "iret", FALSE, NONE, 0, 0 }, + +/*d0*/ { "", TRUE, BYTE, op2(o1, E), db_Grp2 }, +/*d1*/ { "", TRUE, LONG, op2(o1, E), db_Grp2 }, +/*d2*/ { "", TRUE, BYTE, op2(CL, E), db_Grp2 }, +/*d3*/ { "", TRUE, LONG, op2(CL, E), db_Grp2 }, +/*d4*/ { "aam", FALSE, NONE, op1(Iba), 0 }, +/*d5*/ { "aad", FALSE, NONE, op1(Iba), 0 }, +/*d6*/ { ".byte\t0xd6", FALSE, NONE, 0, 0 }, +/*d7*/ { "xlat", FALSE, BYTE, op1(BX), 0 }, + +/*d8*/ { "", TRUE, NONE, 0, db_Esc8 }, +/*d9*/ { "", TRUE, NONE, 0, db_Esc9 }, +/*da*/ { "", TRUE, NONE, 0, db_Esca }, +/*db*/ { "", TRUE, NONE, 0, db_Escb }, +/*dc*/ { "", TRUE, NONE, 0, db_Escc }, +/*dd*/ { "", TRUE, NONE, 0, db_Escd }, +/*de*/ { "", TRUE, NONE, 0, db_Esce }, +/*df*/ { "", TRUE, NONE, 0, db_Escf }, + +/*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 }, +/*e1*/ { "loope", FALSE, NONE, op1(Db), 0 }, +/*e2*/ { "loop", FALSE, NONE, op1(Db), 0 }, +/*e3*/ { "jcxz", FALSE, SDEP, op1(Db), "jecxz" }, +/*e4*/ { "in", FALSE, BYTE, op2(Ib, A), 0 }, +/*e5*/ { "in", FALSE, LONG, op2(Ib, A) , 0 }, +/*e6*/ { "out", FALSE, BYTE, op2(A, Ib), 0 }, +/*e7*/ { "out", FALSE, LONG, op2(A, Ib) , 0 }, + +/*e8*/ { "call", FALSE, NONE, op1(Dl), 0 }, +/*e9*/ { "jmp", FALSE, NONE, op1(Dl), 0 }, +/*ea*/ { "ljmp", FALSE, NONE, op1(OS), 0 }, +/*eb*/ { "jmp", FALSE, NONE, op1(Db), 0 }, +/*ec*/ { "in", FALSE, BYTE, op2(DX, A), 0 }, +/*ed*/ { "in", FALSE, LONG, op2(DX, A) , 0 }, +/*ee*/ { "out", FALSE, BYTE, op2(A, DX), 0 }, +/*ef*/ { "out", FALSE, LONG, op2(A, DX) , 0 }, + +/*f0*/ { "", FALSE, NONE, 0, 0 }, +/*f1*/ { ".byte\t0xf1", FALSE, NONE, 0, 0 }, +/*f2*/ { "", FALSE, NONE, 0, 0 }, +/*f3*/ { "", FALSE, NONE, 0, 0 }, +/*f4*/ { "hlt", FALSE, NONE, 0, 0 }, +/*f5*/ { "cmc", FALSE, NONE, 0, 0 }, +/*f6*/ { "", TRUE, BYTE, 0, db_Grp3 }, +/*f7*/ { "", TRUE, LONG, 0, db_Grp3 }, + +/*f8*/ { "clc", FALSE, NONE, 0, 0 }, +/*f9*/ { "stc", FALSE, NONE, 0, 0 }, +/*fa*/ { "cli", FALSE, NONE, 0, 0 }, +/*fb*/ { "sti", FALSE, NONE, 0, 0 }, +/*fc*/ { "cld", FALSE, NONE, 0, 0 }, +/*fd*/ { "std", FALSE, NONE, 0, 0 }, +/*fe*/ { "", TRUE, NONE, 0, db_Grp4 }, +/*ff*/ { "", TRUE, NONE, 0, db_Grp5 }, +}; + +static const struct inst db_bad_inst = + { "???", FALSE, NONE, 0, 0 } +; + +#define f_mod(byte) ((byte)>>6) +#define f_reg(byte) (((byte)>>3)&0x7) +#define f_rm(byte) ((byte)&0x7) + +#define sib_ss(byte) ((byte)>>6) +#define sib_index(byte) (((byte)>>3)&0x7) +#define sib_base(byte) ((byte)&0x7) + +struct i_addr { + int is_reg; /* if reg, reg number is in 'disp' */ + int disp; + const char * base; + const char * index; + int ss; +}; + +static const char * const db_index_reg_16[8] = { + "%bx,%si", + "%bx,%di", + "%bp,%si", + "%bp,%di", + "%si", + "%di", + "%bp", + "%bx" +}; + +static const char * const db_reg[3][8] = { + {"%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh"}, + {"%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di"}, + {"%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi"} +}; + +static const char * const db_seg_reg[8] = { + "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "", "" +}; + +/* + * lengths for size attributes + */ +static const int db_lengths[] = { + 1, /* BYTE */ + 2, /* WORD */ + 4, /* LONG */ + 8, /* QUAD */ + 4, /* SNGL */ + 8, /* DBLR */ + 10, /* EXTR */ +}; + +#define get_value_inc(result, loc, size, is_signed) \ + result = db_get_value((loc), (size), (is_signed)); \ + (loc) += (size); + +//static db_addr_t +// db_disasm_esc __P((db_addr_t loc, int inst, int short_addr, +// int size, const char *seg)); +//static void db_print_address __P((const char *seg, int size, +// struct i_addr *addrp)); +static db_addr_t + db_read_address __P((db_addr_t loc, int short_addr, + int regmodrm, struct i_addr *addrp)); + +/* + * Read address at location and return updated location. + */ +static db_addr_t +db_read_address(loc, short_addr, regmodrm, addrp) + db_addr_t loc; + int short_addr; + int regmodrm; + struct i_addr * addrp; /* out */ +{ + int mod, rm, sib, index, disp; + + mod = f_mod(regmodrm); + rm = f_rm(regmodrm); + + if (mod == 3) { + addrp->is_reg = TRUE; + addrp->disp = rm; + return (loc); + } + addrp->is_reg = FALSE; + addrp->index = 0; + + if (short_addr) { + addrp->index = 0; + addrp->ss = 0; + switch (mod) { + case 0: + if (rm == 6) { + get_value_inc(disp, loc, 2, FALSE); + addrp->disp = disp; + addrp->base = 0; + } + else { + addrp->disp = 0; + addrp->base = db_index_reg_16[rm]; + } + break; + case 1: + get_value_inc(disp, loc, 1, TRUE); + disp &= 0xFFFF; + addrp->disp = disp; + addrp->base = db_index_reg_16[rm]; + break; + case 2: + get_value_inc(disp, loc, 2, FALSE); + addrp->disp = disp; + addrp->base = db_index_reg_16[rm]; + break; + } + } + else { + if (mod != 3 && rm == 4) { + get_value_inc(sib, loc, 1, FALSE); + rm = sib_base(sib); + index = sib_index(sib); + if (index != 4) + addrp->index = db_reg[LONG][index]; + addrp->ss = sib_ss(sib); + } + + switch (mod) { + case 0: + if (rm == 5) { + get_value_inc(addrp->disp, loc, 4, FALSE); + addrp->base = 0; + } + else { + addrp->disp = 0; + addrp->base = db_reg[LONG][rm]; + } + break; + + case 1: + get_value_inc(disp, loc, 1, TRUE); + addrp->disp = disp; + addrp->base = db_reg[LONG][rm]; + break; + + case 2: + get_value_inc(disp, loc, 4, FALSE); + addrp->disp = disp; + addrp->base = db_reg[LONG][rm]; + break; + } + } + return (loc); +} + +/* + * NWT: fault injection routine only. disasm floating-point instruction + * and return updated location. + */ +static db_addr_t +my_disasm_esc( + db_addr_t loc, + int inst, + int short_addr, + int size, + const char * seg) +{ + int regmodrm; + const struct finst * fp; + int mod; + struct i_addr address; + const char * name; + + get_value_inc(regmodrm, loc, 1, FALSE); + fp = &db_Esc_inst[inst - 0xd8][f_reg(regmodrm)]; + mod = f_mod(regmodrm); + if (mod != 3) { + if (*fp->f_name == '\0') { + return (loc); + } + /* + * Normal address modes. + */ + loc = db_read_address(loc, short_addr, regmodrm, &address); + switch(fp->f_size) { + case SNGL: + break; + case DBLR: + break; + case EXTR: + break; + case WORD: + break; + case LONG: + break; + case QUAD: + break; + default: + break; + } + } + else { + /* + * 'reg-reg' - special formats + */ + switch (fp->f_rrmode) { + case op2(ST,STI): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + break; + case op2(STI,ST): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + break; + case op1(STI): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + break; + case op1(X): + name = ((const char * const *)fp->f_rrname)[f_rm(regmodrm)]; + if (*name == '\0') + goto bad; + break; + case op1(XA): + name = ((const char * const *)fp->f_rrname)[f_rm(regmodrm)]; + if (*name == '\0') + goto bad; + break; + default: + bad: + break; + } + } + + return (loc); +} +/* + * Disassemble instruction at 'loc'. 'altfmt' specifies an + * (optional) alternate format. Return address of start of + * next instruction. + */ +db_addr_t +my_disasm(db_addr_t loc, + boolean_t altfmt) +{ + int inst; + int size; + int short_addr; + const char * seg; + const struct inst * ip; + const char * i_name; + int i_size; + int i_mode; + int regmodrm = 0; + boolean_t first; + int displ; + int prefix; + int imm; + int imm2; + int len; + struct i_addr address; + + get_value_inc(inst, loc, 1, FALSE); + short_addr = FALSE; + size = LONG; + seg = 0; + + /* + * Get prefixes + */ + prefix = TRUE; + do { + switch (inst) { + case 0x66: /* data16 */ + size = WORD; + break; + case 0x67: + short_addr = TRUE; + break; + case 0x26: + seg = "%es"; + break; + case 0x36: + seg = "%ss"; + break; + case 0x2e: + seg = "%cs"; + break; + case 0x3e: + seg = "%ds"; + break; + case 0x64: + seg = "%fs"; + break; + case 0x65: + seg = "%gs"; + break; + case 0xf0: + // db_printf("lock "); + break; + case 0xf2: + // db_printf("repne "); + break; + case 0xf3: + // db_printf("repe "); /* XXX repe VS rep */ + break; + default: + prefix = FALSE; + break; + } + if (prefix) { + get_value_inc(inst, loc, 1, FALSE); + } + } while (prefix); + + if (inst >= 0xd8 && inst <= 0xdf) { + loc = my_disasm_esc(loc, inst, short_addr, size, seg); + return (loc); + } + + if (inst == 0x0f) { + get_value_inc(inst, loc, 1, FALSE); + ip = db_inst_0f[inst>>4]; + if (ip == 0) { + ip = &db_bad_inst; + } + else { + ip = &ip[inst&0xf]; + } + } + else + ip = &db_inst_table[inst]; + + if (ip->i_has_modrm) { + unsigned long prev_loc=loc; + extern unsigned long modAddr; + + get_value_inc(regmodrm, loc, 1, FALSE); + loc = db_read_address(loc, short_addr, regmodrm, &address); + modAddr=prev_loc; +// printf("modrm at %x, offset %d\n", loc, loc-prev_loc); + } + + i_name = ip->i_name; + i_size = ip->i_size; + i_mode = ip->i_mode; + + if (ip->i_extra == db_Grp1 || ip->i_extra == db_Grp2 || + ip->i_extra == db_Grp6 || ip->i_extra == db_Grp7 || + ip->i_extra == db_Grp8 || ip->i_extra == db_Grp9) { + i_name = ((const char * const *)ip->i_extra)[f_reg(regmodrm)]; + } + else if (ip->i_extra == db_Grp3) { + ip = ip->i_extra; + ip = &ip[f_reg(regmodrm)]; + i_name = ip->i_name; + i_mode = ip->i_mode; + } + else if (ip->i_extra == db_Grp4 || ip->i_extra == db_Grp5) { + ip = ip->i_extra; + ip = &ip[f_reg(regmodrm)]; + i_name = ip->i_name; + i_mode = ip->i_mode; + i_size = ip->i_size; + } + + if (i_size == SDEP) { + } + else { + if (i_size != NONE) { + if (i_size == BYTE) { + size = BYTE; + } + else if (i_size == WORD) { + size = WORD; + } + } + } + for (first = TRUE; + i_mode != 0; + i_mode >>= 8, first = FALSE) + { + + switch (i_mode & 0xFF) { + + case E: + // db_print_address(seg, size, &address); + break; + + case Eind: + // db_print_address(seg, size, &address); + break; + + case El: + // db_print_address(seg, LONG, &address); + break; + + case Ew: + // db_print_address(seg, WORD, &address); + break; + + case Eb: + // db_print_address(seg, BYTE, &address); + break; + + case R: + // db_printf("%s", db_reg[size][f_reg(regmodrm)]); + break; + + case Rw: + // db_printf("%s", db_reg[WORD][f_reg(regmodrm)]); + break; + + case Ri: + // db_printf("%s", db_reg[size][f_rm(inst)]); + break; + + case Ril: + // db_printf("%s", db_reg[LONG][f_rm(inst)]); + break; + + case S: + // db_printf("%s", db_seg_reg[f_reg(regmodrm)]); + break; + + case Si: + // db_printf("%s", db_seg_reg[f_reg(inst)]); + break; + + case A: + // db_printf("%s", db_reg[size][0]); /* acc */ + break; + + case BX: + break; + + case CL: + break; + + case DX: + break; + + case SI: + break; + + case DI: + break; + + case CR: + break; + + case DR: + break; + + case TR: + break; + + case I: + len = db_lengths[size]; + get_value_inc(imm, loc, len, FALSE); + break; + + case Is: + len = db_lengths[size]; + get_value_inc(imm, loc, len, FALSE); + /* + * XXX the + in this format doesn't seem to work right. + * `Is' is equivalent to `I'. + */ + break; + + case Ib: + get_value_inc(imm, loc, 1, FALSE); + break; + + case Iba: + get_value_inc(imm, loc, 1, FALSE); + break; + + case Ibs: + get_value_inc(imm, loc, 1, TRUE); + if (size == WORD) + imm &= 0xFFFF; + break; + + case Iw: + get_value_inc(imm, loc, 2, FALSE); + break; + + case O: + len = (short_addr ? 2 : 4); + get_value_inc(displ, loc, len, FALSE); + if (seg) ; + else +// db_printsym((db_addr_t)displ, DB_STGY_ANY); + break; + + case Db: + get_value_inc(displ, loc, 1, TRUE); + displ += loc; + if (size == WORD) + displ &= 0xFFFF; +// db_printsym((db_addr_t)displ, DB_STGY_XTRN); + break; + + case Dl: + len = db_lengths[size]; + get_value_inc(displ, loc, len, FALSE); + displ += loc; + if (size == WORD) + displ &= 0xFFFF; +// db_printsym((db_addr_t)displ, DB_STGY_XTRN); + break; + + case o1: + break; + + case o3: + break; + + case OS: + len = db_lengths[size]; + get_value_inc(imm, loc, len, FALSE); /* offset */ + get_value_inc(imm2, loc, 2, FALSE); /* segment */ + break; + } + } +// db_printf("\n"); + return (loc); +} diff --git a/commands/swifi/db_machdep.h b/commands/swifi/db_machdep.h new file mode 100644 index 000000000..07f71dc3f --- /dev/null +++ b/commands/swifi/db_machdep.h @@ -0,0 +1,99 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + * + * $Id: db_machdep.h,v 1.1 2003/01/15 21:51:24 mikesw Exp $ + */ + +#ifndef _MACHINE_DB_MACHDEP_H_ +#define _MACHINE_DB_MACHDEP_H_ + +//#include +//#include + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define i386_saved_state trapframe + +typedef vm_offset_t db_addr_t; /* address - unsigned */ +typedef int db_expr_t; /* expression - signed */ + +typedef struct i386_saved_state db_regs_t; +extern db_regs_t ddb_regs; /* register state */ +#define DDB_REGS (&ddb_regs) + +#define PC_REGS(regs) (((regs)->tf_cs & 0xfffc) == 0x08 \ + ? (db_addr_t)(regs)->tf_eip : 0) + +#define BKPT_INST 0xcc /* breakpoint instruction */ +#define BKPT_SIZE (1) /* size of breakpoint inst */ +#define BKPT_SET(inst) (BKPT_INST) + +#define FIXUP_PC_AFTER_BREAK ddb_regs.tf_eip -= 1; + +#define db_clear_single_step(regs) ((regs)->tf_eflags &= ~PSL_T) +#define db_set_single_step(regs) ((regs)->tf_eflags |= PSL_T) + +#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT) +/* + * Watchpoints are not supported. The debug exception type is in %dr6 + * and not yet in the args to this macro. + */ +#define IS_WATCHPOINT_TRAP(type, code) 0 + +#define I_CALL 0xe8 +#define I_CALLI 0xff +#define I_RET 0xc3 +#define I_IRET 0xcf + +#define inst_trap_return(ins) (((ins)&0xff) == I_IRET) +#define inst_return(ins) (((ins)&0xff) == I_RET) +#define inst_call(ins) (((ins)&0xff) == I_CALL || \ + (((ins)&0xff) == I_CALLI && \ + ((ins)&0x3800) == 0x1000)) +#define inst_load(ins) 0 +#define inst_store(ins) 0 + +/* + * There no interesting addresses below _kstack = 0xefbfe000. There + * are small absolute values for GUPROF, but we don't want to see them. + * Treat "negative" addresses below _kstack as non-small to allow for + * future reductions of _kstack and to avoid sign extension problems. + * + * There is one interesting symbol above -db_maxoff = 0xffff0000, + * namely _APTD = 0xfffff000. Accepting this would mess up the + * printing of small negative offsets. The next largest symbol is + * _APTmap = 0xffc00000. Accepting this is OK (unless db_maxoff is + * set to >= 0x400000 - (max stack offset)). + */ +#define DB_SMALL_VALUE_MAX 0x7fffffff +#define DB_SMALL_VALUE_MIN (-0x400001) + +#endif /* !_MACHINE_DB_MACHDEP_H_ */ diff --git a/commands/swifi/db_sym.c b/commands/swifi/db_sym.c new file mode 100644 index 000000000..86460b1a2 --- /dev/null +++ b/commands/swifi/db_sym.c @@ -0,0 +1,583 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + * + * $Id: db_sym.c,v 1.2 2003/01/16 01:06:09 mikesw Exp $ + */ + +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ +//#include +//#include +#include +#include +#include +#include "ddb.h" +#include "db_sym.h" +#include "swifi.h" + +/* + * Multiple symbol tables + */ +#ifndef MAXNOSYMTABS +#define MAXNOSYMTABS 3 /* mach, ux, emulator */ +#endif +#if 0 + +static db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},}; +static int db_nsymtab = 0; + +static db_symtab_t *db_last_symtab; + +static db_sym_t db_lookup __P(( char *symstr)); +static char *db_qualify __P((db_sym_t sym, char *symtabname)); +static boolean_t db_symbol_is_ambiguous __P((db_sym_t sym)); +static boolean_t db_line_at_pc __P((db_sym_t, char **, int *, + db_expr_t)); + +/* + * Add symbol table, with given name, to list of symbol tables. + */ +void +db_add_symbol_table(start, end, name, ref) + char *start; + char *end; + char *name; + char *ref; +{ + if (db_nsymtab >= MAXNOSYMTABS) { + printk ("No slots left for %s symbol table", name); + panic ("db_sym.c: db_add_symbol_table"); + } + + db_symtabs[db_nsymtab].start = start; + db_symtabs[db_nsymtab].end = end; + db_symtabs[db_nsymtab].name = name; + db_symtabs[db_nsymtab].private = ref; + db_nsymtab++; +} + +/* + * db_qualify("vm_map", "ux") returns "unix:vm_map". + * + * Note: return value points to static data whose content is + * overwritten by each call... but in practice this seems okay. + */ +static char * +db_qualify(sym, symtabname) + db_sym_t sym; + register char *symtabname; +{ + char *symname; + static char tmp[256]; + + db_symbol_values(sym, &symname, 0); + strcpy(tmp,symtabname); + strcat(tmp,":"); + strcat(tmp,symname); + return tmp; +} + + +boolean_t +db_eqname(src, dst, c) + char *src; + char *dst; + char c; +{ + if (!strcmp(src, dst)) + return (TRUE); + if (src[0] == c) + return (!strcmp(src+1,dst)); + return (FALSE); +} + +boolean_t +db_value_of_name(name, valuep) + char *name; + db_expr_t *valuep; +{ + db_sym_t sym; + + sym = db_lookup(name); + if (sym == DB_SYM_NULL) + return (FALSE); + db_symbol_values(sym, &name, valuep); + return (TRUE); +} + + +/* + * Lookup a symbol. + * If the symbol has a qualifier (e.g., ux:vm_map), + * then only the specified symbol table will be searched; + * otherwise, all symbol tables will be searched. + */ +static db_sym_t +db_lookup(symstr) + char *symstr; +{ + db_sym_t sp; + register int i; + int symtab_start = 0; + int symtab_end = db_nsymtab; + register char *cp; + + /* + * Look for, remove, and remember any symbol table specifier. + */ + for (cp = symstr; *cp; cp++) { + if (*cp == ':') { + *cp = '\0'; + for (i = 0; i < db_nsymtab; i++) { + if (! strcmp(symstr, db_symtabs[i].name)) { + symtab_start = i; + symtab_end = i + 1; + break; + } + } + *cp = ':'; + if (i == db_nsymtab) { + db_error("invalid symbol table name"); + } + symstr = cp+1; + } + } + + /* + * Look in the specified set of symbol tables. + * Return on first match. + */ + for (i = symtab_start; i < symtab_end; i++) { + sp = X_db_lookup(&db_symtabs[i], symstr); + if (sp) { + db_last_symtab = &db_symtabs[i]; + return sp; + } + } + return 0; +} + +/* + * Does this symbol name appear in more than one symbol table? + * Used by db_symbol_values to decide whether to qualify a symbol. + */ +static boolean_t db_qualify_ambiguous_names = FALSE; + +static boolean_t +db_symbol_is_ambiguous(sym) + db_sym_t sym; +{ + char *sym_name; + register int i; + register + boolean_t found_once = FALSE; + + if (!db_qualify_ambiguous_names) + return FALSE; + + db_symbol_values(sym, &sym_name, 0); + for (i = 0; i < db_nsymtab; i++) { + if (X_db_lookup(&db_symtabs[i], sym_name)) { + if (found_once) + return TRUE; + found_once = TRUE; + } + } + return FALSE; +} + +/* + * Find the closest symbol to val, and return its name + * and the difference between val and the symbol found. + */ +db_sym_t +db_search_symbol( val, strategy, offp) + register db_addr_t val; + db_strategy_t strategy; + db_expr_t *offp; +{ + register + unsigned int diff; + unsigned int newdiff; + register int i; + db_sym_t ret = DB_SYM_NULL, sym; + + newdiff = diff = ~0; + db_last_symtab = 0; + for (i = 0; i < db_nsymtab; i++) { + sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff); + if (newdiff < diff) { + db_last_symtab = &db_symtabs[i]; + diff = newdiff; + ret = sym; + } + } + *offp = diff; + return ret; +} + +/* + * Return name and value of a symbol + */ +void +db_symbol_values(sym, namep, valuep) + db_sym_t sym; + char **namep; + db_expr_t *valuep; +{ + db_expr_t value; + + if (sym == DB_SYM_NULL) { + *namep = 0; + return; + } + + X_db_symbol_values(sym, namep, &value); + if (db_symbol_is_ambiguous(sym)) + *namep = db_qualify(sym, db_last_symtab->name); + if (valuep) + *valuep = value; +} + + +/* + * Print a the closest symbol to value + * + * After matching the symbol according to the given strategy + * we print it in the name+offset format, provided the symbol's + * value is close enough (eg smaller than db_maxoff). + * We also attempt to print [filename:linenum] when applicable + * (eg for procedure names). + * + * If we could not find a reasonable name+offset representation, + * then we just print the value in hex. Small values might get + * bogus symbol associations, e.g. 3 might get some absolute + * value like _INCLUDE_VERSION or something, therefore we do + * not accept symbols whose value is "small" (and use plain hex). + */ + + +void +db_printsym(off, strategy) + db_expr_t off; + db_strategy_t strategy; +{ + db_expr_t d; + char *filename; + char *name; + db_expr_t value; + int linenum; + db_sym_t cursym; + + cursym = db_search_symbol(off, strategy, &d); + db_symbol_values(cursym, &name, &value); + if (name == 0) + value = off; + if (value >= DB_SMALL_VALUE_MIN && value <= DB_SMALL_VALUE_MAX) { + printk("0x%x", off); + return; + } + if (name == 0 || d >= db_maxoff) { + printk("0x%x", off); + return; + } + printk("%s", name); + if (d) + printk("+0x%x", d); + if (strategy == DB_STGY_PROC) { + // if (db_line_at_pc(cursym, &filename, &linenum, off)) + // printk(" [%s:%d]", filename, linenum); + } +} + +#endif + +unsigned int db_maxoff = 0x10000; +unsigned long modAddr = 0; + +/* NWT: fault injection routine only. + * figure out start of function address given an address (off) in kernel text. + * name = function name + * value = function address + * d = difference between off and function address + * input is the desired address off and fault type + * returns closest instruction address (if found), NULL otherwise + */ +unsigned long +find_faulty_instr(db_expr_t off, int type, int *instr_len) +{ + db_expr_t d; + char *name; + db_expr_t value, cur_value, prev_value = 0; + int verbose=0, found=0; + const char * mod_name = NULL; + unsigned long mod_start; + unsigned long mod_end; + const char * sec_name = NULL; + unsigned long sec_start; + unsigned long sec_end; + const char * sym_name = NULL; + unsigned long sym_start; + unsigned long sym_end; + + + *instr_len = 0; + if (kallsyms_address_to_symbol(off, + &mod_name, &mod_start, &mod_end, + &sec_name, &sec_start, &sec_end, + &sym_name, &sym_start, &sym_end) == 0) { + return(0); + } + + value = (db_expr_t) sym_start; + d = off - sym_start; + name = (char *) sym_name; + + if (name == 0) { + value = off; + } + + if (value >= DB_SMALL_VALUE_MIN && value <= DB_SMALL_VALUE_MAX) { + printk("0x%x", off); + return 0; + } + + if (name == 0 || d >= db_maxoff) { + printk("0x%x", off); + return 0 ; + } + /* 2) backup to start of function (SOF) + * 3) delineate instruction boundaries, find instruction length too. + */ + + if(verbose) { + printk("function %s", sym_name); + } + + /* 4) skip instructions until we get to our faulty address */ + cur_value = value; + while(cur_value < sec_end) { + if(verbose) { + // db_printsym(cur_value, DB_STGY_PROC); + // printk(":\t"); + } + prev_value=cur_value; + modAddr=0; + if(verbose) { + //cur_value=db_disasm(prev_value, FALSE); + } else { + cur_value=my_disasm(prev_value, FALSE); + } + + /* 4a) bail out if instruction is leave (0xc9) */ + if(cur_value-prev_value == 1) { + unsigned char *c; + c=(char *) prev_value; + if(*c==0xc9) { + if(verbose) printk("bailing out as we hit a leave\n"); + found=0; + break; + } + } + /* 5a) init fault: from SOF, look for movl $X, -Y(%ebp), + * (C645Fxxx or C745Fxxx) and replace with nop. + */ + if(type==INIT_FAULT) { + unsigned char *c; + c=(char *) prev_value; + + if(*c==0x66 || *c==0x67) + c++; /* override prefix */ + + if(*c==0xC6 || *c==0xC7) + c++; /* movb or movl imm */ + else + continue; + + if(*c==0x45) + c++; /* [ebp] */ + else + continue; + + if(*c & 0x80) + found=1; /* negative displacement */ + else + continue; + + found=1; + break; + } else if(type==NOP_FAULT) { + /* 5b) nop*: replace instruction with nop */ + if(cur_value> off) { + found=1; + break; + } + } else if(type==DST_FAULT || type==SRC_FAULT) { + /* 5c) dst/src: flip bits in mod/rm, sib, disp or imm fields */ + if(cur_value>off && (cur_value-prev_value) > 1) { + found=1; + break; + } + } else if(type==BRANCH_FAULT || type==LOOP_FAULT) { + /* 5e) brc*: search forward utnil we hit a Jxx or rep (F3 or F2). + * replace instr with nop. + */ + unsigned char *c; + + c=(char *) prev_value; + + /* look for repX prefix */ + + if(*c==0xf3 || *c==0xf2) { + if(verbose) + printk("found repX prefix\n"); + /* take out repX prefix only */ + found=1; + cur_value=prev_value+1; + break; + } else if( ((*c)&0xf0)==0x70 || (*c>=0xe0 && *c<=0xe2) ) { + /* look for jXX 8 (7X), loop,jcx (e0-3), jXX 16/32 (0f 8X) */ + found=1; + if(verbose) + printk("found jXX rel8, loop or jcx\n"); + break; + } else if(*c==0x66 || *c==0x67) { /* override prefix */ + c++; + } else if(*(c++)==0xf && ((*c)&0xf0)==0x80 ) { + found=1; /* 0x0f 0x8X */ + if(verbose) printk("found branch!\n"); + break; + } + } else if(type==PTR_FAULT) { + /* 5f) ptr: if instruction has regmodrm byte (i_has_modrm), + * and mod field has address ([eyy]dispxx), eyy!=ebp + * flip 1 bit in lower byte (0x0f) or any bit in following + * bytes (sib, imm or disp). + */ + if(cur_value>off && modAddr) { + unsigned char *c; + c=(char *) modAddr; + if( (*c)>0x3f && (*c)<0xc0 && (((*c)&7)!=5) ) { + found=1; + break; + } + } + } else if(type==INTERFACE_FAULT) { + /* 5f) i/f: look for movl XX(ebp), reg or movb XX(ebp), reg, + * where XX is positive. replace instr with nop. + * movl=0x8a, movb=0x8b, mod=01XXX101 (disp8[ebp]), disp>0 + */ + unsigned char *c; + c=(char *) prev_value; + if( *c==0x8a || *c==0x8b) { + c++; + if( ((*(c++))&0xc7)==0x45 && ((*c)&0x80)==0 ) { + /* 75% chance that we'll choose the next arg */ + if(random()&0x3) { + found=1; + break; + } else { + if(verbose) printk("skipped...\n"); + } + } + } + }else if(type==IRQ_FAULT) { + /* 5g) i/f: look for push reg or offset(reg) / popf, + * where XX is positive. replace instr with nop. + * movl=0x8a, movb=0x8b, mod=01XXX101 (disp8[ebp]), disp>0 + */ + unsigned char *c; + c=(char *) prev_value; + if (((*c & 0xf8) == 0x50) || + (*c == 0xff)) { + if (*c == 0xff) { + c++; + // + // Look for push x(ebp) + if ((*c & 0x78) != 0x70) { + continue; + } + // + // Skip the offset + // + c++; + } + c++; + if (*c == 0x9d) { + // + // Increment cur_value to include the + // popf instruction + // + cur_value++; + found = 1; + break; + } + } + + } + } + /* if we're doing nop fault, then we're done. + */ + if(found) { + *instr_len=cur_value-prev_value; + off=prev_value; + if(1 || verbose) { + printk("%s", name); + if (d) printk("+0x%x", d); + printk(" @ %x, ", value); + printk("instr @ %x, len=%d, ", off, *instr_len); + // db_disasm(prev_value, FALSE); + } + return off; + } else { + if(verbose) printk("cannot locate instruction in function\n"); + *instr_len=0; + return 0; + } +} + +#if 0 +static boolean_t +db_line_at_pc( sym, filename, linenum, pc) + db_sym_t sym; + char **filename; + int *linenum; + db_expr_t pc; +{ + return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc); +} + +int +db_sym_numargs(sym, nargp, argnames) + db_sym_t sym; + int *nargp; + char **argnames; +{ + return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames); +} + +#endif diff --git a/commands/swifi/db_sym.h b/commands/swifi/db_sym.h new file mode 100644 index 000000000..66b700e5a --- /dev/null +++ b/commands/swifi/db_sym.h @@ -0,0 +1,118 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + * + * $Id: db_sym.h,v 1.1 2003/01/15 21:51:24 mikesw Exp $ + */ + +#ifndef _DDB_DB_SYM_H_ +#define _DDB_DB_SYM_H_ + +#define db_printf printk + +/* + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 8/90 + */ + +/* + * This module can handle multiple symbol tables + */ +typedef struct { + char *name; /* symtab name */ + char *start; /* symtab location */ + char *end; + char *private; /* optional machdep pointer */ +} db_symtab_t; + +extern db_symtab_t *db_last_symtab; /* where last symbol was found */ + +/* + * Symbol representation is specific to the symtab style: + * BSD compilers use dbx' nlist, other compilers might use + * a different one + */ +typedef char * db_sym_t; /* opaque handle on symbols */ +#define DB_SYM_NULL ((db_sym_t)0) + +/* + * Non-stripped symbol tables will have duplicates, for instance + * the same string could match a parameter name, a local var, a + * global var, etc. + * We are most concern with the following matches. + */ +typedef int db_strategy_t; /* search strategy */ + +#define DB_STGY_ANY 0 /* anything goes */ +#define DB_STGY_XTRN 1 /* only external symbols */ +#define DB_STGY_PROC 2 /* only procedures */ + +extern boolean_t db_qualify_ambiguous_names; + /* if TRUE, check across symbol tables + * for multiple occurrences of a name. + * Might slow down quite a bit */ + +/* + * Functions exported by the symtable module + */ +void db_add_symbol_table __P((char *, char *, char *, char *)); + /* extend the list of symbol tables */ + +db_sym_t db_search_symbol __P((db_addr_t, db_strategy_t, db_expr_t *)); + /* find symbol given value */ + +void db_symbol_values __P((db_sym_t, char **, db_expr_t *)); + /* return name and value of symbol */ + +#define db_find_sym_and_offset(val,namep,offp) \ + db_symbol_values(db_search_symbol(val,DB_STGY_ANY,offp),namep,0) + /* find name&value given approx val */ + +#define db_find_xtrn_sym_and_offset(val,namep,offp) \ + db_symbol_values(db_search_symbol(val,DB_STGY_XTRN,offp),namep,0) + /* ditto, but no locals */ + +int db_eqname __P((char *, char *, char)); + /* strcmp, modulo leading char */ + +void db_printsym __P((db_expr_t, db_strategy_t)); + /* print closest symbol to a value */ + +int db_sym_numargs __P((db_sym_t, int *, char **)); + +boolean_t X_db_line_at_pc __P((db_symtab_t *symtab, db_sym_t cursym, + char **filename, int *linenum, + db_expr_t off)); +db_sym_t X_db_lookup __P((db_symtab_t *stab, char *symstr)); +db_sym_t X_db_search_symbol __P((db_symtab_t *symtab, db_addr_t off, + db_strategy_t strategy, + db_expr_t *diffp)); +int X_db_sym_numargs __P((db_symtab_t *, db_sym_t, int *, + char **)); +void X_db_symbol_values __P((db_sym_t sym, char **namep, + db_expr_t *valuep)); +unsigned long +find_faulty_instr(db_expr_t off, int type, int *instr_len); + +#endif /* !_DDB_DB_SYM_H_ */ diff --git a/commands/swifi/ddb.h b/commands/swifi/ddb.h new file mode 100644 index 000000000..03553f21e --- /dev/null +++ b/commands/swifi/ddb.h @@ -0,0 +1,161 @@ +/*- + * Copyright (c) 1993, Garrett A. Wollman. + * Copyright (c) 1993, University of Vermont and State Agricultural College. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: ddb.h,v 1.1 2003/01/15 21:51:24 mikesw Exp $ + */ + +/* + * Necessary declarations for the `ddb' kernel debugger. + */ + +#ifndef _DDB_DDB_H_ +#define _DDB_DDB_H_ + +#define __P(protos) protos +typedef int boolean_t; +typedef unsigned long vm_offset_t; +unsigned long random __P((void)); +void srandom __P((unsigned long)); + +#include "db_machdep.h" /* type definitions */ + +typedef void db_cmdfcn_t __P((db_expr_t addr, boolean_t have_addr, + db_expr_t count, char *modif)); + +#define DB_COMMAND(cmd_name, func_name) \ + DB_SET(cmd_name, func_name, db_cmd_set) +#define DB_SHOW_COMMAND(cmd_name, func_name) \ + DB_SET(cmd_name, func_name, db_show_cmd_set) + +#define DB_SET(cmd_name, func_name, set) \ +static db_cmdfcn_t func_name; \ + \ +static const struct command __CONCAT(func_name,_cmd) = { \ + __STRING(cmd_name), \ + func_name, \ + 0, \ + 0, \ +}; \ +TEXT_SET(set, __CONCAT(func_name,_cmd)); \ + \ +static void \ +func_name(addr, have_addr, count, modif) \ + db_expr_t addr; \ + boolean_t have_addr; \ + db_expr_t count; \ + char *modif; + +extern char *esym; +extern unsigned int db_maxoff; +extern int db_indent; +extern int db_inst_count; +extern int db_load_count; +extern int db_store_count; +extern int db_radix; +extern int db_max_width; +extern int db_tab_stop_width; + +struct vm_map; + +void cnpollc __P((int)); +void db_check_interrupt __P((void)); +void db_clear_watchpoints __P((void)); +db_addr_t db_disasm __P((db_addr_t loc, boolean_t altfmt)); + /* instruction disassembler */ +//void db_error __P((char *s)); +#define db_error printk +int db_expression __P((db_expr_t *valuep)); +int db_get_variable __P((db_expr_t *valuep)); +void db_iprintf __P((const char *,...)); +struct vm_map *db_map_addr __P((vm_offset_t)); +boolean_t db_map_current __P((struct vm_map *)); +boolean_t db_map_equal __P((struct vm_map *, struct vm_map *)); +void db_print_loc_and_inst __P((db_addr_t loc)); +void db_printf __P((const char *fmt, ...)); +void db_read_bytes __P((vm_offset_t addr, int size, char *data)); + /* machine-dependent */ +int db_readline __P((char *lstart, int lsize)); +void db_restart_at_pc __P((boolean_t watchpt)); +void db_set_watchpoints __P((void)); +void db_skip_to_eol __P((void)); +boolean_t db_stop_at_pc __P((boolean_t *is_breakpoint)); +#define db_strcpy strcpy +void db_trap __P((int type, int code)); +int db_value_of_name __P((char *name, db_expr_t *valuep)); +void db_write_bytes __P((vm_offset_t addr, int size, char *data)); + /* machine-dependent */ +void kdb_init __P((void)); +void kdbprintf __P((const char *fmt, ...)); + +db_cmdfcn_t db_breakpoint_cmd; +db_cmdfcn_t db_continue_cmd; +db_cmdfcn_t db_delete_cmd; +db_cmdfcn_t db_deletewatch_cmd; +db_cmdfcn_t db_examine_cmd; +db_cmdfcn_t db_listbreak_cmd; +db_cmdfcn_t db_listwatch_cmd; +db_cmdfcn_t db_print_cmd; +db_cmdfcn_t db_ps; +db_cmdfcn_t db_search_cmd; +db_cmdfcn_t db_set_cmd; +db_cmdfcn_t db_show_regs; +db_cmdfcn_t db_single_step_cmd; +db_cmdfcn_t db_stack_trace_cmd; +db_cmdfcn_t db_trace_until_call_cmd; +db_cmdfcn_t db_trace_until_matching_cmd; +db_cmdfcn_t db_watchpoint_cmd; +db_cmdfcn_t db_write_cmd; + +#if 0 +db_cmdfcn_t db_help_cmd; +db_cmdfcn_t db_show_all_threads; +db_cmdfcn_t db_show_one_thread; +db_cmdfcn_t ipc_port_print; +db_cmdfcn_t vm_page_print; +#endif + +/* + * Command table. + */ +struct command { + char * name; /* command name */ + db_cmdfcn_t *fcn; /* function to call */ + int flag; /* extra info: */ +#define CS_OWN 0x1 /* non-standard syntax */ +#define CS_MORE 0x2 /* standard syntax, but may have other words + * at end */ +#define CS_SET_DOT 0x100 /* set dot after command */ + struct command *more; /* another level of command */ +}; + +db_addr_t +my_disasm(db_addr_t loc, + boolean_t altfmt); + +#endif /* !_DDB_DDB_H_ */ diff --git a/commands/swifi/fault_model.c b/commands/swifi/fault_model.c new file mode 100644 index 000000000..79326e946 --- /dev/null +++ b/commands/swifi/fault_model.c @@ -0,0 +1,1201 @@ +/* + * fault-model.c -- fault injection code for drivers + * + * Copyright (C) 2003 Mike Swift + * Copyright (c) 1999 Wee Teck Ng + * + * The source code in this file can be freely used, adapted, + * and redistributed in source or binary form, so long as an + * acknowledgment appears in derived source files. No warranty + * is attached; * we cannot take responsibility for errors or + * fitness for use. + * + */ + + +/* + * Fault injector for testing the usefulness of NOOKS + * + * Adapted from the SWIFI tools used by Wee Teck Ng to evaluate the RIO + * file cache at the University of Michigan + * + */ + +/* + * This tool can inject faults into modules, whether they are loaded into a + * nook or loaded into the kernel (for comparison testing). + * + * There are several classes of faults emulated: + * - Corruption of text + * - corruption + * - simulated programming faults + * - skip initialization (immediate write to EBP-x) + * - remove instruction (replace with NOP) + * - incorrect source/destination (corrupted) + * - remove jmp or rep instruction + * - change address computation for memory access (not stack) + * - change termination condition for loop (change repeat to repeat + * -while equal, change condition to !condition + - remove instructions loading registers from arguments (ebp+x) + * + * - Corruption of stack + * - Corruption of heap + * - copy overruns + * - use after free + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ddb.h" +#include "db_sym.h" +#include "swifi.h" + + +#define CRASH_INTERVAL 8192 +#define FI_MASK 0xfff +#define P50 0x3fffffff /* 50% of max rand */ +#define P94 0x7851eb84 /* 94% of max rand */ +#define NOP 0x90 + +unsigned long randomSeed=0; /* random number */ +unsigned long injectFault=1; /* inject fault ? */ +unsigned long diskTest=0; /* run disk test instead of rio */ +unsigned long faultInjected=0; /* has fault been injected? */ +unsigned long crashInterval=0; /* interval between injecting fault */ +unsigned long crashCount=0; /* number of times fault is injected */ +unsigned long faultType; +unsigned long numFaults; +char *crashAddr=0; /* track current malloc */ +int crashToggle=1; +int text_fault(struct module * module, pswifi_result_t res); +int stack_fault(pswifi_result_t res); +int heap_fault(pswifi_result_t res); +int direct_fault(int fault_address, int fault_content, pswifi_result_t res); +int direct_fault1(int fault_address, int fault_content, pswifi_result_t res); +int while1(void); + +int *testVA; + +#if 0 +#define PDEBUG(fmt, args...) \ +do { \ + printk( KERN_ALERT "SWIFI: " fmt, ## args); \ +} while (0) +#else +#define PDEBUG(fmt, args...) +#endif + + +#ifdef CONFIG_SWIFI + +static inline long +get_mod_name(const char *user_name, char **buf) +{ + unsigned long page; + long retval; + + page = __get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE); + if (retval > 0) { + if (retval < PAGE_SIZE) { + *buf = (char *)page; + return retval; + } + retval = -ENAMETOOLONG; + } else if (!retval) + retval = -EINVAL; + + free_page(page); + return retval; +} + +static inline void +put_mod_name(char *buf) +{ + free_page((unsigned long)buf); +} + +long +sys_inject_fault(char * module_name, + unsigned long argFaultType, + unsigned long argRandomSeed, + unsigned long argNumFaults, + pswifi_result_t result_record, + unsigned long argInjectFault) +{ + int result = 0; + unsigned long fault_address = 0; + unsigned long fault_data = 0 ; + char * kern_name = NULL; + struct module * mod = NULL; + int found = 0; + pswifi_result_t res = NULL; + + if (argNumFaults > SWIFI_MAX_FAULTS) { + result = -E2BIG; + goto Cleanup; + } + res = (pswifi_result_t) kmalloc((1+argNumFaults) * sizeof(swifi_result_t), + GFP_KERNEL); + if (res == NULL) { + result = -ENOMEM; + goto Cleanup; + } + memset(res, 0, (1 + argNumFaults) * sizeof(swifi_result_t)); + + // + // Capture the name of the module from usermode + // + + result = get_mod_name(module_name, &kern_name); + if (result < 0) { + goto Cleanup; + } + + + + + + lock_kernel(); + + for (mod = module_list; mod ; mod = mod->next) { + if (strcmp(kern_name, mod->name) == 0) { + found = 1; + break; + } + } + unlock_kernel(); + if (!found) { + result = -ENOENT; + goto Cleanup; + } + + numFaults = argNumFaults; + faultType = argFaultType; + randomSeed = argRandomSeed; + injectFault = argInjectFault; + + + if(faultType>=DISK_TEST) { + faultType=faultType-DISK_TEST; + diskTest=1; + } + if(faultType==STATS) { +#if 0 + extern long time_vmp, n_vmp; + extern long time_pmp, n_pmp; + + PDEBUG("# vm_map_protect=%ld, total cycle=%ld\n", n_vmp, time_vmp); + PDEBUG("# pmap_protect=%ld, total cycle=%ld\n", n_pmp, time_pmp); + n_vmp=0; time_vmp=0; + n_pmp=0; time_pmp=0; +#endif + } else if (faultType == DIRECT_FAULT) { + fault_address = numFaults; + fault_data = randomSeed; + PDEBUG("sys inject fault, type %ld, addr=%lx, flip bit%lx\n", + faultType, fault_address, fault_data); + } else if (faultType == DIRECT_FAULT1) { + fault_address = numFaults; + fault_data = randomSeed; + PDEBUG("sys inject fault, type %ld, addr=%lx, zero bytes %lx\n", + faultType, fault_address, fault_data); + } else { + PDEBUG("sys inject fault, type %ld, seed=%ld, fault=%ld, config=%ld\n", + faultType, randomSeed, numFaults, config); + } + faultInjected=1; + + srandom(randomSeed); + /* set warm reboot, leave RAM unchanged + * 0 : don't inject fault + * 1 : run POST, wipe out memory + * 2 : don't test memory + * 3 : don't change memory (doesn't work) + * 4 : don't sync registry + */ + + /* default number of faults is 5 */ + if(numFaults<=0 || numFaults>100) numFaults=5; + + switch(faultType) + { + case TEXT_FAULT: + result = text_fault(mod, res); + break; + case STACK_FAULT: + result = stack_fault(res); + break; + case HEAP_FAULT: + result = heap_fault(res); + break; + case INIT_FAULT: + case NOP_FAULT: + case DST_FAULT: + case SRC_FAULT: + case BRANCH_FAULT: + case PTR_FAULT: + case LOOP_FAULT: + case INTERFACE_FAULT: + case IRQ_FAULT: + result = text_fault(mod, res); + break; + case FREE_FAULT: + case BCOPY_FAULT: + case SYNC_FAULT: + case ALLOC_FAULT: + crashInterval=CRASH_INTERVAL; /* interval between crash */ + break; + case MEM_LEAK_FAULT: + crashToggle=0; + crashInterval=CRASH_INTERVAL; /* interval between crash */ + break; + case PANIC_FAULT: + panic("testing panic"); + result = 0; + break; + /* case WP_FAULT: page_reg_fault(random()); break; */ + case DIRECT_FAULT: + { + direct_fault(fault_address, fault_data, res); + break; + } + case DIRECT_FAULT1: + { + result = direct_fault1(fault_address, fault_data, res); + + break; + } + /* case PAGE_REG_DUMP: rio_dump(); break; */ + case WHILE1_FAULT: + { + + result = while1(); + + break; + } + /* case CPU_RESET_FAULT: cpu_reset(); break; */; + case COW_FAULT: + { + /* test writing to kernel text. freebsd currently do a COW on a + * write to kernel text. + */ + unsigned long *addr1, *addr2; + + addr1 = (unsigned long *) 0xf0212000; + addr2 = (unsigned long *) 0xf0212010; + PDEBUG("%p=%lx, %p=%lx\n", addr1, *addr1, addr2, *addr2); + __asm__ ("movl $0xf0212000, %eax\n\t" \ + "movl $6, 0(%eax)\n\t" \ + "movl $6, 4(%eax)\n\t"); + addr1 = (unsigned long *) 0xf0212000; + addr2 = (unsigned long *) 0xf0212010; + PDEBUG("after injecting fault\n"); + PDEBUG("%p=%lx, %p=%lx\n", addr1, *addr1, addr2, *addr2); + result = 0; + break; + } + + case DEBUGGER_FAULT: + PDEBUG("Debugger fault"); + __asm__ ("movl %cr4, %ecx\n\t" \ + "movl $42, %ecx; .byte 0x0f, 0x32\n\t" \ + "movl $377, %ecx; .byte 0x0f, 0x32\n\t"); + result = 0; + break; + default: PDEBUG("unknown fault type %ld\n", faultType); break; + } + if (copy_to_user(result_record, res, argNumFaults * sizeof(swifi_result_t))) { + result = -EFAULT; + } + Cleanup: + if (kern_name != NULL) { + put_mod_name(kern_name); + } + if (res != NULL) { + kfree(res); + } + + return (result); +} + +int while1(void) +{ + int i=0; + + PDEBUG("entering into while 1 loop\n"); + while(1) { + udelay(20000); + PDEBUG("delay %4d secs, cpl=0x%x, ipend=0x%x\n", i+=5, 20, 30); + if(i>(100 * 2500)) + break; + } + return(0); +} + + +int direct_fault(int fault_address, int fault_content, pswifi_result_t res) +{ + unsigned long *addr; + int flip_bit=0; + + + addr = (unsigned long *) (PAGE_OFFSET + fault_address); + + PDEBUG("%p:0x%lx => ", addr, *addr); + + flip_bit = 1 << fault_content; + + res[0].address = (unsigned long) addr; + res[0].old = *addr; + res[0].new = (*addr) ^ flip_bit; + + if (injectFault) { + *addr = (*addr) ^ flip_bit; + } + PDEBUG("%lx\n", *addr); + return(0); +} + +int direct_fault1(int fault_address, int fault_content, pswifi_result_t res) +{ + unsigned long *addr, data; + + + addr = (unsigned long *) (PAGE_OFFSET + fault_address); + + PDEBUG("%p:%lx => ", addr, *addr); + + + data = *addr; + if(fault_content==1) { + data = data & 0xffffff00; + data = data | 0x00000090; + } else if(fault_content==2) { + data = data & 0xffff0000; + data = data | 0x00009090; + } else if(fault_content==3) { + data = data & 0xff000000; + data = data | 0x00909090; + } else if(fault_content==4) { + data = 0x90909090; + } + res[0].address = (unsigned long) addr; + res[0].old = *addr; + res[0].new = data; + if (injectFault) { + *addr = data; + } + + PDEBUG("%lx\n", *addr); + + + return(0); +} + + + + +#include + +#define MAX_NUM_TASKS 20 + +struct task_struct * +find_task(void) +{ + struct task_struct * task = NULL, *result = NULL ; + int i,j; + i = 1 + (random() % MAX_NUM_TASKS); + j = i; + + + do { + read_lock(&tasklist_lock); + for_each_task(task) { + if (--i == 0) { + result = task; + break; + } + } + read_unlock(&tasklist_lock); + } while ((i > 0) && (i != j)); + + return(result); +} + +int +stack_fault(pswifi_result_t res) +{ + unsigned long *addr, size, taddr; + int flip_bit=0; + int count=0; + struct task_struct *task = NULL; + + while(count < numFaults) { + task = find_task(); + if (task == NULL) { + return(-1); + } + + size = (unsigned long) task + TASK_SIZE - task->thread.esp; + + PDEBUG("stack range=%lx-%lx\n", + (unsigned long) task->thread.esp, + (unsigned long) task + TASK_SIZE); + + addr = (unsigned long *) ((long) task->thread.esp + + (random()&~0x3)%size); + taddr=(unsigned long) addr; + flip_bit = random() & 0x1f; + PDEBUG("%lx:%lx flip bit %d => ", taddr, *addr, flip_bit); + flip_bit = 1 << flip_bit; + res[count].address = taddr; + res[count].old = *addr; + res[count].new = (*addr) ^ flip_bit; + if (injectFault) { + *addr = ((*addr)^flip_bit); + } + PDEBUG("%lx\n", *addr); + count++; + } + return(0); +} + + +// +// Instead of dealing with heaps directly, we look at the area cache of pages +// and vm pages and find an address there. +// + + +int heap_fault(pswifi_result_t res) +{ +#ifdef notdef + unsigned long *addr, taddr; + int flip_bit=0; + int count=0; + unsigned long flags; + struct list_head *next; + + addr = (unsigned long *) (map->address + (random()&~0xf)%map->size); + + taddr=(unsigned long) addr; + flip_bit = random() & 0x1f; + PDEBUG("heap range=%lx-%lx ", map->address, map->address + map->size); + PDEBUG("%lx:%lx flip bit %d => ", taddr, *addr, flip_bit); + flip_bit = 1 << flip_bit; + res[count].address = taddr; + res[count].old = *addr; + res[count].new = (*addr) ^ flip_bit; + + if (injectFault) { + *addr = ((*addr)^flip_bit); + } + PDEBUG("%lx\n", *addr); + count++; + } while (count < numFaults); +#endif + return(-1); + +} + + +unsigned long +do_fault_copy_from_user (void *kaddr, const void *udaddr, unsigned long len, + unsigned long (* copy_fn) (void *, const void *, unsigned long)) +{ + unsigned int prob, i=0; + + if ( faultInjected && (faultType==BCOPY_FAULT) ) { + + if (++crashCount == crashInterval) { + + crashCount=0; + prob = random(); + crashInterval = CRASH_INTERVAL + (random() & FI_MASK); + + if (prob < P50) { /* corrupt 1 QW */ + i=1; + } else if (prob < P94) { /* corrupt 2 - 1024 QW */ + i = prob & 0x3fe; + while(!i) { + i = random() & 0x3fe; + } + } else { /* corrupt 2-4 pages */ + i= prob & 0xc00; + while(!i) { + i = random() & 0xc00; + } + } + PDEBUG("copyin: %p to %p, len=%ld overrun=%d, Intvl=%ld, inj=%ld\n", + udaddr, kaddr, len, i, crashInterval, faultInjected); + if (faultInjected++ =crashInterval) { + + /* alternate between premature freeing and non-free */ + if(crashToggle) { + if(crashAddr) { + PDEBUG("malloc : freeing %p prematurely\n", + crashAddr); + kfree_fn(crashAddr); + kfree_fn(addr); + crashAddr=0; + crashToggle=0; + crashCount=0; + crashInterval = CRASH_INTERVAL + (random()&FI_MASK); + if (faultInjected++ > numFaults) { + faultInjected=0; + } + } + } else { + PDEBUG("free: don't free %p\n", addr); + if(faultInjected++ > numFaults) { + faultInjected=0; + } + if(faultType==FREE_FAULT) { + crashToggle=1; + } + crashCount=0; + crashInterval = CRASH_INTERVAL + (random()&FI_MASK); + } + } + } else { + kfree_fn(addr); + } +} + +void +swifi_kfree(const void *addr) +{ + do_fault_kfree((void *) addr, kfree); +} + + +void do_vfree(const void * addr) +{ + vfree((void *) addr); +} + + +void +swifi_vfree(void *addr) +{ + do_fault_kfree(addr, do_vfree); +} + + + + +void * +do_fault_kmalloc(size_t size, + int flags, + void * (* kmalloc_fn)(size_t size, int flags)) +{ + if (faultInjected && (faultType==ALLOC_FAULT)) { + crashCount++; + if(crashCount>=crashInterval) { + PDEBUG("kmalloc : returning null\n"); + crashCount=0; + crashInterval = CRASH_INTERVAL + (random()&FI_MASK); + if (faultInjected++ > numFaults) { + faultInjected=0; + return(NULL); + } + + } + } + + return(kmalloc_fn(size, flags)); +} + + +void * +swifi_kmalloc(size_t size, int flags) +{ + return(do_fault_kmalloc(size, flags, kmalloc)); +} + + + +void * do_fault_vmalloc(unsigned long size, + int gfp_mask, + pgprot_t prot, + void * (*vmalloc_fn)(unsigned long size, + int gfp_mask, + pgprot_t prot)) +{ + if (faultInjected && (faultType==ALLOC_FAULT)) { + crashCount++; + if(crashCount>=crashInterval) { + PDEBUG("vmalloc : returning null\n"); + crashCount=0; + crashInterval = CRASH_INTERVAL + (random()&FI_MASK); + if (faultInjected++ > numFaults) { + faultInjected=0; + return(NULL); + } + + } + } + return(vmalloc_fn(size, gfp_mask, prot)); +} + +void * +swifi___vmalloc(unsigned long size, int gfp_mask, pgprot_t prot) +{ + return(do_fault_vmalloc(size, gfp_mask, prot, __vmalloc)); +} + + + +typedef struct section_callback { + const char * module_name; + const char * section_name; + unsigned long sec_start; + unsigned long sec_end; +} section_callback_t; + +static int +text_section_callback(void *token, + const char *modname, + const char *secname, + ElfW(Addr) secstart, + ElfW(Addr) secend, + ElfW(Word) secflags) +{ + section_callback_t * info = (section_callback_t *) token; + + if ((strcmp(modname, info->module_name) == 0) && + (strcmp(secname, info->section_name) == 0)) { + info->sec_start = secstart; + info->sec_end = secend; + return(1); + } + return(0); +} + + + + + +int text_fault(struct module * mod, pswifi_result_t res) +{ + unsigned long *addr, text_size, offset, page, taddr; + unsigned long btext, etext; + + int count, flip_bit=0, len, rc; + unsigned char *c; + struct module * module; + section_callback_t info; + + // + +#define MAX_NUM_MODULES 10 + + /* inject faults into text space */ + + for(count=0; countname; + info.section_name = ".text"; + + kallsyms_sections(&info, text_section_callback); + if (info.sec_start == 0 ) { + return(-1); + } + + btext = info.sec_start; + etext = info.sec_end; + text_size = etext - btext; + + PDEBUG("text=%lx-%lx, size=%lx\n", btext, etext, text_size); + + addr = (unsigned long *) + (btext + ((unsigned long) (random()&~0xf) % text_size)); + + /* now the tricky part */ + + taddr=(unsigned long) addr; + if( faultType==INIT_FAULT || + faultType==NOP_FAULT || + faultType==DST_FAULT || + faultType==SRC_FAULT || + faultType==BRANCH_FAULT || + faultType==PTR_FAULT || + faultType==LOOP_FAULT || + faultType==INTERFACE_FAULT || + faultType==IRQ_FAULT ) { + addr = (unsigned long *) find_faulty_instr(taddr, faultType, &len); + /* do it over again if we can't find the right instruction */ + if(!addr || !len ) { + i--; + continue; + } + } + PDEBUG("target addr=%lx, instr addr=%p, %lx=>", taddr, addr, *addr); + + offset = (unsigned long) addr&PAGE_MASK; + page = (unsigned long) addr&~PAGE_MASK; + + /* it doesn't matter what we used here to unprotect page, + * as this routine will not be in production code. + */ + + res[count].address = taddr; + res[count].old = *addr; + res[count].new = *addr; + + if (faultType==TEXT_FAULT) { + + flip_bit = random() & 0x1f; + PDEBUG("flip bit %d => ", flip_bit); + flip_bit = 1 << flip_bit; + + res[count].new = (*addr) ^ flip_bit; + + if (injectFault) { + *addr = ((*addr)^flip_bit); + } + + } else if (faultType==NOP_FAULT || + faultType==INIT_FAULT || + faultType==BRANCH_FAULT || + faultType==INTERFACE_FAULT || + faultType==IRQ_FAULT) { + c = (unsigned char *) addr; + + for (j = 0; j < len; j++) { + /* replace these bytes with NOP (*c=NOP) */ + if (j < sizeof(unsigned long)) { + ((unsigned char *) &res[count].new)[j] = NOP; + } + if (injectFault) { + *c=NOP; + } + + c++; + } + } else if (faultType==DST_FAULT || faultType==SRC_FAULT) { + /* skip thru the prefix and opcode, and flip bits in following bytes */ + int prefix; + c=(unsigned char *) addr; + do { + switch (*c) { + case 0x66: case 0x67: case 0x26: case 0x36: + case 0x2e: case 0x3e: case 0x64: case 0x65: + case 0xf0: case 0xf2: case 0xf3: + prefix = 1; + break; + default: + prefix = 0; + break; + } + if (prefix) { + c++; + } + } while (prefix); + if(*c>=0xd8 && *c<=0xdf) { + /* don't mess with fp instruction, yet. + * but there shouldn't be any fp instr in kernel. + */ + PDEBUG("floating point instruction, bailing out\n"); + i--; + continue; + } else if(*c==0x0f) { + c++; + } + if(*c==0x0f) { + c++; + } + c++; + len = len-((long) c - (long) addr); + flip_bit = random() % (len*8); + PDEBUG("flip bit %d (len=%d) => ", flip_bit, len); + for(j=0; j=0xd8 && *c<=0xdf) { + /* don't mess with fp instruction, yet */ + PDEBUG("floating point instruction, bailing out\n"); + i--; + continue; + } else if(*c==0x0f) { + c++; + } + if(*c==0x0f) { + c++; + } + c++; + len = len-((long) c - (long) addr); + flip_bit = random() % (len*8-4); + PDEBUG("flip bit %d (len=%d) => ", flip_bit, len); + + /* mod/rm byte is special */ + + if (flip_bit < 4) { + flip_bit = 1 << flip_bit; + + rc = c - (unsigned char *) addr; + if (rc < sizeof(unsigned long)) { + ((unsigned char *) &res[count].new)[rc] = (*c) ^ flip_bit; + + } + if (injectFault) { + *c=(*c^flip_bit); + } + + } + c++; + flip_bit=flip_bit-4; + + for(j=1; j +#include +#include "swifi.h" + + +EXPORT_SYMBOL(sys_inject_fault); + +EXPORT_SYMBOL(swifi_memmove_fn); +EXPORT_SYMBOL(swifi_memcpy_fn); +EXPORT_SYMBOL(memmove_fn); +EXPORT_SYMBOL(memcpy_fn); +EXPORT_SYMBOL(swifi_kfree); +EXPORT_SYMBOL(swifi_vfree); +EXPORT_SYMBOL(swifi_kmalloc); +EXPORT_SYMBOL(swifi___vmalloc); +EXPORT_SYMBOL(swifi___generic_copy_from_user); +EXPORT_SYMBOL(swifi___generic_copy_to_user); + + diff --git a/commands/swifi/swifi-user.h b/commands/swifi/swifi-user.h new file mode 100644 index 000000000..d24aecedd --- /dev/null +++ b/commands/swifi/swifi-user.h @@ -0,0 +1,46 @@ +#ifndef _SWIFI_USER_H +#define _SWIFI_USER_H + + +#define TEXT_FAULT 0 +#define STACK_FAULT 1 +#define HEAP_FAULT 2 +#define INIT_FAULT 3 +#define NOP_FAULT 4 +#define DST_FAULT 5 +#define SRC_FAULT 6 +#define BRANCH_FAULT 7 +#define PTR_FAULT 8 +#define FREE_FAULT 9 +#define BCOPY_FAULT 10 +#define SYNC_FAULT 11 +#define LOOP_FAULT 12 +#define MEM_LEAK_FAULT 13 +#define INTERFACE_FAULT 14 +#define DIRECT_FAULT 15 +#define DIRECT_FAULT1 16 +#define STATS 17 +#define WP_FAULT 19 +#define PANIC_FAULT 20 +#define WHILE1_FAULT 21 +#define DEBUGGER_FAULT 22 +#define CPU_RESET_FAULT 23 +#define PAGE_REG_DUMP 24 +#define COW_FAULT 25 +#define IRQ_FAULT 26 +#define ALLOC_FAULT 27 +#define DISK_TEST 100 + + +#define SWIFI_MAX_FAULTS 1000 + +typedef struct swifi_result { + unsigned long address; + unsigned long old; + unsigned long new; +} swifi_result_t, *pswifi_result_t; + + + +#endif // _SWIFI_USER_H + diff --git a/commands/swifi/swifi.h b/commands/swifi/swifi.h new file mode 100644 index 000000000..b5e5364e7 --- /dev/null +++ b/commands/swifi/swifi.h @@ -0,0 +1,61 @@ +#ifndef _LINUX_SWIFI_H +#define _LINUX_SWIFI_H + +#include "swifi-user.h" + +long +swifi_inject_fault(char * nook_name, + unsigned long faultType, + unsigned long randSeed, + unsigned long numFaults, + void * results, + unsigned long do_inject); + + +long +sys_inject_fault(char * module, + unsigned long argFaultType, + unsigned long argRandomSeed, + unsigned long argNumFaults, + pswifi_result_t result_record, + unsigned long argInjectFault); + +void +swifi_kfree(const void *addr); + + +void +swifi_vfree(void *addr); + + +void * +swifi_memmove_fn(void *to, void *from, size_t len); + + +void * +swifi_memcpy_fn(void *to, void *from, size_t len); + + +void * +memmove_fn(void *to, void *from, size_t len); + +void * +memcpy_fn(void *to, void *from, size_t len); + +unsigned long +swifi___generic_copy_from_user (void *kaddr, void *udaddr, unsigned long len); + +unsigned long +swifi___generic_copy_to_user(void *udaddr, void *kaddr, unsigned long len); + + +void * +swifi_kmalloc(size_t size, int flags); + + +void * +swifi___vmalloc(unsigned long size, int gfp_mask, pgprot_t prot); + + +#endif // _LINUX_SWIFI_H +