static void generate_memset_zero (gimple stmt, tree op0, tree nb_iter, gimple_stmt_iterator bsi) { tree addr_base, nb_bytes; bool res = false; gimple_seq stmt_list = NULL, stmts; gimple fn_call; tree mem, fn; struct data_reference *dr = XCNEW (struct data_reference); location_t loc = gimple_location (stmt); DR_STMT (dr) = stmt; DR_REF (dr) = op0; res = dr_analyze_innermost (dr); gcc_assert (res && stride_of_unit_type_p (DR_STEP (dr), TREE_TYPE (op0))); nb_bytes = build_size_arg_loc (loc, nb_iter, op0, &stmt_list); addr_base = size_binop_loc (loc, PLUS_EXPR, DR_OFFSET (dr), DR_INIT (dr)); addr_base = fold_convert_loc (loc, sizetype, addr_base); /* Test for a negative stride, iterating over every element. */ if (integer_zerop (size_binop (PLUS_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (op0)), fold_convert (sizetype, DR_STEP (dr))))) { addr_base = size_binop_loc (loc, MINUS_EXPR, addr_base, fold_convert_loc (loc, sizetype, nb_bytes)); addr_base = size_binop_loc (loc, PLUS_EXPR, addr_base, TYPE_SIZE_UNIT (TREE_TYPE (op0))); } addr_base = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (DR_BASE_ADDRESS (dr)), DR_BASE_ADDRESS (dr), addr_base); mem = force_gimple_operand (addr_base, &stmts, true, NULL); gimple_seq_add_seq (&stmt_list, stmts); fn = build_fold_addr_expr (implicit_built_in_decls [BUILT_IN_MEMSET]); fn_call = gimple_build_call (fn, 3, mem, integer_zero_node, nb_bytes); gimple_seq_add_stmt (&stmt_list, fn_call); gsi_insert_seq_after (&bsi, stmt_list, GSI_CONTINUE_LINKING); if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "generated memset zero\n"); free_data_ref (dr); }
/* retrieve the thread x86 registers */ void get_thread_context( struct thread *thread, context_t *context, unsigned int flags ) { int i, pid = get_ptrace_tid(thread); long data[8]; /* all other regs are handled on the client side */ assert( flags == SERVER_CTX_DEBUG_REGISTERS ); if (!suspend_for_ptrace( thread )) return; for (i = 0; i < 8; i++) { if (i == 4 || i == 5) continue; errno = 0; data[i] = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(i), 0 ); if ((data[i] == -1) && errno) { file_set_error(); goto done; } } switch (context->cpu) { case CPU_x86: context->debug.i386_regs.dr0 = data[0]; context->debug.i386_regs.dr1 = data[1]; context->debug.i386_regs.dr2 = data[2]; context->debug.i386_regs.dr3 = data[3]; context->debug.i386_regs.dr6 = data[6]; context->debug.i386_regs.dr7 = data[7]; break; case CPU_x86_64: context->debug.x86_64_regs.dr0 = data[0]; context->debug.x86_64_regs.dr1 = data[1]; context->debug.x86_64_regs.dr2 = data[2]; context->debug.x86_64_regs.dr3 = data[3]; context->debug.x86_64_regs.dr6 = data[6]; context->debug.x86_64_regs.dr7 = data[7]; break; default: set_error( STATUS_INVALID_PARAMETER ); goto done; } context->flags |= SERVER_CTX_DEBUG_REGISTERS; done: resume_after_ptrace( thread ); }
/* set the thread x86 registers */ void set_thread_context( struct thread *thread, const context_t *context, unsigned int flags ) { int pid = get_ptrace_tid( thread ); /* all other regs are handled on the client side */ assert( flags == SERVER_CTX_DEBUG_REGISTERS ); if (!suspend_for_ptrace( thread )) return; switch (context->cpu) { case CPU_x86: /* Linux 2.6.33+ does DR0-DR3 alignment validation, so it has to know LEN bits first */ if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 & 0xffff0000 ) == -1) goto error; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->debug.i386_regs.dr0 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr0 = context->debug.i386_regs.dr0; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->debug.i386_regs.dr1 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr1 = context->debug.i386_regs.dr1; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->debug.i386_regs.dr2 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr2 = context->debug.i386_regs.dr2; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->debug.i386_regs.dr3 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr3 = context->debug.i386_regs.dr3; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->debug.i386_regs.dr6 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr6 = context->debug.i386_regs.dr6; /* Linux 2.6.33+ needs enable bits set briefly to update value returned by PEEKUSER later */ ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 | 0x55 ); if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr7 = context->debug.i386_regs.dr7; break; case CPU_x86_64: if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 & 0xffff0000 ) == -1) goto error; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->debug.x86_64_regs.dr0 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr0 = context->debug.x86_64_regs.dr0; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->debug.x86_64_regs.dr1 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr1 = context->debug.x86_64_regs.dr1; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->debug.x86_64_regs.dr2 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr2 = context->debug.x86_64_regs.dr2; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->debug.x86_64_regs.dr3 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr3 = context->debug.x86_64_regs.dr3; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->debug.x86_64_regs.dr6 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr6 = context->debug.x86_64_regs.dr6; ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 | 0x55 ); if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr7 = context->debug.x86_64_regs.dr7; break; default: set_error( STATUS_INVALID_PARAMETER ); } resume_after_ptrace( thread ); return; error: file_set_error(); resume_after_ptrace( thread ); }
static bool generate_memset_zero (gimple stmt, tree op0, tree nb_iter, gimple_stmt_iterator bsi) { tree addr_base; tree nb_bytes = NULL; bool res = false; gimple_seq stmts = NULL, stmt_list = NULL; gimple fn_call; tree mem, fndecl, fntype, fn; gimple_stmt_iterator i; struct data_reference *dr = XCNEW (struct data_reference); location_t loc = gimple_location (stmt); DR_STMT (dr) = stmt; DR_REF (dr) = op0; if (!dr_analyze_innermost (dr)) goto end; /* Test for a positive stride, iterating over every element. */ if (integer_zerop (fold_build2_loc (loc, MINUS_EXPR, integer_type_node, DR_STEP (dr), TYPE_SIZE_UNIT (TREE_TYPE (op0))))) { tree offset = fold_convert_loc (loc, sizetype, size_binop_loc (loc, PLUS_EXPR, DR_OFFSET (dr), DR_INIT (dr))); addr_base = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (DR_BASE_ADDRESS (dr)), DR_BASE_ADDRESS (dr), offset); } /* Test for a negative stride, iterating over every element. */ else if (integer_zerop (fold_build2_loc (loc, PLUS_EXPR, integer_type_node, TYPE_SIZE_UNIT (TREE_TYPE (op0)), DR_STEP (dr)))) { nb_bytes = build_size_arg_loc (loc, nb_iter, op0, &stmt_list); addr_base = size_binop_loc (loc, PLUS_EXPR, DR_OFFSET (dr), DR_INIT (dr)); addr_base = fold_build2_loc (loc, MINUS_EXPR, sizetype, addr_base, fold_convert_loc (loc, sizetype, nb_bytes)); addr_base = force_gimple_operand (addr_base, &stmts, true, NULL); gimple_seq_add_seq (&stmt_list, stmts); addr_base = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (DR_BASE_ADDRESS (dr)), DR_BASE_ADDRESS (dr), addr_base); } else goto end; mem = force_gimple_operand (addr_base, &stmts, true, NULL); gimple_seq_add_seq (&stmt_list, stmts); fndecl = implicit_built_in_decls [BUILT_IN_MEMSET]; fntype = TREE_TYPE (fndecl); fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl); if (!nb_bytes) nb_bytes = build_size_arg_loc (loc, nb_iter, op0, &stmt_list); fn_call = gimple_build_call (fn, 3, mem, integer_zero_node, nb_bytes); gimple_seq_add_stmt (&stmt_list, fn_call); for (i = gsi_start (stmt_list); !gsi_end_p (i); gsi_next (&i)) { gimple s = gsi_stmt (i); update_stmt_if_modified (s); } gsi_insert_seq_after (&bsi, stmt_list, GSI_CONTINUE_LINKING); res = true; if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "generated memset zero\n"); end: free_data_ref (dr); return res; }
static bool generate_memset_zero (gimple stmt, tree op0, tree nb_iter, gimple_stmt_iterator bsi) { tree t, addr_base; tree nb_bytes = NULL; bool res = false; gimple_seq stmts = NULL, stmt_list = NULL; gimple fn_call; tree mem, fndecl, fntype, fn; gimple_stmt_iterator i; ssa_op_iter iter; struct data_reference *dr = XCNEW (struct data_reference); DR_STMT (dr) = stmt; DR_REF (dr) = op0; if (!dr_analyze_innermost (dr)) goto end; /* Test for a positive stride, iterating over every element. */ if (integer_zerop (fold_build2 (MINUS_EXPR, integer_type_node, DR_STEP (dr), TYPE_SIZE_UNIT (TREE_TYPE (op0))))) { tree offset = fold_convert (sizetype, size_binop (PLUS_EXPR, DR_OFFSET (dr), DR_INIT (dr))); addr_base = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (DR_BASE_ADDRESS (dr)), DR_BASE_ADDRESS (dr), offset); } /* Test for a negative stride, iterating over every element. */ else if (integer_zerop (fold_build2 (PLUS_EXPR, integer_type_node, TYPE_SIZE_UNIT (TREE_TYPE (op0)), DR_STEP (dr)))) { nb_bytes = build_size_arg (nb_iter, op0, &stmt_list); addr_base = size_binop (PLUS_EXPR, DR_OFFSET (dr), DR_INIT (dr)); addr_base = fold_build2 (MINUS_EXPR, sizetype, addr_base, nb_bytes); addr_base = force_gimple_operand (addr_base, &stmts, true, NULL); gimple_seq_add_seq (&stmt_list, stmts); addr_base = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (DR_BASE_ADDRESS (dr)), DR_BASE_ADDRESS (dr), addr_base); } else goto end; mem = force_gimple_operand (addr_base, &stmts, true, NULL); gimple_seq_add_seq (&stmt_list, stmts); fndecl = implicit_built_in_decls [BUILT_IN_MEMSET]; fntype = TREE_TYPE (fndecl); fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl); if (!nb_bytes) nb_bytes = build_size_arg (nb_iter, op0, &stmt_list); fn_call = gimple_build_call (fn, 3, mem, integer_zero_node, nb_bytes); gimple_seq_add_stmt (&stmt_list, fn_call); for (i = gsi_start (stmt_list); !gsi_end_p (i); gsi_next (&i)) { gimple s = gsi_stmt (i); update_stmt_if_modified (s); FOR_EACH_SSA_TREE_OPERAND (t, s, iter, SSA_OP_VIRTUAL_DEFS) { if (TREE_CODE (t) == SSA_NAME) t = SSA_NAME_VAR (t); mark_sym_for_renaming (t); } } /* Mark also the uses of the VDEFS of STMT to be renamed. */ FOR_EACH_SSA_TREE_OPERAND (t, stmt, iter, SSA_OP_VIRTUAL_DEFS) { if (TREE_CODE (t) == SSA_NAME) { gimple s; imm_use_iterator imm_iter; FOR_EACH_IMM_USE_STMT (s, imm_iter, t) update_stmt (s); t = SSA_NAME_VAR (t); } mark_sym_for_renaming (t); } gsi_insert_seq_after (&bsi, stmt_list, GSI_CONTINUE_LINKING); res = true; if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "generated memset zero\n"); todo |= TODO_rebuild_alias; end: free_data_ref (dr); return res; }
/* set the thread x86 registers */ void set_thread_context( struct thread *thread, const context_t *context, unsigned int flags ) { int pid = get_ptrace_tid( thread ); /* all other regs are handled on the client side */ assert( flags == SERVER_CTX_DEBUG_REGISTERS ); if (!suspend_for_ptrace( thread )) return; switch (context->cpu) { case CPU_x86: if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->debug.i386_regs.dr0 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr0 = context->debug.i386_regs.dr0; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->debug.i386_regs.dr1 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr1 = context->debug.i386_regs.dr1; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->debug.i386_regs.dr2 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr2 = context->debug.i386_regs.dr2; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->debug.i386_regs.dr3 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr3 = context->debug.i386_regs.dr3; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->debug.i386_regs.dr6 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr6 = context->debug.i386_regs.dr6; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 ) == -1) goto error; if (thread->context) thread->context->debug.i386_regs.dr7 = context->debug.i386_regs.dr7; break; case CPU_x86_64: if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->debug.x86_64_regs.dr0 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr0 = context->debug.x86_64_regs.dr0; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->debug.x86_64_regs.dr1 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr1 = context->debug.x86_64_regs.dr1; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->debug.x86_64_regs.dr2 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr2 = context->debug.x86_64_regs.dr2; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->debug.x86_64_regs.dr3 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr3 = context->debug.x86_64_regs.dr3; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->debug.x86_64_regs.dr6 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr6 = context->debug.x86_64_regs.dr6; if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 ) == -1) goto error; if (thread->context) thread->context->debug.x86_64_regs.dr7 = context->debug.x86_64_regs.dr7; break; default: set_error( STATUS_INVALID_PARAMETER ); } resume_after_ptrace( thread ); return; error: file_set_error(); resume_after_ptrace( thread ); }
int main(void) { int status; pid_t pid; // Allocate a shared block. share = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if ((pid = fork()) < 0) { perror("fork"); abort(); } else if (pid == 0) { ptrace(PTRACE_TRACEME, 0, NULL, NULL); kill(getpid(), SIGSTOP); share[0] = 1; // open("foo.bar", O_WRONLY | O_CREAT); _exit(0); } #if 0 if (waitpid(pid, &status, 0) < 0) { perror("waitpid"); abort(); } assert(WIFSTOPPED(status)); assert(WSTOPSIG(status) == SIGSTOP); if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) < 0) { perror("ptrace(PTRACE_SYSCALL, ...)"); ptrace(PTRACE_KILL, pid, NULL, NULL); abort(); } if (waitpid(pid, &status, 0) < 0) { perror("waitpid"); ptrace(PTRACE_KILL, pid, NULL, NULL); abort(); } assert(WIFSTOPPED(status)); assert(WSTOPSIG(status) == SIGTRAP); #endif printf("ORIG_ACCUM %d and ORIG_EAX %d, DR_OFFSET(0) %d DR_OFFSET(1) %d total %d\n",ORIG_ACCUM, ORIG_EAX, DR_OFFSET(0), DR_OFFSET(1), sizeof(struct user)); #if 0 if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) { perror("ptrace(PTRACE_ATTACH, ...)" ); ptrace(PTRACE_KILL, pid, NULL, NULL); abort(); } #endif /* Change the system call to something invalid, so it will be denied. */ // if (ptrace(PTRACE_POKEUSER, pid, ORIG_ACCUM, 0xbadca11) < 0) { if (ptrace(PTRACE_POKEUSER, pid, DR_OFFSET(0), share) < 0) { perror("ptrace(PTRACE_POKEUSER, ...)"); ptrace(PTRACE_KILL, pid, NULL, NULL); abort(); } /* Let the process continue */ ptrace(PTRACE_CONT, pid, NULL, NULL); waitpid(pid, &status, 0); // assert(WIFEXITED(status)); exit(WEXITSTATUS(status)); }