├── README ├── example ├── faultinject.py └── pin.instcategory.txt ├── faultinjection.cpp ├── faultinjection.h ├── fi_cjmp_map.h ├── instcategory.cpp ├── instcount.cpp ├── instselector.cpp ├── instselector.h ├── makefile ├── makefile.rules ├── pin.config.instselector.txt ├── utils.cpp └── utils.h /README: -------------------------------------------------------------------------------- 1 | HOW TO USE PINFI: 2 | 3 | 1. Installation 4 | - Make sure pin is installed. 5 | - Create a directory under /source/tools, such as /source/tools/pinfi 6 | - Copy the top-level directory (everything except the example/ subdirectory) to /source/tools/pinfi 7 | - In the command line, type 'make' under /source/tools/pinfi to compile the pinfi. 8 | - After compiling pinfi, a folder called obj-intel64 will be created under the project folder. 9 | 10 | 2. Usage 11 | 12 | - We provide a fault injection script located in example/, namely faultinject.py. There are several variables in the script need to be set based on your own configurations: 13 | - progbin: folder path to the benchmark under test 14 | - pinbin: path to the executable of pin 15 | - instcategorylib: path to instcategory.so which can be found under obj-intel64 folder. 16 | - instcountlib: path to instcount.so which can be found under obj-intel64 folder. 17 | - filib: path to faultinjection.so which can be found under obj-intel64 folder. 18 | - outputdir: std output generated by the benchmark under test. 19 | - errordir: error output generated by the benchmark under test. 20 | - basedir: golden output generated by the benchmark under test. 21 | - optionlist: configure parameters as desired based on the benchmark undertest. 22 | 23 | - Put the instructions category (default is 'all') that are desired to be fault injected in pin.instcategory.txt under the directory where faultinject.py locates, and run faultinject.py to inject faults in the specified locations. We provide an example of the pin.instcategory.txt file in example/ as well. 24 | -------------------------------------------------------------------------------- /example/faultinject.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import os 5 | import getopt 6 | import time 7 | import random 8 | import signal 9 | import subprocess 10 | 11 | #basedir = "/home/jshwei/Desktop/splash_time_automated" 12 | #basedir = "." 13 | currdir = "." 14 | progbin = currdir + "/libquantum" 15 | pinbin = "pin" 16 | instcategorylib = "/ubc/ece/home/kp/grads/jwei/pin/source/tools/FaultInject/obj-intel64/instcategory.so" 17 | instcountlib = "/ubc/ece/home/kp/grads/jwei/pin/source/tools/FaultInject/obj-intel64/instcount.so" 18 | filib = "/ubc/ece/home/kp/grads/jwei/pin/source/tools/FaultInject/obj-intel64/faultinjection.so" 19 | #inputfile = currdir + "/inputs/input.2048" 20 | outputdir = currdir + "/prog_output" 21 | basedir = currdir + "/baseline" 22 | errordir = currdir + "/error_output" 23 | 24 | if not os.path.isdir(outputdir): 25 | os.mkdir(outputdir) 26 | if not os.path.isdir(basedir): 27 | os.mkdir(basedir) 28 | if not os.path.isdir(errordir): 29 | os.mkdir(errordir) 30 | 31 | timeout = 500 32 | 33 | optionlist = ["33", "5"] 34 | 35 | def execute( execlist): 36 | #print "Begin" 37 | #inputFile = open(inputfile, "r") 38 | global outputfile 39 | print ' '.join(execlist) 40 | #print outputfile 41 | outputFile = open(outputfile, "w") 42 | p = subprocess.Popen(execlist, stdout = outputFile) 43 | elapsetime = 0 44 | while (elapsetime < timeout): 45 | elapsetime += 1 46 | time.sleep(1) 47 | #print p.poll() 48 | if p.poll() is not None: 49 | print "\t program finish", p.returncode 50 | print "\t time taken", elapsetime 51 | #outputFile = open(outputfile, "w") 52 | #outputFile.write(p.communicate()[0]) 53 | outputFile.close() 54 | #inputFile.close() 55 | return str(p.returncode) 56 | #inputFile.close() 57 | outputFile.close() 58 | print "\tParent : Child timed out. Cleaning up ... " 59 | p.kill() 60 | return "timed-out" 61 | #should never go here 62 | sys.exit(syscode) 63 | 64 | 65 | def main(): 66 | #clear previous output 67 | global run_number, optionlist, outputfile 68 | outputfile = basedir + "/golden_output" 69 | execlist = [pinbin, '-t', instcategorylib, '--', progbin] 70 | execlist.extend(optionlist) 71 | execute(execlist) 72 | 73 | 74 | # baseline 75 | outputfile = basedir + "/golden_output" 76 | execlist = [pinbin, '-t', instcountlib, '--', progbin] 77 | execlist.extend(optionlist) 78 | execute(execlist) 79 | # fault injection 80 | for index in range(0, run_number): 81 | outputfile = outputdir + "/outputfile-" + str(index) 82 | errorfile = errordir + "/errorfile-" + str(index) 83 | execlist = [pinbin, '-t', filib, '-fioption', 'AllInst', '--', progbin] 84 | execlist.extend(optionlist) 85 | ret = execute(execlist) 86 | if ret == "timed-out": 87 | error_File = open(errorfile, 'w') 88 | error_File.write("Program hang\n") 89 | error_File.close() 90 | elif int(ret) < 0: 91 | error_File = open(errorfile, 'w') 92 | error_File.write("Program crashed, terminated by the system, return code " + ret + '\n') 93 | error_File.close() 94 | elif int(ret) > 0: 95 | error_File = open(errorfile, 'w') 96 | error_File.write("Program crashed, terminated by itself, return code " + ret + '\n') 97 | error_File.close() 98 | 99 | if __name__=="__main__": 100 | global run_number 101 | assert len(sys.argv) == 2 and "Format: prog fi_number" 102 | run_number = int(sys.argv[1]) 103 | main() 104 | -------------------------------------------------------------------------------- /example/pin.instcategory.txt: -------------------------------------------------------------------------------- 1 | BINARY 2 | ADD 3 | CMP 4 | DEC 5 | IDIV 6 | IMUL 7 | INC 8 | NEG 9 | SUB 10 | BITBYTE 11 | BT 12 | CONVERT 13 | CDQ 14 | CVTSD2SS 15 | CVTSI2SD 16 | CVTSI2SS 17 | CVTSS2SD 18 | CVTTSD2SI 19 | DATAXFER 20 | MOV 21 | MOVAPS 22 | MOVQ 23 | MOVSD_XMM 24 | MOVSS 25 | MOVSXD 26 | MOVZX 27 | LOGICAL 28 | AND 29 | ANDPS 30 | OR 31 | PXOR 32 | TEST 33 | XOR 34 | MISC 35 | LEA 36 | POP 37 | POP 38 | PUSH 39 | PUSH 40 | SHIFT 41 | SAR 42 | SHL 43 | SHR 44 | SSE 45 | ADDSD 46 | ADDSS 47 | DIVSD 48 | DIVSS 49 | MULSD 50 | MULSS 51 | SQRTSD 52 | SUBSD 53 | SUBSS 54 | UCOMISD 55 | UCOMISS 56 | -------------------------------------------------------------------------------- /faultinjection.cpp: -------------------------------------------------------------------------------- 1 | #include "faultinjection.h" 2 | #include 3 | #include 4 | #include "pin.H" 5 | #include "fi_cjmp_map.h" 6 | 7 | #include "utils.h" 8 | #include "instselector.h" 9 | 10 | //#define INCLUDEALLINST 11 | #define NOBRANCHES //always set 12 | //#define NOSTACKFRAMEOP 13 | //#define ONLYFP 14 | 15 | UINT64 fi_inject_instance = 0; 16 | UINT64 fi_iterator = 0; 17 | UINT64 total_num_inst = 0; 18 | int activated = 0; 19 | 20 | 21 | CJmpMap jmp_map; 22 | 23 | 24 | VOID FI_InjectFault_FlagReg(VOID * ip, UINT32 reg_num, UINT32 jmp_num, CONTEXT* ctxt) 25 | { 26 | if(fi_iterator == fi_inject_instance) { 27 | 28 | bool isvalid = false; 29 | 30 | const REG reg = reg_map.findInjectReg(reg_num); 31 | if(REG_valid(reg)){ 32 | 33 | isvalid = true; 34 | 35 | CJmpMap::JmpType jmptype = jmp_map.findJmpType(jmp_num); 36 | PRINT_MESSAGE(3, ("EXECUTING flag reg: Original Reg name %s value %p\n", REG_StringShort(reg).c_str(), 37 | (VOID*)PIN_GetContextReg( ctxt, reg ))); 38 | if(jmptype == CJmpMap::DEFAULT) { 39 | ADDRINT temp = PIN_GetContextReg( ctxt, reg ); 40 | UINT32 inject_bit = jmp_map.findInjectBit(jmp_num); 41 | temp = temp ^ (1UL << inject_bit); 42 | 43 | PIN_SetContextReg( ctxt, reg, temp); 44 | } else if (jmptype == CJmpMap::USPECJMP) { 45 | ADDRINT temp = PIN_GetContextReg( ctxt, reg ); 46 | UINT32 CF_val = (temp & (1UL << CF_BIT)) >> CF_BIT; 47 | UINT32 ZF_val = (temp & (1UL << ZF_BIT)) >> ZF_BIT; 48 | if(CF_val || ZF_val) { 49 | temp = temp & (~(1UL << CF_BIT)); 50 | temp = temp & (~(1UL << ZF_BIT)); 51 | } 52 | else { 53 | temp = temp | (1UL << ZF_BIT); 54 | } 55 | PIN_SetContextReg( ctxt, reg, temp); 56 | } else { 57 | ADDRINT temp = PIN_GetContextReg( ctxt, reg ); 58 | UINT32 SF_val = (temp & (1UL << SF_BIT)) >> SF_BIT; 59 | UINT32 OF_val = (temp & (1UL << OF_BIT)) >> OF_BIT; 60 | UINT32 ZF_val = (temp & (1UL << ZF_BIT)) >> ZF_BIT; 61 | if(ZF_val || (SF_val != OF_val)) { 62 | temp = temp & (~(1UL << ZF_BIT)); 63 | if(SF_val != OF_val) { 64 | temp = temp ^ (1UL << SF_BIT); 65 | } 66 | } 67 | else { 68 | temp = temp | (1UL << ZF_BIT); 69 | } 70 | PIN_SetContextReg( ctxt, reg, temp); 71 | } 72 | PRINT_MESSAGE(3, ("EXECUTING flag reg: Changed Reg name %s value %p\n", REG_StringShort(reg).c_str(), 73 | (VOID*)PIN_GetContextReg( ctxt, reg ))); 74 | 75 | //FI_PrintActivationInfo(); 76 | //fi_iterator ++; 77 | } 78 | if(isvalid){ 79 | fprintf(activationFile, "Activated: Valid Reg name %s in %p\n", REG_StringShort(reg).c_str(), ip); 80 | fclose(activationFile); // can crash after this! 81 | activated = 1; 82 | fi_iterator ++; 83 | 84 | PIN_ExecuteAt(ctxt); 85 | //PIN_ExecuteAt() will lead to reexecution of the function right after injection 86 | } 87 | 88 | 89 | 90 | else 91 | fi_inject_instance++; 92 | 93 | //fi_iterator ++; 94 | 95 | } 96 | fi_iterator ++; 97 | } 98 | 99 | 100 | 101 | //analysis code -- injection code 102 | /* 103 | VOID inject_SP_FP(VOID *ip, UINT32 reg_num, CONTEXT *ctxt){ 104 | if(fi_iterator == fi_inject_instance) { 105 | const REG reg = reg_map.findInjectReg(reg_num); 106 | if(!REG_valid(reg)){ 107 | fprintf(stderr, "ERROR, Has to be one of SP or BP\n"); 108 | exit(1); 109 | } 110 | PRINT_MESSAGE(4, ("EXECUTING: Reg name %s value %p\n", REG_StringShort(reg).c_str(), 111 | (VOID*)PIN_GetContextReg( ctxt, reg ))); 112 | 113 | ADDRINT temp = PIN_GetContextReg( ctxt, reg ); 114 | srand((unsigned)time(0)); 115 | UINT32 low_bound_bit = reg_map.findLowBoundBit(reg_num); 116 | UINT32 high_bound_bit = reg_map.findHighBoundBit(reg_num); 117 | 118 | UINT32 inject_bit = (rand() % (high_bound_bit - low_bound_bit)) + low_bound_bit; 119 | 120 | temp = (ADDRINT) (temp ^ (1UL << inject_bit)); 121 | 122 | PIN_SetContextReg( ctxt, reg, temp); 123 | PRINT_MESSAGE(4, ("EXECUTING: Changed Reg name %s value %p\n", REG_StringShort(reg).c_str(), 124 | (VOID*)PIN_GetContextReg( ctxt, reg ))); 125 | 126 | FI_PrintActivationInfo(); 127 | fi_iterator ++; 128 | PIN_ExecuteAt(ctxt); 129 | } 130 | //PIN_ExecuteAt() will lead to reexecution of the function right after injection 131 | fi_iterator ++; 132 | } 133 | */ 134 | 135 | 136 | VOID inject_CCS(VOID *ip, UINT32 reg_num, CONTEXT *ctxt){ 137 | //need to consider FP regs and context 138 | if(fi_iterator == fi_inject_instance) { 139 | const REG reg = reg_map.findInjectReg(reg_num); 140 | int isvalid = 0; 141 | if(REG_valid(reg)){ 142 | isvalid = 1; 143 | //PRINT_MESSAGE(4, ("Executing: Valid Reg name %s\n", REG_StringShort(reg).c_str())); 144 | 145 | if(reg_map.isFloatReg(reg_num)) { 146 | //PRINT_MESSAGE(4, ("Executing: Float Reg name %s\n", REG_StringShort(reg).c_str())); 147 | 148 | if (REG_is_xmm(reg)) { 149 | PRINT_MESSAGE(4, ("Executing: xmm: Reg name %s\n", REG_StringShort(reg).c_str())); 150 | 151 | FI_SetXMMContextReg(ctxt, reg, reg_num); 152 | } 153 | else if (REG_is_ymm(reg)) { 154 | 155 | PRINT_MESSAGE(4, ("Executing: ymm: Reg name %s\n", REG_StringShort(reg).c_str())); 156 | 157 | FI_SetYMMContextReg(ctxt, reg, reg_num); 158 | } 159 | //else if(REG_is_fr_or_x87(reg) || REG_is_mm(reg)) { 160 | else if(REG_is_fr(reg) || REG_is_mm(reg)) { 161 | PRINT_MESSAGE(4, ("Executing: mm or x87: Reg name %s\n", REG_StringShort(reg).c_str())); 162 | 163 | FI_SetSTContextReg(ctxt, reg, reg_num); 164 | } 165 | else { 166 | fprintf(stderr, "Register %s not covered!\n", REG_StringShort(reg).c_str()); 167 | exit(3); 168 | } 169 | } 170 | else{ 171 | //PRINT_MESSAGE(4, ("EXECUTING: Reg name %s value %p\n", REG_StringShort(reg).c_str(), 172 | // (VOID*)PIN_GetContextReg( ctxt, reg ))); 173 | 174 | ADDRINT temp = PIN_GetContextReg( ctxt, reg ); 175 | srand((unsigned)time(0)); 176 | UINT32 low_bound_bit = reg_map.findLowBoundBit(reg_num); 177 | UINT32 high_bound_bit = reg_map.findHighBoundBit(reg_num); 178 | 179 | UINT32 inject_bit = (rand() % (high_bound_bit - low_bound_bit)) + low_bound_bit; 180 | 181 | temp = (ADDRINT)(temp ^ (1UL << inject_bit)); 182 | 183 | PIN_SetContextReg( ctxt, reg, temp); 184 | 185 | 186 | //PRINT_MESSAGE(4, ("EXECUTING: Changed Reg name %s value %p\n", REG_StringShort(reg).c_str(), 187 | // (VOID*)PIN_GetContextReg( ctxt, reg ))); 188 | } 189 | 190 | //FI_PrintActivationInfo(); 191 | } 192 | if(isvalid){ 193 | fprintf(activationFile, "Activated: Valid Reg name %s in %p\n", REG_StringShort(reg).c_str(), ip); 194 | fclose(activationFile); // can crash after this! 195 | activated = 1; 196 | fi_iterator ++; 197 | 198 | PIN_ExecuteAt(ctxt); 199 | //PIN_ExecuteAt() will lead to reexecution of the function right after injection 200 | } 201 | else 202 | fi_inject_instance++; 203 | } 204 | fi_iterator ++; 205 | } 206 | 207 | VOID FI_InjectFault_Mem(VOID * ip, VOID *memp, UINT32 size) 208 | { 209 | if(fi_iterator == fi_inject_instance) { 210 | if(size == 4) { 211 | PRINT_MESSAGE(4, ("Executing %p, memory %p, value %d, in hex %p\n", 212 | ip, memp, * ((int*)memp), (VOID*)(*((int*)memp)))); 213 | } 214 | 215 | UINT8* temp_p = (UINT8*) memp; 216 | srand((unsigned)time(0)); 217 | UINT32 inject_bit = rand() % (size * 8/* bits in one byte*/); 218 | 219 | UINT32 byte_num = inject_bit / 8; 220 | UINT32 offset_num = inject_bit % 8; 221 | 222 | *(temp_p + byte_num) = *(temp_p + byte_num) ^ (1U << offset_num); 223 | 224 | if(size == 4) { 225 | PRINT_MESSAGE(4, ("Executing %p, memory %p, value %d, in hex %p\n", 226 | ip, memp, * ((int*)memp), (VOID*)(*((int*)memp)))); 227 | } 228 | 229 | 230 | fprintf(activationFile, "Activated: Memory injection\n"); 231 | fclose(activationFile); // can crash after this! 232 | activated = 1; 233 | 234 | 235 | fi_iterator ++; //This is because the inject_reg will mistakenly add 1 more time when injecting 236 | } 237 | 238 | fi_iterator ++; 239 | } 240 | 241 | VOID FI_InjectFault_MEM_ECC(VOID * ip, VOID *memp, UINT32 size,UINT32 num, BOOL mode) 242 | { 243 | if(fi_iterator == fi_inject_instance) { 244 | 245 | fprintf(activationFile, "Executing %p, memory %p, value %lld, in hex %llx, size %d\n", 246 | ip, memp, * ((long long*)memp), (*((long long*)memp)),size); 247 | 248 | 249 | UINT8* temp_p = (UINT8*) memp; 250 | srand((unsigned)time(0)); 251 | UINT32 last_inject_bit = 0; 252 | for (UINT32 i = 0; i < num; i ++) { 253 | UINT32 inject_bit = rand() % (size * 8/* bits in one byte*/); 254 | 255 | if ((i == num-1) && mode) 256 | { 257 | inject_bit = last_inject_bit+1; 258 | if (inject_bit == size*8) 259 | inject_bit = 0; // just do this for now. This case should be rare. 260 | } 261 | UINT32 byte_num = inject_bit / 8; 262 | UINT32 offset_num = inject_bit % 8; 263 | 264 | *(temp_p + byte_num) = *(temp_p + byte_num) ^ (1U << offset_num); 265 | 266 | 267 | fprintf(activationFile, "Executing %p, memory %p, value %lld, in hex %llx, injected_bit %d\n", 268 | ip, memp, * ((long long*)memp), (*((long long*)memp)),inject_bit); 269 | last_inject_bit = inject_bit; 270 | } 271 | fprintf(activationFile, "Activated: Memory injection\n"); 272 | fclose(activationFile); // can crash after this! 273 | activated = 1; 274 | 275 | 276 | fi_iterator ++; //This is because the inject_reg will mistakenly add 1 more time when injecting 277 | } 278 | 279 | fi_iterator ++; 280 | } 281 | 282 | 283 | VOID instruction_InstrumentationECC(INS ins, VOID *v) 284 | { 285 | int num = multibits.Value(); 286 | bool mode = consecutive.Value(); 287 | if (!isValidInst(ins)) 288 | return; 289 | // memory write, so the injection happens after 290 | /*if (INS_IsMemoryWrite(ins)){ 291 | INS_InsertPredicatedCall( 292 | ins, IPOINT_AFTER, (AFUNPTR)FI_InjectFault_MEM_ECC, 293 | IARG_ADDRINT, INS_Address(ins), 294 | IARG_MEMORYREAD_EA, 295 | IARG_MEMORYREAD_SIZE, 296 | IARG_UINT32,num, 297 | IARG_UINT32,mode, 298 | IARG_END); 299 | }*/ 300 | 301 | if (INS_IsMemoryRead(ins)){ 302 | INS_InsertPredicatedCall( 303 | ins, IPOINT_BEFORE, (AFUNPTR)FI_InjectFault_MEM_ECC, 304 | IARG_ADDRINT, INS_Address(ins), 305 | IARG_MEMORYREAD_EA, 306 | IARG_MEMORYREAD_SIZE, 307 | IARG_UINT32,num, 308 | IARG_BOOL,mode, 309 | IARG_END); 310 | } 311 | 312 | } 313 | 314 | 315 | VOID instruction_Instrumentation(INS ins, VOID *v){ 316 | // decides where to insert the injection calls and what calls to inject 317 | if (!isValidInst(ins)) 318 | return; 319 | 320 | int numW = INS_MaxNumWRegs(ins), randW = 0; 321 | UINT32 index = 0; 322 | REG reg; 323 | 324 | #ifdef INCLUDEALLINST 325 | int mayChangeControlFlow = 0; 326 | if(!INS_HasFallThrough(ins)) 327 | mayChangeControlFlow = 1; 328 | for(int i =0; i < numW; i++){ 329 | reg = INS_RegW(ins, i); 330 | if(reg == REG_RIP || reg == REG_EIP || reg == REG_IP) // conditional branches 331 | { mayChangeControlFlow = 1; break;} 332 | } 333 | if(numW > 1) 334 | randW = random() % numW; 335 | if(numW > 1 && (reg == REG_RFLAGS || reg == REG_FLAGS || reg == REG_EFLAGS)) 336 | randW = (randW + 1) % numW; 337 | if(numW > 1 && REG_valid(INS_RegW(ins, randW))) 338 | reg = INS_RegW(ins, randW); 339 | else 340 | reg = INS_RegW(ins, 0); 341 | if(!REG_valid(reg)) 342 | return; 343 | index = reg_map.findRegIndex(reg); 344 | LOG("ins:" + INS_Disassemble(ins) + "\n"); 345 | LOG("reg:" + REG_StringShort(reg) + "\n"); 346 | 347 | // FIXME: INCLUDEINST is not used now. However, if you enable this option 348 | // in the future, you need to change the code below. If it changes the 349 | // control flow, you need to inject fault in the read register rather than 350 | // write register 351 | if(mayChangeControlFlow) 352 | INS_InsertPredicatedCall( 353 | ins, IPOINT_BEFORE, (AFUNPTR)inject_CCS, 354 | IARG_ADDRINT, INS_Address(ins), 355 | IARG_UINT32, index, 356 | IARG_CONTEXT, 357 | IARG_END); 358 | else 359 | INS_InsertPredicatedCall( 360 | ins, IPOINT_AFTER, (AFUNPTR)inject_CCS, 361 | IARG_ADDRINT, INS_Address(ins), 362 | IARG_UINT32, index, 363 | IARG_CONTEXT, 364 | IARG_END); 365 | #else 366 | 367 | 368 | #ifdef NOBRANCHES 369 | if(INS_IsBranch(ins) || !INS_HasFallThrough(ins)) { 370 | //LOG("faultinject: branch/ret inst: " + INS_Disassemble(ins) + "\n"); 371 | return; 372 | } 373 | #endif 374 | 375 | // NOSTACKFRAMEOP must be used together with NOBRANCHES, IsStackWrite 376 | // has a bug that does not put pop into the list 377 | #ifdef NOSTACKFRAMEOP 378 | if(INS_IsStackWrite(ins) || OPCODE_StringShort(INS_Opcode(ins)) == "POP") { 379 | //LOG("faultinject: stack frame change inst: " + INS_Disassemble(ins) + "\n"); 380 | return; 381 | } 382 | #endif 383 | 384 | #ifdef ONLYFP 385 | bool hasfp = false; 386 | for (int i = 0; i < numW; i++){ 387 | if (reg_map.isFloatReg(reg)) { 388 | hasfp = true; 389 | break; 390 | } 391 | } 392 | if (!hasfp){ 393 | return; 394 | } 395 | #endif 396 | 397 | 398 | // select instruction based on instruction type 399 | if(!isInstFITarget(ins)) 400 | return; 401 | 402 | 403 | 404 | 405 | if(numW > 1) 406 | randW = random() % numW; 407 | else 408 | randW = 0; 409 | 410 | // Jiesheng 411 | reg = INS_RegW(ins, randW); 412 | #ifdef ONLYFP 413 | while (!reg_map.isFloatReg(reg)) { 414 | randW = (randW + 1) % numW; 415 | reg = INS_RegW(ins, randW); 416 | } 417 | #endif 418 | 419 | if(numW > 1 && (reg == REG_RFLAGS || reg == REG_FLAGS || reg == REG_EFLAGS)) 420 | randW = (randW + 1) % numW; 421 | if(numW > 1 && REG_valid(INS_RegW(ins, randW))) 422 | reg = INS_RegW(ins, randW); 423 | else 424 | reg = INS_RegW(ins, 0); 425 | if(!REG_valid(reg)) { 426 | 427 | LOG("REGNOTVALID: inst " + INS_Disassemble(ins) + "\n"); 428 | return; 429 | } 430 | index = reg_map.findRegIndex(reg); 431 | LOG("ins:" + INS_Disassemble(ins) + "\n"); 432 | LOG("reg:" + REG_StringShort(reg) + "\n"); 433 | 434 | // Jiesheng Wei 435 | if (reg == REG_RFLAGS || reg == REG_FLAGS || reg == REG_EFLAGS) { 436 | INS next_ins = INS_Next(ins); 437 | if (INS_Valid(next_ins) && INS_Category(next_ins) == XED_CATEGORY_COND_BR) { 438 | //LOG("inject flag bit:" + REG_StringShort(reg) + "\n"); 439 | 440 | UINT32 jmpindex = jmp_map.findJmpIndex(OPCODE_StringShort(INS_Opcode(next_ins))); 441 | INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)FI_InjectFault_FlagReg, 442 | IARG_INST_PTR, 443 | IARG_UINT32, index, 444 | IARG_UINT32, jmpindex, 445 | IARG_CONTEXT, 446 | IARG_END); 447 | return; 448 | } else if (INS_IsMemoryWrite(ins)) { 449 | LOG("COMP2MEM: inst " + INS_Disassemble(ins) + "\n"); 450 | 451 | INS_InsertPredicatedCall( 452 | ins, IPOINT_BEFORE, (AFUNPTR)FI_InjectFault_Mem, 453 | IARG_ADDRINT, INS_Address(ins), 454 | IARG_MEMORYREAD_EA, 455 | IARG_MEMORYREAD_SIZE, 456 | IARG_END); 457 | return; 458 | 459 | } else { 460 | LOG("NORMAL FLAG REG: inst " + INS_Disassemble(ins) + "\n"); 461 | } 462 | 463 | } 464 | 465 | 466 | 467 | INS_InsertPredicatedCall( 468 | ins, IPOINT_AFTER, (AFUNPTR)inject_CCS, 469 | IARG_ADDRINT, INS_Address(ins), 470 | IARG_UINT32, index, 471 | IARG_CONTEXT, 472 | IARG_END); 473 | #endif 474 | 475 | } 476 | 477 | VOID get_instance_number(const char* fi_instcount_file) 478 | { 479 | FILE *fi_input_FILE = fopen(fi_instcount_file, "r"); 480 | activationFile = fopen(fi_activation_file.Value().c_str(), "a"); 481 | char line_buffer[FI_MAX_CHAR_PER_LINE]; 482 | char *word = NULL; 483 | char *brnode = NULL; 484 | char *temp = NULL; 485 | UINT32 index = 0; 486 | if(fi_input_FILE == NULL) { 487 | fprintf(stderr, "ERROR, can not open Instruction count file %s, use -fi_function to specify a valid one\n", 488 | fi_instcount_file); 489 | exit(1); 490 | } 491 | if(!(fioption.Value() == CCS_INST || fioption.Value() == FP_INST || fioption.Value() == SP_INST || fioption.Value() == ALL_INST)){ 492 | fprintf(stderr, "ERROR, Specify one of valid options\n"); 493 | exit(1); 494 | } 495 | 496 | while(fgets(line_buffer,FI_MAX_CHAR_PER_LINE,fi_input_FILE) != NULL){ 497 | if(line_buffer[0] == '#') //only accept comments that start a new line 498 | continue; 499 | 500 | word=strtok_r(line_buffer,":", &brnode); 501 | index=0; 502 | while(word != NULL){ 503 | switch(index){ 504 | case 0: 505 | temp = word; 506 | break; 507 | case 1: 508 | if(strcmp(temp, fioption.Value().c_str()) == 0) 509 | total_num_inst = atol (word); 510 | break; 511 | default: 512 | fprintf(stderr, "Too many argument in the line\n"); 513 | exit(1); 514 | } 515 | index++; 516 | word=strtok_r(NULL,":",&brnode); 517 | } 518 | 519 | //assert((index == 2 || index == 0) && "Too few arguments in the line"); 520 | } 521 | //PRINT_MESSAGE(4, ("Num Insts:%llu\n",total_num_inst)); 522 | //srand((unsigned)time(0)); 523 | unsigned int seed; 524 | FILE* urandom = fopen("/dev/urandom", "r"); 525 | fread(&seed, sizeof(int), 1, urandom); 526 | fclose(urandom); 527 | srand(seed); 528 | fi_inject_instance = random() / (RAND_MAX * 1.0) * total_num_inst; 529 | //PRINT_MESSAGE(4, ("Instance:%llu\n",fi_inject_instance)); 530 | fclose(fi_input_FILE); 531 | } 532 | 533 | VOID Fini(INT32 code, VOID *v) 534 | { 535 | if(!activated){ 536 | fprintf(activationFile, "Not Activated!\n"); 537 | fclose(activationFile); 538 | } 539 | } 540 | 541 | /* ===================================================================== */ 542 | /* Print Help Message */ 543 | /* ===================================================================== */ 544 | 545 | INT32 Usage() 546 | { 547 | PIN_ERROR( "This Pintool does fault injection\n" 548 | + KNOB_BASE::StringKnobSummary() + "\n"); 549 | return -1; 550 | } 551 | 552 | int main(int argc, char *argv[]) 553 | { 554 | PIN_InitSymbols(); 555 | 556 | if (PIN_Init(argc, argv)) return Usage(); 557 | 558 | 559 | 560 | configInstSelector(); 561 | 562 | 563 | get_instance_number(instcount_file.Value().c_str()); 564 | 565 | if (!fiecc.Value()) 566 | INS_AddInstrumentFunction(instruction_Instrumentation, 0); 567 | 568 | else 569 | INS_AddInstrumentFunction(instruction_InstrumentationECC, 0); 570 | 571 | PIN_AddFiniFunction(Fini, 0); 572 | 573 | // Never returns 574 | PIN_StartProgram(); 575 | 576 | return 0; 577 | } 578 | 579 | -------------------------------------------------------------------------------- /faultinjection.h: -------------------------------------------------------------------------------- 1 | #ifndef FAULT_INJECTION_H 2 | #define FAULT_INJECTION_H 3 | #include 4 | #include "pin.H" 5 | #include "stdio.h" 6 | #include "stdlib.h" 7 | #include 8 | #include 9 | 10 | KNOB instcount_file(KNOB_MODE_WRITEONCE, "pintool", 11 | "o", "pin.instcount.txt", "specify instruction count file name"); 12 | 13 | KNOB fioption(KNOB_MODE_WRITEONCE, "pintool", "fioption", "", "specify fault injection option: all, sp, fp, ccs"); 14 | 15 | KNOB fi_activation_file (KNOB_MODE_WRITEONCE, "pintool", 16 | "fi_activation", "activate", "specify fault injection activation file"); 17 | 18 | KNOB fiecc(KNOB_MODE_WRITEONCE, "pintool", "e", "0", "enbale ecc error injection"); 19 | KNOB multibits(KNOB_MODE_WRITEONCE,"pintool","m","2","how many bits to inject"); 20 | KNOB consecutive(KNOB_MODE_WRITEONCE,"pintool","c","0","if the injected bits are consecutive"); 21 | //typedef uint64_t UINT64; 22 | //typedef uint32_t UINT32; 23 | 24 | FILE *activationFile; 25 | #define ALL_INST "AllInst" 26 | #define CCS_INST "CCSavedInst" 27 | #define FP_INST "FPInst" //EBP reg 28 | #define SP_INST "SPInst" 29 | #define FI_MAX_CHAR_PER_LINE 1000 30 | 31 | //modified version of Jiesheng's code for Reg Map and floating point registers, We need this for FI into CCS 32 | #define MAX_ST_NUM 8 33 | 34 | //#define DEBUG 35 | 36 | #ifdef DEBUG 37 | #define _logLevel 2 38 | 39 | #define PRINT_MESSAGE(l, x)\ 40 | if(l > _logLevel) {printf x; fflush(stdout);} 41 | #else 42 | 43 | #define PRINT_MESSAGE(l, x) 44 | 45 | #endif // DEBUG 46 | 47 | using namespace std; 48 | 49 | class RegMap{ 50 | 51 | struct Reg_Info { 52 | REG reg; 53 | REG inject_reg; 54 | UINT32 low_bit; 55 | UINT32 high_bit; 56 | bool fp_flag; 57 | 58 | Reg_Info (REG p_reg, REG p_inject, UINT32 p_low, UINT32 p_high, bool p_flag) { 59 | reg = p_reg; 60 | inject_reg = p_inject; 61 | low_bit = p_low; 62 | high_bit = p_high; 63 | fp_flag = p_flag; 64 | } 65 | }; 66 | typedef map RegInfoMap; 67 | 68 | RegInfoMap reg_map; 69 | 70 | public: 71 | 72 | RegMap(){ 73 | createMap(); 74 | } 75 | 76 | UINT32 findRegIndex(REG reg) { 77 | RegInfoMap::iterator reg_iter; 78 | for(reg_iter = reg_map.begin() ; reg_iter !=reg_map.end() ; reg_iter++ ) { 79 | if(reg_iter -> second -> reg == reg) 80 | return reg_iter -> first; 81 | } 82 | fprintf(stderr, "Register %s not in the list!\n", REG_StringShort(reg).c_str()); 83 | exit(2); 84 | } 85 | 86 | // Jiesheng: made changes to the find process for performance improvement 87 | REG findInjectReg (UINT32 index) { 88 | RegInfoMap::iterator reg_iter; 89 | reg_iter = reg_map.find(index); 90 | if ( reg_iter == reg_map.end()) { 91 | fprintf(stderr, "Register index %u not in the list!\n", index); 92 | exit(2); 93 | } 94 | return reg_iter -> second -> inject_reg; 95 | } 96 | 97 | UINT32 findLowBoundBit (UINT32 index) { 98 | RegInfoMap::iterator reg_iter; 99 | reg_iter = reg_map.find(index); 100 | if ( reg_iter == reg_map.end()) { 101 | fprintf(stderr, "Register index %u not in the list!\n", index); 102 | exit(2); 103 | } 104 | return reg_iter -> second -> low_bit; 105 | 106 | } 107 | 108 | UINT32 findHighBoundBit (UINT32 index) { 109 | RegInfoMap::iterator reg_iter; 110 | reg_iter = reg_map.find(index); 111 | if ( reg_iter == reg_map.end()) { 112 | fprintf(stderr, "Register index %u not in the list!\n", index); 113 | exit(2); 114 | } 115 | return reg_iter -> second -> high_bit; 116 | 117 | } 118 | 119 | bool isFloatReg (UINT32 index) { 120 | RegInfoMap::iterator reg_iter; 121 | reg_iter = reg_map.find(index); 122 | if ( reg_iter == reg_map.end()) { 123 | fprintf(stderr, "Register index %u not in the list!\n", index); 124 | exit(2); 125 | } 126 | return reg_iter -> second -> fp_flag; 127 | 128 | } 129 | 130 | 131 | private: 132 | void createMap() { 133 | reg_map[0] = new Reg_Info(REG_EDI, REG_RDI, 0, 32, false); 134 | reg_map[1] = new Reg_Info(REG_ESI, REG_RSI, 0, 32, false); 135 | reg_map[2] = new Reg_Info(REG_EBP, REG_RBP, 0, 32, false); 136 | reg_map[3] = new Reg_Info(REG_ESP, REG_RSP, 0, 32, false); 137 | reg_map[4] = new Reg_Info(REG_EBX, REG_RBX, 0, 32, false); 138 | reg_map[5] = new Reg_Info(REG_EDX, REG_RDX, 0, 32, false); 139 | reg_map[6] = new Reg_Info(REG_ECX, REG_RCX, 0, 32, false); 140 | reg_map[7] = new Reg_Info(REG_EAX, REG_RAX, 0, 32, false); 141 | 142 | reg_map[8] = new Reg_Info(REG_SEG_CS, REG_SEG_CS, 0, 32, false); 143 | reg_map[9] = new Reg_Info(REG_SEG_SS, REG_SEG_SS, 0, 32, false); 144 | reg_map[10] = new Reg_Info(REG_SEG_DS, REG_SEG_DS, 0, 32, false); 145 | reg_map[11] = new Reg_Info(REG_SEG_ES, REG_SEG_ES, 0, 32, false); 146 | reg_map[12] = new Reg_Info(REG_SEG_FS, REG_SEG_FS, 0, 32, false); 147 | reg_map[13] = new Reg_Info(REG_SEG_GS, REG_SEG_GS, 0, 32, false); 148 | 149 | reg_map[14] = new Reg_Info(REG_EFLAGS, REG_RFLAGS, 0, 32, false); 150 | reg_map[15] = new Reg_Info(REG_EIP, REG_RIP, 0, 32, false); 151 | 152 | reg_map[16] = new Reg_Info(REG_BX, REG_RBX, 0, 16, false); 153 | reg_map[17] = new Reg_Info(REG_DX, REG_RDX, 0, 16, false); 154 | reg_map[18] = new Reg_Info(REG_CX, REG_RCX, 0, 16, false); 155 | reg_map[19] = new Reg_Info(REG_AX, REG_RAX, 0, 16, false); 156 | reg_map[20] = new Reg_Info(REG_BL, REG_RBX, 0, 8, false); 157 | reg_map[21] = new Reg_Info(REG_DL, REG_RDX, 0, 8, false); 158 | reg_map[22] = new Reg_Info(REG_CL, REG_RCX, 0, 8, false); 159 | reg_map[23] = new Reg_Info(REG_AL, REG_RAX, 0, 8, false); 160 | reg_map[24] = new Reg_Info(REG_BH, REG_RBX, 8, 16, false); 161 | reg_map[25] = new Reg_Info(REG_DH, REG_RDX, 8, 16, false); 162 | reg_map[26] = new Reg_Info(REG_CH, REG_RCX, 8, 16, false); 163 | reg_map[27] = new Reg_Info(REG_AH, REG_RAX, 8, 16, false); 164 | 165 | reg_map[28] = new Reg_Info(REG_DI, REG_RDI, 0, 16, false); 166 | reg_map[29] = new Reg_Info(REG_SI, REG_RSI, 0, 16, false); 167 | reg_map[30] = new Reg_Info(REG_BP, REG_RBP, 0, 16, false); 168 | reg_map[31] = new Reg_Info(REG_SP, REG_RSP, 0, 16, false); 169 | 170 | reg_map[32] = new Reg_Info(REG_FLAGS, REG_RFLAGS, 0, 16, false); 171 | reg_map[33] = new Reg_Info(REG_IP, REG_RIP, 0, 16, false); 172 | 173 | reg_map[34] = new Reg_Info(REG_MM0, REG_MM0, 0, 64, true); 174 | reg_map[35] = new Reg_Info(REG_MM1, REG_MM1, 0, 64, true); 175 | reg_map[36] = new Reg_Info(REG_MM2, REG_MM2, 0, 64, true); 176 | reg_map[37] = new Reg_Info(REG_MM3, REG_MM3, 0, 64, true); 177 | reg_map[38] = new Reg_Info(REG_MM4, REG_MM4, 0, 64, true); 178 | reg_map[39] = new Reg_Info(REG_MM5, REG_MM5, 0, 64, true); 179 | reg_map[40] = new Reg_Info(REG_MM6, REG_MM6, 0, 64, true); 180 | reg_map[41] = new Reg_Info(REG_MM7, REG_MM7, 0, 64, true); 181 | 182 | reg_map[42] = new Reg_Info(REG_ST0, REG_ST0, 0, 80, true); 183 | reg_map[43] = new Reg_Info(REG_ST1, REG_ST1, 0, 80, true); 184 | reg_map[44] = new Reg_Info(REG_ST2, REG_ST2, 0, 80, true); 185 | reg_map[45] = new Reg_Info(REG_ST3, REG_ST3, 0, 80, true); 186 | reg_map[46] = new Reg_Info(REG_ST4, REG_ST4, 0, 80, true); 187 | reg_map[47] = new Reg_Info(REG_ST5, REG_ST5, 0, 80, true); 188 | reg_map[48] = new Reg_Info(REG_ST6, REG_ST6, 0, 80, true); 189 | reg_map[49] = new Reg_Info(REG_ST7, REG_ST7, 0, 80, true); 190 | 191 | reg_map[50] = new Reg_Info(REG_XMM0, REG_XMM0, 0, 128, true); 192 | reg_map[51] = new Reg_Info(REG_XMM1, REG_XMM1, 0, 128, true); 193 | reg_map[52] = new Reg_Info(REG_XMM2, REG_XMM2, 0, 128, true); 194 | reg_map[53] = new Reg_Info(REG_XMM3, REG_XMM3, 0, 128, true); 195 | reg_map[54] = new Reg_Info(REG_XMM4, REG_XMM4, 0, 128, true); 196 | reg_map[55] = new Reg_Info(REG_XMM5, REG_XMM5, 0, 128, true); 197 | reg_map[56] = new Reg_Info(REG_XMM6, REG_XMM6, 0, 128, true); 198 | reg_map[57] = new Reg_Info(REG_XMM7, REG_XMM7, 0, 128, true); 199 | 200 | reg_map[58] = new Reg_Info(REG_X87, REG_X87, 0, 80, true); 201 | 202 | reg_map[59] = new Reg_Info(REG_YMM0, REG_YMM0, 0, 128, true); 203 | reg_map[60] = new Reg_Info(REG_YMM1, REG_YMM1, 0, 128, true); 204 | reg_map[61] = new Reg_Info(REG_YMM2, REG_YMM2, 0, 128, true); 205 | reg_map[62] = new Reg_Info(REG_YMM3, REG_YMM3, 0, 128, true); 206 | reg_map[63] = new Reg_Info(REG_YMM4, REG_YMM4, 0, 128, true); 207 | reg_map[64] = new Reg_Info(REG_YMM5, REG_YMM5, 0, 128, true); 208 | reg_map[65] = new Reg_Info(REG_YMM6, REG_YMM6, 0, 128, true); 209 | reg_map[66] = new Reg_Info(REG_YMM7, REG_YMM7, 0, 128, true); 210 | 211 | //the R regs for 64 bit 212 | reg_map[67] = new Reg_Info(REG_RDI, REG_RDI, 0, 64, false); 213 | reg_map[68] = new Reg_Info(REG_RSI, REG_RSI, 0, 64, false); 214 | reg_map[69] = new Reg_Info(REG_RBP, REG_RBP, 0, 64, false); 215 | reg_map[70] = new Reg_Info(REG_RSP, REG_RSP, 0, 64, false); 216 | reg_map[71] = new Reg_Info(REG_RBX, REG_RBX, 0, 64, false); 217 | reg_map[72] = new Reg_Info(REG_RDX, REG_RDX, 0, 64, false); 218 | reg_map[73] = new Reg_Info(REG_RCX, REG_RCX, 0, 64, false); 219 | reg_map[74] = new Reg_Info(REG_RAX, REG_RAX, 0, 64, false); 220 | 221 | reg_map[75] = new Reg_Info(REG_RIP, REG_RIP, 0, 64, false); 222 | 223 | //the R8-R16 regs 224 | reg_map[76] = new Reg_Info(REG_R8, REG_R8, 0, 64, false); 225 | reg_map[77] = new Reg_Info(REG_R9, REG_R9, 0, 64, false); 226 | reg_map[78] = new Reg_Info(REG_R10, REG_R10, 0, 64, false); 227 | reg_map[79] = new Reg_Info(REG_R11, REG_R11, 0, 64, false); 228 | reg_map[80] = new Reg_Info(REG_R12, REG_R12, 0, 64, false); 229 | reg_map[81] = new Reg_Info(REG_R13, REG_R13, 0, 64, false); 230 | reg_map[82] = new Reg_Info(REG_R14, REG_R14, 0, 64, false); 231 | reg_map[83] = new Reg_Info(REG_R15, REG_R15, 0, 64, false); 232 | //reg_map[84] = new Reg_Info(REG_R16, REG_R16, 0, 64, false); 233 | 234 | reg_map[85] = new Reg_Info(REG_R8D, REG_R8, 0, 32, false); 235 | reg_map[86] = new Reg_Info(REG_R9D, REG_R9, 0, 32, false); 236 | reg_map[87] = new Reg_Info(REG_R10D, REG_R10, 0, 32, false); 237 | reg_map[88] = new Reg_Info(REG_R11D, REG_R11, 0, 32, false); 238 | reg_map[89] = new Reg_Info(REG_R12D, REG_R12, 0, 32, false); 239 | reg_map[90] = new Reg_Info(REG_R13D, REG_R13, 0, 32, false); 240 | reg_map[91] = new Reg_Info(REG_R14D, REG_R14, 0, 32, false); 241 | reg_map[92] = new Reg_Info(REG_R15D, REG_R15, 0, 32, false); 242 | //reg_map[93] = new Reg_Info(REG_R16D, REG_R16, 0, 32, false); 243 | 244 | reg_map[94] = new Reg_Info(REG_R8W, REG_R8, 0, 16, false); 245 | reg_map[95] = new Reg_Info(REG_R9W, REG_R9, 0, 16, false); 246 | reg_map[96] = new Reg_Info(REG_R10W, REG_R10, 0, 16, false); 247 | reg_map[97] = new Reg_Info(REG_R11W, REG_R11, 0, 16, false); 248 | reg_map[98] = new Reg_Info(REG_R12W, REG_R12, 0, 16, false); 249 | reg_map[99] = new Reg_Info(REG_R13W, REG_R13, 0, 16, false); 250 | reg_map[100] = new Reg_Info(REG_R14W, REG_R14, 0, 16, false); 251 | reg_map[101] = new Reg_Info(REG_R15W, REG_R15, 0, 16, false); 252 | //reg_map[102] = new Reg_Info(REG_R16W, REG_R16, 0, 16, false); 253 | 254 | reg_map[103] = new Reg_Info(REG_R8B, REG_R8, 0, 8, false); 255 | reg_map[104] = new Reg_Info(REG_R9B, REG_R9, 0, 8, false); 256 | reg_map[105] = new Reg_Info(REG_R10B, REG_R10, 0, 8, false); 257 | reg_map[106] = new Reg_Info(REG_R11B, REG_R11, 0, 8, false); 258 | reg_map[107] = new Reg_Info(REG_R12B, REG_R12, 0, 8, false); 259 | reg_map[108] = new Reg_Info(REG_R13B, REG_R13, 0, 8, false); 260 | reg_map[109] = new Reg_Info(REG_R14B, REG_R14, 0, 8, false); 261 | reg_map[110] = new Reg_Info(REG_R15B, REG_R15, 0, 8, false); 262 | //reg_map[111] = new Reg_Info(REG_R16B, REG_R16, 0, 8, false); 263 | 264 | reg_map[111] = new Reg_Info(REG_RFLAGS, REG_RFLAGS, 0, 64, false); 265 | 266 | //low 8 bits 267 | reg_map[112] = new Reg_Info(REG_SIL, REG_RSI, 0, 8, false); 268 | reg_map[113] = new Reg_Info(REG_DIL, REG_RDI, 0, 8, false); 269 | reg_map[114] = new Reg_Info(REG_BPL, REG_RBP, 0, 8, false); 270 | reg_map[115] = new Reg_Info(REG_SPL, REG_RSP, 0, 8, false); 271 | 272 | //additional xmm8-15 273 | reg_map[116] = new Reg_Info(REG_XMM8, REG_XMM8, 0, 128, true); 274 | reg_map[117] = new Reg_Info(REG_XMM9, REG_XMM9, 0, 128, true); 275 | reg_map[118] = new Reg_Info(REG_XMM10, REG_XMM10, 0, 128, true); 276 | reg_map[119] = new Reg_Info(REG_XMM11, REG_XMM11, 0, 128, true); 277 | reg_map[120] = new Reg_Info(REG_XMM12, REG_XMM12, 0, 128, true); 278 | reg_map[121] = new Reg_Info(REG_XMM13, REG_XMM13, 0, 128, true); 279 | reg_map[122] = new Reg_Info(REG_XMM14, REG_XMM14, 0, 128, true); 280 | reg_map[123] = new Reg_Info(REG_XMM15, REG_XMM15, 0, 128, true); 281 | 282 | //additional ymm8-15 283 | reg_map[124] = new Reg_Info(REG_YMM8, REG_YMM8, 0, 128, true); 284 | reg_map[125] = new Reg_Info(REG_YMM9, REG_YMM9, 0, 128, true); 285 | reg_map[126] = new Reg_Info(REG_YMM10, REG_YMM10, 0, 128, true); 286 | reg_map[127] = new Reg_Info(REG_YMM11, REG_YMM11, 0, 128, true); 287 | reg_map[128] = new Reg_Info(REG_YMM12, REG_YMM12, 0, 128, true); 288 | reg_map[129] = new Reg_Info(REG_YMM13, REG_YMM13, 0, 128, true); 289 | reg_map[130] = new Reg_Info(REG_YMM14, REG_YMM14, 0, 128, true); 290 | reg_map[131] = new Reg_Info(REG_YMM15, REG_YMM15, 0, 128, true); 291 | } 292 | 293 | }; 294 | 295 | RegMap reg_map; 296 | 297 | // FI: set the X87 ST[0-7] or MM[0-7] context register 298 | VOID FI_SetSTContextReg (CONTEXT* ctxt, REG reg, UINT32 reg_num) 299 | { 300 | //INPUT: x87 or st0-7 or MM[0-7] 301 | //choose st[i] to inject 302 | UINT32 i = 0; 303 | if(reg == REG_X87) { 304 | srand((unsigned)time(0)); 305 | i = rand() % MAX_ST_NUM; 306 | } 307 | else { 308 | string reg_name = REG_StringShort(reg); 309 | i = reg_name[reg_name.size() - 1] - '0'; 310 | } 311 | 312 | CHAR fpContextSpace[FPSTATE_SIZE]; 313 | FPSTATE *fpContext = reinterpret_cast(fpContextSpace); 314 | 315 | PIN_GetContextFPState(ctxt, fpContext); 316 | 317 | 318 | UINT32 low_bound_bit = reg_map.findLowBoundBit(reg_num); 319 | UINT32 high_bound_bit = reg_map.findHighBoundBit(reg_num); 320 | 321 | UINT32 inject_bit = (rand() % (high_bound_bit - low_bound_bit)) + low_bound_bit; 322 | 323 | if(inject_bit < 64) { 324 | PRINT_MESSAGE(3, ("EXECUTING: Reg name %s Low value %p\n", REG_StringShort(reg).c_str(), 325 | (VOID*)fpContext->fxsave_legacy._sts[i]._raw._lo)); 326 | 327 | fpContext->fxsave_legacy._sts[i]._raw._lo ^= (1UL << inject_bit); 328 | 329 | PRINT_MESSAGE(3, ("EXECUTING: Changed Reg name %s Low value %p\n", REG_StringShort(reg).c_str(), 330 | (VOID*)fpContext->fxsave_legacy._sts[i]._raw._lo)); 331 | 332 | } 333 | else { 334 | PRINT_MESSAGE(3, ("EXECUTING: Reg name %s High value %p\n", REG_StringShort(reg).c_str(), 335 | (VOID*)fpContext->fxsave_legacy._sts[i]._raw._hi)); 336 | 337 | fpContext->fxsave_legacy._sts[i]._raw._hi ^= (1UL << (inject_bit - 64)); 338 | 339 | PRINT_MESSAGE(3, ("EXECUTING: Changed Reg name %s High value %p\n", REG_StringShort(reg).c_str(), 340 | (VOID*)fpContext->fxsave_legacy._sts[i]._raw._hi)); 341 | 342 | } 343 | 344 | PIN_SetContextFPState(ctxt, fpContext); 345 | } 346 | 347 | // FI: set the XMM[0-7] context register 348 | VOID FI_SetXMMContextReg (CONTEXT* ctxt, REG reg, UINT32 reg_num) 349 | { 350 | //choose XMM[i] to inject 351 | string reg_name = REG_StringShort(reg); 352 | UINT32 i = reg_name[reg_name.size() - 1] - '0'; 353 | 354 | CHAR fpContextSpace[FPSTATE_SIZE]; 355 | FPSTATE *fpContext = reinterpret_cast(fpContextSpace); 356 | 357 | PIN_GetContextFPState(ctxt, fpContext); 358 | 359 | 360 | UINT32 low_bound_bit = reg_map.findLowBoundBit(reg_num); 361 | UINT32 high_bound_bit = reg_map.findHighBoundBit(reg_num); 362 | 363 | UINT32 inject_bit = (rand() % (high_bound_bit - low_bound_bit)) + low_bound_bit; 364 | 365 | // JIESHENG: this is not a right change from the hardware perspective, but it 366 | // is to improve the activated faults. 367 | // xmm is used for double, so only the lower 64 bits are used 368 | if (inject_bit >= 64) 369 | inject_bit -= 64; 370 | 371 | // JIESHNEG: something wrong, just to test whether the xmm injection is correct or not 372 | // 373 | srand(time(NULL)); 374 | inject_bit = (rand() % 64); 375 | std::cerr << "Inject into bit " << inject_bit << std::endl; 376 | 377 | if(inject_bit < 64) { 378 | PRINT_MESSAGE(3, ("EXECUTING: Reg name %s Low value %p\n", REG_StringShort(reg).c_str(), 379 | (VOID*)fpContext->fxsave_legacy._xmms[i]._vec64[0])); 380 | 381 | fpContext->fxsave_legacy._xmms[i]._vec64[0] ^= (1UL << inject_bit); 382 | 383 | PRINT_MESSAGE(3, ("EXECUTING: Changed Reg name %s Low value %p\n", REG_StringShort(reg).c_str(), 384 | (VOID*)fpContext->fxsave_legacy._xmms[i]._vec64[0])); 385 | 386 | } 387 | else { 388 | PRINT_MESSAGE(3, ("EXECUTING: Reg name %s High value %p\n", REG_StringShort(reg).c_str(), 389 | (VOID*)fpContext->fxsave_legacy._xmms[i]._vec64[1])); 390 | 391 | fpContext->fxsave_legacy._xmms[i]._vec64[1] ^= (1UL << (inject_bit - 64)); 392 | 393 | PRINT_MESSAGE(3, ("EXECUTING: Changed Reg name %s High value %p\n", REG_StringShort(reg).c_str(), 394 | (VOID*)fpContext->fxsave_legacy._xmms[i]._vec64[1])); 395 | 396 | } 397 | 398 | PIN_SetContextFPState(ctxt, fpContext); 399 | } 400 | 401 | // FI: set the YMM[0-7] context register 402 | VOID FI_SetYMMContextReg (CONTEXT* ctxt, REG reg, UINT32 reg_num) 403 | { 404 | //choose YMM[i] to inject 405 | string reg_name = REG_StringShort(reg); 406 | UINT32 i = reg_name[reg_name.size() - 1] - '0'; 407 | 408 | CHAR fpContextSpace[FPSTATE_SIZE]; 409 | FPSTATE *fpContext = reinterpret_cast(fpContextSpace); 410 | 411 | PIN_GetContextFPState(ctxt, fpContext); 412 | 413 | 414 | UINT32 low_bound_bit = reg_map.findLowBoundBit(reg_num); 415 | UINT32 high_bound_bit = reg_map.findHighBoundBit(reg_num); 416 | 417 | UINT32 inject_bit = (rand() % (high_bound_bit - low_bound_bit)) + low_bound_bit; 418 | 419 | //FIXME: change number below to parameter 420 | UINT32 index = (i * 128 + inject_bit) / (sizeof(UINT8) * 8); 421 | UINT32 bit = (i * 128 + inject_bit) % (sizeof(UINT8) * 8); 422 | 423 | PRINT_MESSAGE(3, ("EXECUTING: Reg name %s Low value %u\n", REG_StringShort(reg).c_str(), 424 | fpContext->_xstate._ymmUpper[index])); 425 | 426 | fpContext->_xstate._ymmUpper[index] ^= (1UL << bit); 427 | 428 | PRINT_MESSAGE(3, ("EXECUTING: Changed Reg name %s Low value %u\n", REG_StringShort(reg).c_str(), 429 | fpContext->_xstate._ymmUpper[index])); 430 | 431 | PIN_SetContextFPState(ctxt, fpContext); 432 | } 433 | 434 | VOID FI_PrintActivationInfo() 435 | { 436 | if(fi_activation_file.Value() != "") { 437 | FILE* fi_act_FILE = fopen(fi_activation_file.Value().c_str(), "w"); 438 | 439 | if(fi_act_FILE != NULL) { 440 | fprintf(fi_act_FILE, "activated"); 441 | fclose(fi_act_FILE); 442 | } 443 | } 444 | 445 | } 446 | 447 | bool is_stackptrReg(REG reg){ 448 | if(reg == REG_RSP || reg == REG_ESP || reg == REG_SP) 449 | return true; 450 | return false; 451 | } 452 | 453 | bool is_frameptrReg(REG reg){ 454 | if(reg == REG_RBP || reg == REG_EBP || reg == REG_BP) 455 | return true; 456 | return false; 457 | } 458 | #endif 459 | -------------------------------------------------------------------------------- /fi_cjmp_map.h: -------------------------------------------------------------------------------- 1 | #ifndef FI_CJMP_MAP_H 2 | #define FI_CJMP_MAP_H 3 | 4 | #include 5 | #include 6 | #include "pin.H" 7 | #include "stdio.h" 8 | 9 | #define MAX_ST_NUM 8 10 | 11 | #define CF_BIT 0 12 | #define PF_BIT 2 13 | #define ZF_BIT 6 14 | #define SF_BIT 7 15 | #define OF_BIT 11 16 | #define NA_BIT 100 17 | 18 | using namespace std; 19 | 20 | class CJmpMap{ 21 | public: 22 | enum JmpType {DEFAULT = 0, USPECJMP = 1, SSPECJMP = 2}; 23 | 24 | struct Jmp_Info { 25 | string name; 26 | enum JmpType type; //types other than DEFAULT needs special operations 27 | UINT32 inject_bit; 28 | 29 | Jmp_Info (string p_name, JmpType p_type, UINT32 p_inject) { 30 | name = p_name; 31 | type = p_type; 32 | inject_bit = p_inject; 33 | } 34 | }; 35 | typedef map JmpInfoMap; 36 | public: 37 | 38 | CJmpMap(){ 39 | createMap(); 40 | } 41 | 42 | UINT32 findJmpIndex(string jmp) { 43 | JmpInfoMap::iterator jmp_iter; 44 | for(jmp_iter = jmp_map.begin() ; jmp_iter !=jmp_map.end() ; jmp_iter++ ) { 45 | if(jmp_iter -> second -> name == jmp) 46 | return jmp_iter -> first; 47 | } 48 | fprintf(stderr, "ERROR: Jump %s not in the list!\n", jmp.c_str()); 49 | exit(2); 50 | } 51 | 52 | JmpType findJmpType(UINT32 index) { 53 | JmpInfoMap::iterator jmp_iter; 54 | jmp_iter = jmp_map.find(index); 55 | if ( jmp_iter == jmp_map.end()) { 56 | fprintf(stderr, "ERROR: Jump index %u not in the list!\n", index); 57 | exit(2); 58 | } 59 | return jmp_iter -> second -> type; 60 | 61 | } 62 | 63 | string& findJmpName(UINT32 index) { 64 | JmpInfoMap::iterator jmp_iter; 65 | jmp_iter = jmp_map.find(index); 66 | if ( jmp_iter == jmp_map.end()) { 67 | fprintf(stderr, "ERROR: Jump index %u not in the list!\n", index); 68 | exit(2); 69 | } 70 | return jmp_iter -> second -> name; 71 | } 72 | 73 | UINT32 findInjectBit (UINT32 index) { 74 | JmpInfoMap::iterator jmp_iter; 75 | jmp_iter = jmp_map.find(index); 76 | if ( jmp_iter == jmp_map.end()) { 77 | fprintf(stderr, "ERROR: Jump index %u not in the list!\n", index); 78 | exit(2); 79 | } 80 | 81 | assert(jmp_iter->second->type == DEFAULT); 82 | return jmp_iter -> second -> inject_bit; 83 | } 84 | 85 | bool isParityJmp (string jmpname) { 86 | return (jmpname == "JP") || (jmpname == "JPE") || 87 | (jmpname == "JNP") || (jmpname == "JPO"); 88 | } 89 | 90 | private: 91 | void createMap() { 92 | jmp_map[0] = new Jmp_Info("JO", DEFAULT, OF_BIT); 93 | jmp_map[1] = new Jmp_Info("JNO", DEFAULT, OF_BIT); 94 | 95 | jmp_map[2] = new Jmp_Info("JS", DEFAULT, SF_BIT); 96 | jmp_map[3] = new Jmp_Info("JNS", DEFAULT, SF_BIT); 97 | 98 | jmp_map[4] = new Jmp_Info("JZ", DEFAULT, ZF_BIT); 99 | jmp_map[5] = new Jmp_Info("JE", DEFAULT, ZF_BIT); 100 | jmp_map[6] = new Jmp_Info("JNZ", DEFAULT, ZF_BIT); 101 | jmp_map[7] = new Jmp_Info("JNE", DEFAULT, ZF_BIT); 102 | 103 | jmp_map[8] = new Jmp_Info("JB", DEFAULT, CF_BIT); 104 | jmp_map[9] = new Jmp_Info("JNAE", DEFAULT, CF_BIT); 105 | jmp_map[10] = new Jmp_Info("JC", DEFAULT, CF_BIT); 106 | jmp_map[11] = new Jmp_Info("JNB", DEFAULT, CF_BIT); 107 | jmp_map[12] = new Jmp_Info("JAE", DEFAULT, CF_BIT); 108 | jmp_map[13] = new Jmp_Info("JNC", DEFAULT, CF_BIT); 109 | 110 | jmp_map[14] = new Jmp_Info("JBE", USPECJMP, NA_BIT); 111 | jmp_map[15] = new Jmp_Info("JNA", USPECJMP, NA_BIT); 112 | jmp_map[16] = new Jmp_Info("JA", USPECJMP, NA_BIT); 113 | jmp_map[17] = new Jmp_Info("JNBE", USPECJMP, NA_BIT); 114 | 115 | jmp_map[18] = new Jmp_Info("JL", DEFAULT, SF_BIT); 116 | jmp_map[19] = new Jmp_Info("JNGE", DEFAULT, SF_BIT); 117 | jmp_map[20] = new Jmp_Info("JGE", DEFAULT, SF_BIT); 118 | jmp_map[21] = new Jmp_Info("JNL", DEFAULT, SF_BIT); 119 | 120 | jmp_map[22] = new Jmp_Info("JLE", SSPECJMP, NA_BIT); 121 | jmp_map[23] = new Jmp_Info("JNG", SSPECJMP, NA_BIT); 122 | jmp_map[24] = new Jmp_Info("JG", SSPECJMP, NA_BIT); 123 | jmp_map[25] = new Jmp_Info("JNLE", SSPECJMP, NA_BIT); 124 | 125 | jmp_map[26] = new Jmp_Info("JP", DEFAULT, PF_BIT); 126 | jmp_map[27] = new Jmp_Info("JPE", DEFAULT, PF_BIT); 127 | jmp_map[28] = new Jmp_Info("JNP", DEFAULT, PF_BIT); 128 | jmp_map[29] = new Jmp_Info("JPO", DEFAULT, PF_BIT); 129 | 130 | //DO NOT INCLUDE THE TWO BELOW FOR NOW 131 | //jmp_map[30] = new Jmp_Info("JCXZ", DEFAULT, NA_BIT); 132 | //jmp_map[31] = new Jmp_Info("JECXZ", DEFAULT, NA_BIT); 133 | } 134 | 135 | 136 | private: 137 | 138 | JmpInfoMap jmp_map; 139 | }; 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /instcategory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "pin.H" 9 | #include "utils.h" 10 | 11 | //#define INCLUDEALLINST 12 | #define NOBRANCHES 13 | //#define NOSTACKFRAMEOP 14 | //#define ONLYFP 15 | 16 | KNOB instcategory_file(KNOB_MODE_WRITEONCE, "pintool", 17 | "o", "pin.instcategory.txt", "output file to store instruction categories"); 18 | 19 | static std::map* > category_opcode_map; 20 | 21 | // Pin calls this function every time a new instruction is encountered 22 | VOID CountInst(INS ins, VOID *v) 23 | { 24 | if (!isValidInst(ins)) 25 | return; 26 | 27 | //INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)countAllInst, IARG_END); 28 | #ifdef INCLUDEALLINST 29 | #else 30 | 31 | #ifdef NOBRANCHES 32 | if(INS_IsBranch(ins) || !INS_HasFallThrough(ins)) { 33 | LOG("instcount: branch/ret inst: " + INS_Disassemble(ins) + "\n"); 34 | return; 35 | } 36 | #endif 37 | 38 | // NOSTACKFRAMEOP must be used together with NOBRANCHES, IsStackWrite 39 | // has a bug that does not put pop into the list 40 | #ifdef NOSTACKFRAMEOP 41 | if(INS_IsStackWrite(ins) || OPCODE_StringShort(INS_Opcode(ins)) == "POP") { 42 | LOG("instcount: stack frame change inst: " + INS_Disassemble(ins) + "\n"); 43 | return; 44 | } 45 | #endif 46 | 47 | #ifdef ONLYFP 48 | int numW = INS_MaxNumWRegs(ins); 49 | bool hasfp = false; 50 | for (int i = 0; i < numW; i++) { 51 | if (reg_map.isFloatReg(reg)) { 52 | hasfp = true; 53 | break; 54 | } 55 | } 56 | if (!hasfp){ 57 | return; 58 | } 59 | #endif 60 | 61 | #endif 62 | 63 | string cate = CATEGORY_StringShort(INS_Category(ins)); 64 | if (category_opcode_map.find(cate) == category_opcode_map.end()) { 65 | category_opcode_map.insert(std::pair* >(cate, new std::set)); 66 | } 67 | category_opcode_map[cate]->insert(INS_Mnemonic(ins)); 68 | } 69 | 70 | // This function is called when the application exits 71 | VOID Fini(INT32 code, VOID *v) 72 | { 73 | // Write to a file since cout and cerr maybe closed by the application 74 | ofstream OutFile; 75 | OutFile.open(instcategory_file.Value().c_str()); 76 | OutFile.setf(ios::showbase); 77 | 78 | for (std::map* >::iterator it = category_opcode_map.begin(); 79 | it != category_opcode_map.end(); ++it) { 80 | OutFile << it->first << std::endl; 81 | for (std::set::iterator it2 = it->second->begin(); 82 | it2 != it->second->end(); ++it2) { 83 | OutFile << "\t" << *it2 << endl; 84 | } 85 | } 86 | 87 | OutFile.close(); 88 | } 89 | 90 | /* ===================================================================== */ 91 | /* Print Help Message */ 92 | /* ===================================================================== */ 93 | 94 | INT32 Usage() { 95 | cerr << "This tool collects the instruction categories/opcode in the program" << endl; 96 | cerr << endl << KNOB_BASE::StringKnobSummary() << endl; 97 | return -1; 98 | } 99 | 100 | 101 | int main(int argc, char * argv[]) 102 | { 103 | PIN_InitSymbols(); 104 | // Initialize pin 105 | if (PIN_Init(argc, argv)) return Usage(); 106 | 107 | // Register Instruction to be called to instrument instructions 108 | INS_AddInstrumentFunction(CountInst, 0); 109 | 110 | // Register Fini to be called when the application exits 111 | PIN_AddFiniFunction(Fini, 0); 112 | 113 | // Start the program, never returns 114 | PIN_StartProgram(); 115 | 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /instcount.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "pin.H" 9 | #include "utils.h" 10 | #include "instselector.h" 11 | 12 | //#include "faultinjection.h" 13 | //#include "commonvars.h" 14 | 15 | //#define INCLUDEALLINST 16 | #define NOBRANCHES 17 | //#define NOSTACKFRAMEOP 18 | //#define ONLYFP 19 | 20 | KNOB instcount_file(KNOB_MODE_WRITEONCE, "pintool", 21 | "o", "pin.instcount.txt", "specify instruction count file name"); 22 | 23 | static UINT64 fi_all = 0; 24 | static UINT64 fi_ccs = 0; 25 | static UINT64 fi_sp = 0; 26 | static UINT64 fi_bp = 0; 27 | 28 | VOID countAllInst() {fi_all++;} 29 | VOID countCCSInst() {fi_ccs++;} 30 | VOID countSPInst() {fi_sp++;} 31 | VOID countBPInst() { fi_bp++;} 32 | 33 | 34 | // Pin calls this function every time a new instruction is encountered 35 | VOID CountInst(INS ins, VOID *v) 36 | { 37 | if (!isValidInst(ins)) 38 | return; 39 | 40 | #ifdef INCLUDEALLINST 41 | int numW = INS_MaxNumWRegs(ins), mayChangeControlFlow = 0; 42 | if(!INS_HasFallThrough(ins)) 43 | mayChangeControlFlow = 1; 44 | for(int i =0; i < numW; i++){ 45 | reg = INS_RegW(ins, i); 46 | if(reg == REG_RIP || reg == REG_EIP || reg == REG_IP) // conditional branches 47 | { mayChangeControlFlow = 1; break;} 48 | } 49 | 50 | if(mayChangeControlFlow) { 51 | INS_InsertPredicatedCall( 52 | ins, IPOINT_BEFORE, (AFUNPTR)countAllInst, 53 | IARG_END); 54 | //LOG("No through\n"); 55 | } 56 | else{ 57 | INS_InsertPredicatedCall( 58 | ins, IPOINT_AFTER, (AFUNPTR)countAllInst, 59 | IARG_END); 60 | // LOG("ins SP:" + INS_Disassemble(ins) + "\n"); 61 | // LOG("reg:" + REG_StringShort(reg) +"\n"); 62 | //LOG(numW+"\n"); 63 | } 64 | #else 65 | 66 | #ifdef NOBRANCHES 67 | if(INS_IsBranch(ins) || !INS_HasFallThrough(ins)) { 68 | LOG("instcount: branch/ret inst: " + INS_Disassemble(ins) + "\n"); 69 | return; 70 | } 71 | #endif 72 | 73 | // NOSTACKFRAMEOP must be used together with NOBRANCHES, IsStackWrite 74 | // has a bug that does not put pop into the list 75 | #ifdef NOSTACKFRAMEOP 76 | if(INS_IsStackWrite(ins) || OPCODE_StringShort(INS_Opcode(ins)) == "POP") { 77 | LOG("instcount: stack frame change inst: " + INS_Disassemble(ins) + "\n"); 78 | return; 79 | } 80 | #endif 81 | 82 | #ifdef ONLYFP 83 | int numW = INS_MaxNumWRegs(ins); 84 | bool hasfp = false; 85 | for (int i = 0; i < numW; i++){ 86 | if (reg_map.isFloatReg(reg)) { 87 | hasfp = true; 88 | break; 89 | } 90 | } 91 | if (!hasfp){ 92 | return; 93 | } 94 | #endif 95 | 96 | 97 | // select instruction based on instruction type 98 | if(!isInstFITarget(ins)) 99 | return; 100 | 101 | 102 | INS_InsertPredicatedCall( 103 | ins, IPOINT_AFTER, (AFUNPTR)countAllInst, 104 | IARG_END); 105 | #endif 106 | 107 | 108 | } 109 | 110 | // bool mayChangeControlFlow(INS ins){ 111 | // REG reg; 112 | // if(!INS_HasFallThrough(ins)) 113 | // return true; 114 | // int numW = INS_MaxNumWRegs(ins); 115 | // for(int i =0; i < numW; i++){ 116 | // if(reg == REG_RIP || reg == REG_EIP || reg == REG_IP) // conditional branches 117 | // return true; 118 | // } 119 | // return false; 120 | // } 121 | // This function is called when the application exits 122 | VOID Fini(INT32 code, VOID *v) 123 | { 124 | // Write to a file since cout and cerr maybe closed by the application 125 | ofstream OutFile; 126 | OutFile.open(instcount_file.Value().c_str()); 127 | OutFile.setf(ios::showbase); 128 | OutFile <<"AllInst:"<< fi_all << endl; 129 | OutFile <<"CCSavedInst:"<< fi_ccs << endl; 130 | OutFile << "SPInst:"<< fi_sp << endl; 131 | OutFile << "FPInst:"<< fi_bp << endl; 132 | 133 | OutFile.close(); 134 | } 135 | 136 | /* ===================================================================== */ 137 | /* Print Help Message */ 138 | /* ===================================================================== */ 139 | 140 | INT32 Usage() 141 | { 142 | cerr << "This tool counts the number of dynamic instructions executed" << endl; 143 | cerr << endl << KNOB_BASE::StringKnobSummary() << endl; 144 | return -1; 145 | } 146 | 147 | 148 | 149 | int main(int argc, char * argv[]) 150 | { 151 | PIN_InitSymbols(); 152 | // Initialize pin 153 | if (PIN_Init(argc, argv)) return Usage(); 154 | 155 | 156 | 157 | configInstSelector(); 158 | 159 | 160 | 161 | // Register Instruction to be called to instrument instructions 162 | INS_AddInstrumentFunction(CountInst, 0); 163 | 164 | // Register Fini to be called when the application exits 165 | PIN_AddFiniFunction(Fini, 0); 166 | 167 | // Start the program, never returns 168 | PIN_StartProgram(); 169 | 170 | return 0; 171 | } 172 | -------------------------------------------------------------------------------- /instselector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "pin.H" 6 | 7 | using namespace std; 8 | 9 | static std::set includeinst; 10 | static std::set excludeinst; 11 | static const string CMP = "cmp"; 12 | static const string ALL = "all"; 13 | static const string LOAD = "load"; 14 | static const string STORE = "store"; 15 | 16 | static string configfile = "pin.config.instselector.txt"; 17 | 18 | 19 | bool _isLoadInst(INS ins) { 20 | string opcode = INS_Mnemonic(ins); 21 | //cerr << opcode << endl; 22 | return INS_IsMemoryRead(ins) /*and opcode.find("MOV") != string::npos*/; 23 | } 24 | 25 | bool _isStoreInst(INS ins) { 26 | return INS_IsMemoryWrite(ins); 27 | } 28 | 29 | bool _isCmpInst(INS ins) { 30 | return INS_Valid(INS_Next(ins)) && 31 | INS_Category(INS_Next(ins)) == XED_CATEGORY_COND_BR; 32 | } 33 | 34 | bool _isCmpIncluded() { 35 | return includeinst.find(CMP) != includeinst.end() || 36 | (includeinst.find(ALL) != includeinst.end() && 37 | excludeinst.find(CMP) == excludeinst.end()); 38 | } 39 | 40 | void configInstSelector() { 41 | std::ifstream ifs; 42 | ifs.open(configfile.c_str(), std::ifstream::in); 43 | 44 | if (!ifs.fail()) { 45 | unsigned line_num = 0; 46 | 47 | while (!ifs.eof()) { 48 | char line[1000]; 49 | ifs.getline(line, 1000); 50 | // starting with '#' means comment 51 | if (line[0] == '#') 52 | continue; 53 | 54 | string line_str(line); 55 | string line_arr[100]; 56 | UINT32 num = Tokenize(line_str, line_arr, 100); 57 | 58 | // first line include 59 | if (line_num == 0) { 60 | for (UINT32 i = 0; i < num; i++) { 61 | if (line_arr[i] != "") { 62 | includeinst.insert(line_arr[i]); 63 | } 64 | } 65 | } else if (line_num == 1) { 66 | for (UINT32 i = 0; i < num; i++) { 67 | if (line_arr[i] != "") { 68 | excludeinst.insert(line_arr[i]); 69 | } 70 | } 71 | } 72 | 73 | line_num++; 74 | } 75 | 76 | ifs.close(); 77 | } else { 78 | includeinst.insert(ALL); 79 | } 80 | 81 | // for debug 82 | std::cerr << "include " << endl; 83 | for (std::set::const_iterator it = includeinst.begin(); 84 | it != includeinst.end(); ++it) { 85 | std::cerr << *it << endl; 86 | } 87 | std::cerr << "exclude " << endl; 88 | for (std::set::const_iterator it = excludeinst.begin(); 89 | it != excludeinst.end(); ++it) { 90 | std::cerr << *it << endl; 91 | } 92 | } 93 | 94 | 95 | bool isInstFITarget(INS ins) { 96 | bool ret = false; 97 | 98 | // check include 99 | if (includeinst.find(ALL) != includeinst.end()) { 100 | ret = true; 101 | } else { 102 | if (includeinst.find(LOAD) != includeinst.end() && 103 | _isLoadInst(ins)) { 104 | ret = true; 105 | } else if (includeinst.find(STORE) != includeinst.end() && 106 | _isStoreInst(ins)) { 107 | ret = true; 108 | } else if (includeinst.find(CATEGORY_StringShort(INS_Category(ins))) != includeinst.end() || 109 | includeinst.find(INS_Mnemonic(ins)) != includeinst.end()) { 110 | ret = true; 111 | } 112 | } 113 | 114 | if (excludeinst.find(LOAD) != excludeinst.end() && 115 | _isLoadInst(ins)) { 116 | ret = false; 117 | } else if (excludeinst.find(STORE) != excludeinst.end() && 118 | _isStoreInst(ins)) { 119 | ret = false; 120 | } else if (excludeinst.find(CATEGORY_StringShort(INS_Category(ins))) != excludeinst.end() || 121 | excludeinst.find(INS_Mnemonic(ins)) != excludeinst.end()) { 122 | ret = false; 123 | } 124 | 125 | // cmp inst is treated differently because cmp inst and other categories are not mutually exclusive 126 | if (_isCmpIncluded()) { 127 | if (_isCmpInst(ins)) 128 | ret = true; 129 | } else { 130 | if (_isCmpInst(ins)) 131 | ret = false; 132 | } 133 | 134 | // debug 135 | if (ret) { 136 | //std::cerr << "instruction to be included " << INS_Disassemble(ins) << endl; 137 | LOG("INSTSELECTOR: instruction to be included " + INS_Disassemble(ins) + "\n"); 138 | } else { 139 | //std::cerr << "instruction to be excluded " << INS_Disassemble(ins) << endl; 140 | } 141 | 142 | return ret; 143 | } 144 | -------------------------------------------------------------------------------- /instselector.h: -------------------------------------------------------------------------------- 1 | #ifndef INST_SELECTOR_H 2 | #define INST_SELECTOR_H 3 | 4 | #include "pin.H" 5 | 6 | void configInstSelector(); 7 | 8 | bool isInstFITarget(INS ins); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | ############################################################## 2 | # 3 | # DO NOT EDIT THIS FILE! 4 | # 5 | ############################################################## 6 | 7 | # If the tool is built out of the kit, PIN_ROOT must be specified in the make invocation and point to the kit root. 8 | ifdef PIN_ROOT 9 | CONFIG_ROOT := $(PIN_ROOT)/source/tools/Config 10 | else 11 | CONFIG_ROOT := ../Config 12 | endif 13 | include $(CONFIG_ROOT)/makefile.config 14 | include makefile.rules 15 | include $(TOOLS_ROOT)/Config/makefile.default.rules 16 | 17 | ############################################################## 18 | # 19 | # DO NOT EDIT THIS FILE! 20 | # 21 | ############################################################## 22 | -------------------------------------------------------------------------------- /makefile.rules: -------------------------------------------------------------------------------- 1 | ############################################################## 2 | # 3 | # This file includes all the test targets as well as all the 4 | # non-default build rules and test recipes. 5 | # 6 | ############################################################## 7 | 8 | 9 | ############################################################## 10 | # 11 | # Test targets 12 | # 13 | ############################################################## 14 | 15 | ###### Place all generic definitions here ###### 16 | 17 | # This defines tests which run tools of the same name. This is simply for convenience to avoid 18 | # defining the test name twice (once in TOOL_ROOTS and again in TEST_ROOTS). 19 | # Tests defined here should not be defined in TOOL_ROOTS and TEST_ROOTS. 20 | TEST_TOOL_ROOTS := 21 | 22 | # This defines the tests to be run that were not already defined in TEST_TOOL_ROOTS. 23 | TEST_ROOTS := 24 | 25 | # This defines the tools which will be run during the the tests, and were not already defined in 26 | # TEST_TOOL_ROOTS. 27 | TOOL_ROOTS := instcount instcategory faultinjection 28 | 29 | # This defines the static analysis tools which will be run during the the tests. They should not 30 | # be defined in TEST_TOOL_ROOTS. If a test with the same name exists, it should be defined in 31 | # TEST_ROOTS. 32 | # Note: Static analysis tools are in fact executables linked with the Pin Static Analysis Library. 33 | # This library provides a subset of the Pin APIs which allows the tool to perform static analysis 34 | # of an application or dll. Pin itself is not used when this tool runs. 35 | SA_TOOL_ROOTS := 36 | 37 | # This defines all the applications that will be run during the tests. 38 | APP_ROOTS := 39 | 40 | # This defines any additional object files that need to be compiled. 41 | OBJECT_ROOTS := utils instcount instcategory instselector faultinjection 42 | 43 | # This defines any additional dlls (shared objects), other than the pintools, that need to be compiled. 44 | DLL_ROOTS := 45 | 46 | # This defines any static libraries (archives), that need to be built. 47 | LIB_ROOTS := 48 | 49 | ###### Place architecture-specific definitions here ###### 50 | 51 | # Place ia32-specific definitions here if they apply to all supported operating systems. 52 | #ifeq ($(TARGET),ia32) 53 | # # Maid currently handles 32 bit syscalls only. 54 | # TEST_TOOL_ROOTS += faultinjection instcount instcategroy 55 | # OBJECT_ROOTS += faultinjection instcount instcategory 56 | #endif 57 | 58 | ###### Handle exceptions here ###### 59 | 60 | # The Maid test is disabled on OS X*. 61 | # See Mantis 3184 62 | #ifeq ($(TARGET_OS),mac) 63 | # TEST_TOOL_ROOTS := 64 | # TEST_ROOTS := 65 | # TOOL_ROOTS := 66 | # SA_TOOL_ROOTS := 67 | # APP_ROOTS := 68 | # OBJECT_ROOTS := 69 | # DLL_ROOTS := 70 | # LIB_ROOTS := 71 | #endif 72 | 73 | ###### Define the sanity subset ###### 74 | 75 | # This defines the list of tests that should run in sanity. It should include all the tests listed in 76 | # TEST_TOOL_ROOTS and TEST_ROOTS excluding only unstable tests. 77 | SANITY_SUBSET := $(TEST_TOOL_ROOTS) $(TEST_ROOTS) 78 | 79 | 80 | ############################################################## 81 | # 82 | # Test recipes 83 | # 84 | ############################################################## 85 | 86 | # This section contains recipes for tests other than the default. 87 | # See makefile.default.rules for the default test rules. 88 | # All tests in this section should adhere to the naming convention: .test 89 | 90 | 91 | ############################################################## 92 | # 93 | # Build rules 94 | # 95 | ############################################################## 96 | 97 | # This section contains the build rules for all binaries that have special build rules. 98 | # See makefile.default.rules for the default build rules. 99 | #TOOLS = $(TOOL_ROOTS:%=$(OBJDIR)%$(PINTOOL_SUFFIX)) 100 | #$(TOOLS): %$(PINTOOL_SUFFIX) : %.o $(OBJDIR)instselector.o $(OBJDIR)utils.o 101 | # $(PIN_LD) $(PIN_LDFLAGS) ${LINK_OUT}$@ $< $(OBJDIR)instselector.o $(OBJDIR)utils.o $(PIN_LIBS) $(DBG) 102 | 103 | ###### Special tools' build rules ###### 104 | $(OBJDIR)faultinjection$(PINTOOL_SUFFIX): $(OBJDIR)faultinjection.o $(OBJDIR)instselector.o $(OBJDIR)utils.o 105 | $(CXX) -shared -Wl,--hash-style=sysv ../../../intel64/runtime/pincrt/crtbeginS.o -Wl,-Bsymbolic -Wl,--version-script=../../../source/include/pin/pintool.ver -fabi-version=2 -o ${LINK_OUT}$@ $< $(OBJDIR)instselector.o $(OBJDIR)utils.o -L../../../intel64/runtime/pincrt -L../../../intel64/lib -L../../../intel64/lib-ext -L../../../extras/xed-intel64/lib -lpin -lxed ../../../intel64/runtime/pincrt/crtendS.o -lpin3dwarf -ldl-dynamic -nostdlib -lstlport-dynamic -lm-dynamic -lc-dynamic -lunwind-dynamic 106 | 107 | $(OBJDIR)instcount$(PINTOOL_SUFFIX): $(OBJDIR)instcount.o $(OBJDIR)instselector.o $(OBJDIR)utils.o 108 | $(CXX) -shared -Wl,--hash-style=sysv ../../../intel64/runtime/pincrt/crtbeginS.o -Wl,-Bsymbolic -Wl,--version-script=../../../source/include/pin/pintool.ver -fabi-version=2 -o ${LINK_OUT}$@ $< $(OBJDIR)instselector.o $(OBJDIR)utils.o -L../../../intel64/runtime/pincrt -L../../../intel64/lib -L../../../intel64/lib-ext -L../../../extras/xed-intel64/lib -lpin -lxed ../../../intel64/runtime/pincrt/crtendS.o -lpin3dwarf -ldl-dynamic -nostdlib -lstlport-dynamic -lm-dynamic -lc-dynamic -lunwind-dynamic 109 | 110 | $(OBJDIR)instcategory$(PINTOOL_SUFFIX): $(OBJDIR)instcategory.o $(OBJDIR)instselector.o $(OBJDIR)utils.o 111 | $(CXX) -shared -Wl,--hash-style=sysv ../../../intel64/runtime/pincrt/crtbeginS.o -Wl,-Bsymbolic -Wl,--version-script=../../../source/include/pin/pintool.ver -fabi-version=2 -o ${LINK_OUT}$@ $< $(OBJDIR)instselector.o $(OBJDIR)utils.o -L../../../intel64/runtime/pincrt -L../../../intel64/lib -L../../../intel64/lib-ext -L../../../extras/xed-intel64/lib -lpin -lxed ../../../intel64/runtime/pincrt/crtendS.o -lpin3dwarf -ldl-dynamic -nostdlib -lstlport-dynamic -lm-dynamic -lc-dynamic -lunwind-dynamic 112 | 113 | -------------------------------------------------------------------------------- /pin.config.instselector.txt: -------------------------------------------------------------------------------- 1 | loadstore -------------------------------------------------------------------------------- /utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | 4 | bool isValidInst(INS ins) { 5 | /** 6 | * IMPORTANT: This is to make sure fault injections are done at the .text 7 | * of the compiled code, instead of at libraries or .init/.fini sections 8 | */ 9 | if (!RTN_Valid(INS_Rtn(ins))) { // some library instructions do not have rtn !? 10 | LOG("Invalid RTN " + INS_Disassemble(ins) + "\n"); 11 | return false; 12 | } 13 | 14 | if (!IMG_IsMainExecutable(SEC_Img(RTN_Sec(INS_Rtn(ins))))) { 15 | //LOG("Libraries " + IMG_Name(SEC_Img(RTN_Sec(INS_Rtn(ins)))) + "\n"); 16 | return false; 17 | } 18 | if (SEC_Name(RTN_Sec(INS_Rtn(ins))) != ".text") { 19 | //LOG("Section: " + SEC_Name(RTN_Sec(INS_Rtn(ins))) + "\n"); 20 | return false; 21 | } 22 | std::string rtnname = RTN_Name(INS_Rtn(ins)); 23 | if (rtnname.find("__libc") == 0 || rtnname.find("_start") == 0 || 24 | rtnname.find("call_gmon_start") == 0 || rtnname.find("frame_dummy") == 0 || 25 | rtnname.find("__do_global") == 0 || rtnname.find("__stat") == 0) { 26 | return false; 27 | } 28 | LOG("Exe " + RTN_Name(INS_Rtn(ins)) + "\n"); 29 | 30 | REG reg = INS_RegW(ins, 0); 31 | if(!REG_valid(reg)) 32 | return false; 33 | 34 | return true; 35 | } 36 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | 4 | #include "pin.H" 5 | 6 | bool isValidInst(INS ins); 7 | 8 | #endif 9 | --------------------------------------------------------------------------------