/** @brief translate the port and address of the entering connect syscall * * We take the arguments in the registers, which correspond to global * simulated address and port. We translate them to real local ones, * and put the result back in the registers to actually get the * connect syscall performed by the kernel. */ void sys_translate_connect_in(process_descriptor_t * proc, syscall_arg_u * sysarg) { connect_arg_t arg = &(sysarg->connect); pid_t pid = proc->pid; reg_s reg; ptrace_get_register(pid, ®); arg->sai.sin_port = htons(get_real_port(proc, arg->sai.sin_addr.s_addr, ntohs(arg->sai.sin_port))); arg->sai.sin_addr.s_addr = inet_addr("127.0.0.1"); XBT_DEBUG("Try to connect on 127.0.0.1:%d", arg->sai.sin_port); ptrace_poke(pid, (void *) reg.arg2, &(arg->sai), sizeof(struct sockaddr_in)); }
/** @brief put the arguments we want in the registers of poll syscall */ void sys_build_poll(process_descriptor_t * proc, syscall_arg_u * sysarg, int match) { pid_t pid = proc->pid; ptrace_restore_syscall(pid, SYS_poll, match); reg_s r; ptrace_get_register(pid, &r); poll_arg_t arg = &(sysarg->poll); arg->ret = match; if (r.arg1 != 0) { ptrace_poke(pid, (void *) r.arg1, arg->fd_list, sizeof(struct pollfd) * arg->nbfd); } }
/** @brief translate the port and address of the exiting connect syscall * * We take the arguments in the registers, which correspond to the real * local address and port we established the connection on. We translate * them into global simulated ones and put the result back in the registers, * so that the application gets wronged. */ void sys_translate_connect_out(process_descriptor_t * proc, syscall_arg_u * sysarg) { connect_arg_t arg = &(sysarg->connect); pid_t pid = proc->pid; reg_s reg; ptrace_get_register(pid, ®); translate_desc_t *td = get_translation(ntohs(arg->sai.sin_port)); arg->sai.sin_port = htons(td->port_num); arg->sai.sin_addr.s_addr = td->ip; XBT_DEBUG("Restore %s:%d", inet_ntoa(arg->sai.sin_addr), td->port_num); ptrace_poke(pid, (void *) reg.arg2, &(arg->sai), sizeof(struct sockaddr_in)); }
/** @brief translate the port and address of the exiting recvfrom syscall * * We take the arguments in the registers, which correspond to the real * local address and port we received the message from. We translate them * into global simulated ones and put the result back in the registers, so * that the application gets wronged. */ void sys_translate_recvfrom_out(process_descriptor_t * proc, syscall_arg_u * sysarg) { recvfrom_arg_t arg = &(sysarg->recvfrom); pid_t pid = proc->pid; reg_s reg; ptrace_get_register(pid, ®); if (reg.arg5 == 0) return; translate_desc_t *td = get_translation(ntohs(arg->sai.sin_port)); arg->sai.sin_port = htons(td->port_num); arg->sai.sin_addr.s_addr = td->ip; ptrace_poke(pid, (void *) reg.arg5, &(arg->sai), sizeof(struct sockaddr_in)); }
/** @brief translate the port and address of the entering recvfrom syscall * * We take the arguments in the registers, which correspond to the global * simulated address and port the application wants to receive the message * from. We translate them to real local ones and put the result back in the * registers to actually get the recvfrom syscall performed by the kernel. */ void sys_translate_recvfrom_in(process_descriptor_t * proc, syscall_arg_u * sysarg) { recvfrom_arg_t arg = &(sysarg->recvfrom); pid_t pid = proc->pid; reg_s reg; ptrace_get_register(pid, ®); if (reg.arg5 == 0) return; struct sockaddr_in temp = arg->sai; int port = get_real_port(proc, temp.sin_addr.s_addr, ntohs(temp.sin_port)); temp.sin_addr.s_addr = inet_addr("127.0.0.1"); temp.sin_port = htons(port); ptrace_poke(pid, (void *) reg.arg5, &temp, sizeof(struct sockaddr_in)); arg->sai = temp; XBT_DEBUG("Using 127.0.0.1:%d", port); }
/** @brief put the arguments we want in the registers of select syscall */ void sys_build_select(process_descriptor_t * proc, syscall_arg_u * sysarg, int match) { //TODO use unified union syscall_arg_u pid_t pid = proc->pid; ptrace_restore_syscall(pid, SYS_select, match); reg_s r; ptrace_get_register(pid, &r); select_arg_t arg = &(sysarg->select); if (arg->fd_state & SELECT_FDRD_SET) { ptrace_poke(pid, (void *) r.arg2, &(arg->fd_read), sizeof(fd_set)); } if (arg->fd_state & SELECT_FDWR_SET) { ptrace_poke(pid, (void *) r.arg3, &(arg->fd_write), sizeof(fd_set)); } if (arg->fd_state & SELECT_FDEX_SET) { ptrace_poke(pid, (void *) r.arg4, &(arg->fd_except), sizeof(fd_set)); } }
/** @brief translate the port and address of the entering sendto syscall * * We take the arguments in the registers, which correspond to the global * simulated address and port the application wants to send the message to. * We translate them to real local ones and put the result back in the * registers to actually get the sendto syscall performed by the kernel. */ void sys_translate_sendto_in(process_descriptor_t * proc, syscall_arg_u * sysarg) { sendto_arg_t arg = &(sysarg->sendto); pid_t pid = proc->pid; reg_s reg; ptrace_get_register(pid, ®); if (reg.arg5 == 0) return; struct in_addr in = { arg->sai.sin_addr.s_addr }; XBT_DEBUG("Translate address %s:%d", inet_ntoa(in), ntohs(arg->sai.sin_port)); struct sockaddr_in temp = arg->sai; int port = get_real_port(proc, temp.sin_addr.s_addr, ntohs(temp.sin_port)); temp.sin_addr.s_addr = inet_addr("127.0.0.1"); temp.sin_port = htons(port); ptrace_poke(pid, (void *) reg.arg5, &temp, sizeof(struct sockaddr_in)); XBT_DEBUG("Using 127.0.0.1:%d", port); }
/** @brief translate the port and address of the exiting accept syscall * * We take the arguments in the registers, which correspond to the * real local address and port we obtained. We translate them into * global simulated ones and put the result back in the registers, so * that the application gets wronged. */ void sys_translate_accept_out(process_descriptor_t * proc, syscall_arg_u * sysarg) { accept_arg_t arg = &(sysarg->accept); pid_t pid = proc->pid; reg_s reg; ptrace_get_register(pid, ®); int port = ntohs(arg->sai.sin_port); struct infos_socket *is = get_infos_socket(proc, arg->sockfd); comm_get_ip_port_accept(is, &(arg->sai)); msg_host_t host; if (arg->sai.sin_addr.s_addr == inet_addr("127.0.0.1")) host = proc->host; else host = get_host_by_ip(arg->sai.sin_addr.s_addr); set_real_port(host, ntohs(arg->sai.sin_port), port); add_new_translation(port, ntohs(arg->sai.sin_port), arg->sai.sin_addr.s_addr); ptrace_poke(pid, (void *) reg.arg2, &(arg->sai), sizeof(struct sockaddr_in)); }
/** @brief Handles all syscalls of the tracked pid until it does a blocking action. * * Blocking actions are stuff that must be reported to the simulator and which * completion takes time. The most prominent examples are related to sending and * receiving data. * * The tracked pid can run more than one syscall in this function if theses calls * are about the metadata that we maintain in simterpose without exposing them to * simgrid. For example, if you call socket() or accept(), we only have to maintain * our metadata but there is no need to inform the simulator, nor to ask for the * completion time of these things. */ int process_handle(process_descriptor_t * proc) { reg_s arg; pid_t pid = proc->pid; XBT_DEBUG("PROCESS HANDLE MSG"); while (1) { ptrace_get_register(pid, &arg); int ret; XBT_DEBUG("found syscall: [%d] %s (%ld) = %ld, in_syscall = %d", pid, syscall_list[arg.reg_orig], arg.reg_orig, arg.ret, proc->in_syscall); switch (arg.reg_orig) { case SYS_creat: syscall_creat(&arg, proc); break; case SYS_open: XBT_DEBUG("On open"); XBT_DEBUG("Valeur des registres dans l'AS:"); XBT_DEBUG("Valeur de retour %lu", arg.ret); XBT_DEBUG("Valeur des arg %lu %lu %lu %lu %lu %lu", arg.arg[0], arg.arg[1], arg.arg[2], arg.arg[3], arg.arg[4], arg.arg[5]); syscall_open(&arg, proc); break; case SYS_close: syscall_close(&arg, proc); break; case SYS_read: syscall_read(&arg, proc); break; case SYS_write: XBT_DEBUG("On write"); XBT_DEBUG("Valeur des registres dans l'AS:"); XBT_DEBUG("Valeur de retour %lu", arg.ret); XBT_DEBUG("Valeur des arg %lu %lu %lu %lu %lu %lu", arg.arg[0], arg.arg[1], arg.arg[2], arg.arg[3], arg.arg[4], arg.arg[5]); if ((ret = syscall_write(&arg, proc))) return ret; break; case SYS_dup: syscall_dup(&arg, proc); break; case SYS_dup2: syscall_dup2(&arg, proc); break; case SYS_fcntl: syscall_fcntl(&arg, proc); break; case SYS_lseek: syscall_lseek(&arg, proc); break; case SYS_poll: syscall_poll(&arg, proc); break; case SYS_select: syscall_select(&arg, proc); break; case SYS_pipe: syscall_pipe(&arg, proc); case SYS_brk: syscall_brk(&arg, proc); break; case SYS_socket: syscall_socket(&arg, proc); break; case SYS_connect: syscall_connect(&arg, proc); break; case SYS_bind: syscall_bind(&arg, proc); break; case SYS_listen: syscall_listen(&arg, proc); break; case SYS_accept: syscall_accept(&arg, proc); break; #if UINTPTR_MAX == 0xffffffff /* 32-bit architecture */ case SYS_send: ret = syscall_send(&arg, proc); if (ret) return ret; break; case SYS_recv: syscall_recv(&arg, proc); break; #endif case SYS_sendto: ret = syscall_sendto(&arg, proc); if (ret) return ret; break; case SYS_recvfrom: syscall_recvfrom(&arg, proc); break; case SYS_sendmsg: if ((ret = syscall_sendmsg( &arg, proc))) return ret; break; case SYS_recvmsg: syscall_recvmsg(&arg, proc); break; case SYS_shutdown: syscall_shutdown(&arg, proc); break; case SYS_getpeername: syscall_getpeername(&arg, proc); break; case SYS_getsockopt: syscall_getsockopt(&arg, proc); break; case SYS_setsockopt: syscall_setsockopt(&arg, proc); break; case SYS_clone: syscall_clone(&arg, proc); break; case SYS_execve: syscall_execve(&arg, proc); break; case SYS_exit: XBT_DEBUG("exit(%ld) called", arg.arg[0]); return syscall_exit(&arg, proc); break; case SYS_exit_group: XBT_DEBUG("exit_group(%ld) called", arg.arg[0]); return syscall_exit(&arg, proc); break; case SYS_getpid: syscall_getpid(&arg, proc); break; case SYS_tuxcall: syscall_tuxcall(&arg, proc); break; default: syscall_default(pid, &arg, proc); break; } // Step the traced process ptrace_resume_process(pid); // XBT_DEBUG("process resumed, waitpid"); waitpid(pid, &(proc->status), __WALL); } // while(1) THROW_IMPOSSIBLE; //There's no way to quit the loop return 0; }