void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, int* total_sleep_time_usec) { log_t log; log.tfd = fd; log.amfd = amfd; dump_process_header(&log, pid); dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec); char task_path[64]; snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid); DIR* d = opendir(task_path); if (d != NULL) { struct dirent* de = NULL; while ((de = readdir(d)) != NULL) { if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { continue; } char* end; pid_t new_tid = strtoul(de->d_name, &end, 10); if (*end || new_tid == tid) { continue; } dump_thread(&log, new_tid, false, detach_failed, total_sleep_time_usec); } closedir(d); } dump_process_footer(&log, pid); }
BOOL ThreadCloseHandle(HANDLE handle) { WINPR_THREAD* thread = (WINPR_THREAD*) handle; if (!thread_list) { WLog_ERR(TAG, "Thread list does not exist, check call!"); dump_thread(thread); } else if (!ListDictionary_Contains(thread_list, &thread->thread)) { WLog_ERR(TAG, "Thread list does not contain this thread! check call!"); dump_thread(thread); } else { ListDictionary_Lock(thread_list); dump_thread(thread); if ((thread->started) && (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0)) { WLog_ERR(TAG, "Thread running, setting to detached state!"); thread->detached = TRUE; pthread_detach(thread->thread); } else { cleanup_handle(thread); } ListDictionary_Unlock(thread_list); if (ListDictionary_Count(thread_list) < 1) { ListDictionary_Free(thread_list); thread_list = NULL; } } return TRUE; }
bool thread_trap(thread_t * thread) { pt_regs regs; address_t ip, jump_target; if (unlikely(!thread_get_regs(thread, ®s))) { /* Thread died while reading registers. Consider this case as handled. */ return true; } ip = regs.pc; jump_target = jump_get(thread->process, ip); debug("Thread %s hit a break at %s.", str_thread(thread), str_address(thread->process, ip)); #if 0 /* enable to see full context on each hit */ dump_thread(thread); #endif if (likely(jump_target)) { /* Thread hit a tracepoint. Change the PC and let it continue. */ if (likely(!thread->process->stabilizing)) { debug("Thread %s jumping to %s.", str_thread(thread), str_address(thread->process, jump_target)); regs.pc = jump_target; if (likely(thread_set_regs(thread, ®s))) { thread_continue_or_stop(thread, 0); } } else { /* The process is currently stabilizing threads. The current thread just hit a tracepoint, but we don't * change its address to the trampoline, we just leave it stopped. If we continue the thread now, it * will hit the tracepoint again. */ info("Thread %s is stabilizing, deferring jump to %s.", str_thread(thread), str_address(thread->process, jump_target)); } return true; } /* Linker breakpoint */ if (likely(ip == thread->process->linker.bkpt)) { /* Linker breakpoint */ linker_notify(thread); regs.pc = regs.regs[30]; if (likely(thread_set_regs(thread, ®s))) { thread_continue_or_stop(thread, 0); } return true; } return false; }
/* Run given thread until it reaches address stopat. */ bool fncall_runtil(thread_t * thread, address_t stopat) { /* TODO: Be more verbose about errors. */ insn_t insn; insn_kind_t kind; assert(!thread->state.slavemode); info("Running thread %s until it reaches %p (runtil).", str_thread(thread), (void *) stopat); thread->state.slavemode = true; kind = (stopat & 0x1) ? INSN_KIND_THUMB : INSN_KIND_ARM; if (!patch_read_insn_detect_kind(thread, stopat, &insn, &kind)) goto fail; /* Patch instruction. */ if (!patch_insn(thread, stopat, kind, get_breakpoint_insn(kind))) goto fail; thread_continue(thread, 0); while (1) { thread_wait(thread, false); if (thread->state.dead) goto fail; if ((thread->state.signo == SIGSEGV) || (thread->state.signo == SIGTRAP) || (thread->state.signo == SIGBUS)) { struct pt_regs regs; thread_get_regs(thread, ®s); if (arch_get_pc(®s) == (stopat & 0xfffffffe)) { /* This is the signal we were waiting for. */ break; } } warning("Unexpected signal %s received during runtil in thread %s. The signal will be delivered.", str_signal(thread->state.signo), str_thread(thread)); dump_thread(thread); void callback(segment_t * segment) { verbose("%s\n", str_segment(segment)); } segment_iter(thread->process, callback); /* Deliver the signal. */ thread_continue(thread, 0); }
static void initial_thread_func(void) { thread_t *ct = get_current_thread(); #if LOCAL_TRACE LTRACEF("thread %p calling %p with arg %p\n", ct, ct->entry, ct->arg); dump_thread(ct); #endif /* exit the implicit critical section we're within */ exit_critical_section(); int ret = ct->entry(ct->arg); LTRACEF("thread %p exiting with %d\n", ct, ret); thread_exit(ret); }
static void initial_thread_func(void) { thread_t *ct = get_current_thread(); #if LOCAL_TRACE LTRACEF("thread %p calling %p with arg %p\n", ct, ct->entry, ct->arg); dump_thread(ct); #endif /* release the thread lock that was implicitly held across the reschedule */ spin_unlock(&thread_lock); arch_enable_ints(); int ret = ct->entry(ct->arg); LTRACEF("thread %p exiting with %d\n", ct, ret); thread_exit(ret); }
static BOOL winpr_StartThread(WINPR_THREAD* thread) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); if (thread->dwStackSize > 0) pthread_attr_setstacksize(&attr, (size_t) thread->dwStackSize); thread->started = TRUE; reset_event(thread); if (pthread_create(&thread->thread, &attr, thread_launcher, thread)) goto error; if (pthread_mutex_lock(&thread->threadIsReadyMutex)) goto error; if (!ListDictionary_Add(thread_list, &thread->thread, thread)) { WLog_ERR(TAG, "failed to add the thread to the thread list"); pthread_mutex_unlock(&thread->threadIsReadyMutex); goto error; } if (pthread_cond_signal(&thread->threadIsReady) != 0) { WLog_ERR(TAG, "failed to signal the thread was ready"); pthread_mutex_unlock(&thread->threadIsReadyMutex); goto error; } if (pthread_mutex_unlock(&thread->threadIsReadyMutex)) goto error; pthread_attr_destroy(&attr); dump_thread(thread); return TRUE; error: pthread_attr_destroy(&attr); return FALSE; }
int __used parasite_service(unsigned int cmd, void *args) { pr_info("Parasite cmd %d/%x process\n", cmd, cmd); switch (cmd) { case PARASITE_CMD_INIT: return init(args); case PARASITE_CMD_INIT_THREAD: return init_thread(); case PARASITE_CMD_FINI: return fini(); case PARASITE_CMD_FINI_THREAD: return fini_thread(); case PARASITE_CMD_CFG_LOG: return parasite_cfg_log(args); case PARASITE_CMD_DUMPPAGES: return dump_pages(args); case PARASITE_CMD_MPROTECT_VMAS: return mprotect_vmas(args); case PARASITE_CMD_DUMP_SIGACTS: return dump_sigact(args); case PARASITE_CMD_DUMP_ITIMERS: return dump_itimers(args); case PARASITE_CMD_DUMP_MISC: return dump_misc(args); case PARASITE_CMD_DUMP_CREDS: return dump_creds(args); case PARASITE_CMD_DUMP_THREAD: return dump_thread(args); case PARASITE_CMD_DRAIN_FDS: return drain_fds(args); case PARASITE_CMD_GET_PROC_FD: return parasite_get_proc_fd(); case PARASITE_CMD_DUMP_TTY: return parasite_dump_tty(args); } pr_err("Unknown command to parasite: %d\n", cmd); return -EINVAL; }
static BOOL winpr_StartThread(WINPR_THREAD *thread) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); if (thread->dwStackSize > 0) pthread_attr_setstacksize(&attr, (size_t) thread->dwStackSize); thread->started = TRUE; reset_event(thread); if (pthread_create(&thread->thread, &attr, thread_launcher, thread)) goto error; if (!ListDictionary_Add(thread_list, &thread->thread, thread)) goto error; pthread_attr_destroy(&attr); dump_thread(thread); return TRUE; error: pthread_attr_destroy(&attr); return FALSE; }
static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) { mm_segment_t fs; int has_dumped = 0; unsigned long dump_start, dump_size; struct user dump; #if defined(__alpha__) # define START_DATA(u) (u.start_data) #elif defined(__arm__) # define START_DATA(u) ((u.u_tsize << PAGE_SHIFT) + u.start_code) #elif defined(__sparc__) # define START_DATA(u) (u.u_tsize) #elif defined(__i386__) || defined(__mc68000__) || defined(__arch_um__) # define START_DATA(u) (u.u_tsize << PAGE_SHIFT) #endif #ifdef __sparc__ # define START_STACK(u) ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1)) #else # define START_STACK(u) (u.start_stack) #endif fs = get_fs(); set_fs(KERNEL_DS); has_dumped = 1; current->flags |= PF_DUMPCORE; strncpy(dump.u_comm, current->comm, sizeof(current->comm)); #ifndef __sparc__ dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump))); #endif dump.signal = signr; dump_thread(regs, &dump); /* If the size of the dump file exceeds the rlimit, then see what would happen if we wrote the stack, but not the data area. */ #ifdef __sparc__ if ((dump.u_dsize+dump.u_ssize) > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_dsize = 0; #else if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_dsize = 0; #endif /* Make sure we have enough room to write the stack and data areas. */ #ifdef __sparc__ if ((dump.u_ssize) > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_ssize = 0; #else if ((dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_ssize = 0; #endif /* make sure we actually have a data and stack area to dump */ set_fs(USER_DS); #ifdef __sparc__ if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize)) dump.u_dsize = 0; if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize)) dump.u_ssize = 0; #else if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT)) dump.u_dsize = 0; if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize << PAGE_SHIFT)) dump.u_ssize = 0; #endif set_fs(KERNEL_DS); /* struct user */ DUMP_WRITE(&dump,sizeof(dump)); /* Now dump all of the user data. Include malloced stuff as well */ #ifndef __sparc__ DUMP_SEEK(PAGE_SIZE); #endif /* now we start writing out the user space info */ set_fs(USER_DS); /* Dump the data area */ if (dump.u_dsize != 0) { dump_start = START_DATA(dump); #ifdef __sparc__ dump_size = dump.u_dsize; #else dump_size = dump.u_dsize << PAGE_SHIFT; #endif DUMP_WRITE(dump_start,dump_size); } /* Now prepare to dump the stack area */ if (dump.u_ssize != 0) { dump_start = START_STACK(dump); #ifdef __sparc__ dump_size = dump.u_ssize; #else dump_size = dump.u_ssize << PAGE_SHIFT; #endif DUMP_WRITE(dump_start,dump_size); } /* Finally dump the task struct. Not be used by gdb, but could be useful */ set_fs(KERNEL_DS); DUMP_WRITE(current,sizeof(*current)); end_coredump: set_fs(fs); return has_dumped; }
/* * Page fault handler for x86-64 */ void x86_pfe_handler(struct x86_iframe *frame) { /* Handle a page fault exception */ uint32_t error_code; thread_t *current_thread; error_code = frame->err_code; #ifdef PAGE_FAULT_DEBUG_INFO uint64_t v_addr, ssp, esp, ip, rip; v_addr = x86_get_cr2(); ssp = frame->user_ss & X86_8BYTE_MASK; esp = frame->user_rsp; ip = frame->cs & X86_8BYTE_MASK; rip = frame->rip; dprintf(SPEW, "<PAGE FAULT> Instruction Pointer = 0x%x:0x%x\n", (unsigned int)ip, (unsigned int)rip); dprintf(SPEW, "<PAGE FAULT> Stack Pointer = 0x%x:0x%x\n", (unsigned int)ssp, (unsigned int)esp); dprintf(SPEW, "<PAGE FAULT> Fault Linear Address = 0x%x\n", (unsigned int)v_addr); dprintf(SPEW, "<PAGE FAULT> Error Code Value = 0x%x\n", error_code); dprintf(SPEW, "<PAGE FAULT> Error Code Type = %s %s %s%s, %s\n", error_code & PFEX_U ? "user" : "supervisor", error_code & PFEX_W ? "write" : "read", error_code & PFEX_I ? "instruction" : "data", error_code & PFEX_RSV ? " rsv" : "", error_code & PFEX_P ? "protection violation" : "page not present"); #endif current_thread = get_current_thread(); dump_thread(current_thread); if(error_code & PFEX_U) { // User mode page fault switch(error_code) { case 4: case 5: case 6: case 7: #ifdef PAGE_FAULT_DEBUG_INFO thread_detach(current_thread); #else thread_exit(current_thread->retcode); #endif break; } } else { // Supervisor mode page fault switch(error_code) { case 0: case 1: case 2: case 3: exception_die(frame, "Page Fault exception, halting\n"); break; } } }
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) { HANDLE handle; WINPR_THREAD* thread; thread = (WINPR_THREAD*) calloc(1, sizeof(WINPR_THREAD)); if (!thread) return NULL; thread->dwStackSize = dwStackSize; thread->lpParameter = lpParameter; thread->lpStartAddress = lpStartAddress; thread->lpThreadAttributes = lpThreadAttributes; thread->ops = &ops; #if defined(WITH_DEBUG_THREADS) thread->create_stack = winpr_backtrace(20); dump_thread(thread); #endif thread->pipe_fd[0] = -1; thread->pipe_fd[1] = -1; #ifdef HAVE_EVENTFD_H thread->pipe_fd[0] = eventfd(0, EFD_NONBLOCK); if (thread->pipe_fd[0] < 0) { WLog_ERR(TAG, "failed to create thread pipe fd 0"); goto error_pipefd0; } #else if (pipe(thread->pipe_fd) < 0) { WLog_ERR(TAG, "failed to create thread pipe"); goto error_pipefd0; } { int flags = fcntl(thread->pipe_fd[0], F_GETFL); fcntl(thread->pipe_fd[0], F_SETFL, flags | O_NONBLOCK); } #endif if (pthread_mutex_init(&thread->mutex, 0) != 0) { WLog_ERR(TAG, "failed to initialize thread mutex"); goto error_mutex; } if (pthread_mutex_init(&thread->threadIsReadyMutex, NULL) != 0) { WLog_ERR(TAG, "failed to initialize a mutex for a condition variable"); goto error_thread_ready_mutex; } if (pthread_cond_init(&thread->threadIsReady, NULL) != 0) { WLog_ERR(TAG, "failed to initialize a condition variable"); goto error_thread_ready; } WINPR_HANDLE_SET_TYPE_AND_MODE(thread, HANDLE_TYPE_THREAD, WINPR_FD_READ); handle = (HANDLE) thread; if (!thread_list) { thread_list = ListDictionary_New(TRUE); if (!thread_list) { WLog_ERR(TAG, "Couldn't create global thread list"); goto error_thread_list; } thread_list->objectKey.fnObjectEquals = thread_compare; } if (!(dwCreationFlags & CREATE_SUSPENDED)) { if (!winpr_StartThread(thread)) goto error_thread_list; } else { if (!set_event(thread)) goto error_thread_list; } return handle; error_thread_list: pthread_cond_destroy(&thread->threadIsReady); error_thread_ready: pthread_mutex_destroy(&thread->threadIsReadyMutex); error_thread_ready_mutex: pthread_mutex_destroy(&thread->mutex); error_mutex: if (thread->pipe_fd[1] >= 0) close(thread->pipe_fd[1]); if (thread->pipe_fd[0] >= 0) close(thread->pipe_fd[0]); error_pipefd0: free(thread); return NULL; }
static inline int do_aout_core_dump(long signr, struct pt_regs * regs) { struct inode * inode = NULL; struct file file; unsigned short fs; int has_dumped = 0; char corefile[6+sizeof(current->comm)]; unsigned long dump_start, dump_size; struct user dump; #ifdef __alpha__ # define START_DATA(u) (u.start_data) #elif defined(CONFIG_ARM) # define START_DATA(u) ((u.u_tsize << PAGE_SHIFT) + u.start_code) #else # define START_DATA(u) (u.u_tsize << PAGE_SHIFT) #endif if (!current->dumpable || current->mm->count != 1) return 0; current->dumpable = 0; /* See if we have enough room to write the upage. */ if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE) return 0; fs = get_fs(); set_fs(KERNEL_DS); memcpy(corefile,"core.",5); #if 0 memcpy(corefile+5,current->comm,sizeof(current->comm)); #else corefile[4] = '\0'; #endif if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) { inode = NULL; goto end_coredump; } if (!S_ISREG(inode->i_mode)) goto end_coredump; if (!inode->i_op || !inode->i_op->default_file_ops) goto end_coredump; if (get_write_access(inode)) goto end_coredump; file.f_mode = 3; file.f_flags = 0; file.f_count = 1; file.f_inode = inode; file.f_pos = 0; file.f_reada = 0; file.f_op = inode->i_op->default_file_ops; if (file.f_op->open) if (file.f_op->open(inode,&file)) goto done_coredump; if (!file.f_op->write) goto close_coredump; has_dumped = 1; current->flags |= PF_DUMPCORE; strncpy(dump.u_comm, current->comm, sizeof(current->comm)); dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump))); dump.signal = signr; dump_thread(regs, &dump); /* If the size of the dump file exceeds the rlimit, then see what would happen if we wrote the stack, but not the data area. */ if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_dsize = 0; /* Make sure we have enough room to write the stack and data areas. */ if ((dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_ssize = 0; /* make sure we actually have a data and stack area to dump */ set_fs(USER_DS); if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT)) dump.u_dsize = 0; if (verify_area(VERIFY_READ, (void *) dump.start_stack, dump.u_ssize << PAGE_SHIFT)) dump.u_ssize = 0; set_fs(KERNEL_DS); /* struct user */ DUMP_WRITE(&dump,sizeof(dump)); /* Now dump all of the user data. Include malloced stuff as well */ DUMP_SEEK(PAGE_SIZE); /* now we start writing out the user space info */ set_fs(USER_DS); /* Dump the data area */ if (dump.u_dsize != 0) { dump_start = START_DATA(dump); dump_size = dump.u_dsize << PAGE_SHIFT; DUMP_WRITE(dump_start,dump_size); } /* Now prepare to dump the stack area */ if (dump.u_ssize != 0) { dump_start = dump.start_stack; dump_size = dump.u_ssize << PAGE_SHIFT; DUMP_WRITE(dump_start,dump_size); } /* Finally dump the task struct. Not be used by gdb, but could be useful */ set_fs(KERNEL_DS); DUMP_WRITE(current,sizeof(*current)); close_coredump: if (file.f_op->release) file.f_op->release(inode,&file); done_coredump: put_write_access(inode); end_coredump: set_fs(fs); iput(inode); return has_dumped; }