This is threads.m in view mode; [Download] [Up]
/* Print and select threads for GDB, the GNU debugger, on Mach TT systems. Copyright (C) 1986, 1987 Free Software Foundation, Inc. GDB is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the GDB General Public License for full details. Everyone is granted permission to copy, modify and redistribute GDB, but only under the conditions described in the GDB General Public License. A copy of this license is supposed to have been given to you along with GDB so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. In other words, go ahead and share GDB, but don't try to stop anyone else from sharing it farther. Help stamp out software hoarding! */ #import "gdb.h" #import "stdio.h" #define KERNEL_FEATURES #import <sys/param.h> #import <sys/dir.h> /* #import <bsd/hppa/label_t.h> */ #import <sys/user.h> #import <mach/cthreads.h> #define MTHREAD #import "cthread_internals.h" extern RegionManager *regionManager; static int otherThreadsSuspended = FALSE; static thread_array_t threadList = NULL; static int threadCount = 0; static int abortThreads = 0; CORE_ADDR dontSuspendThreadAddress = 0xFFFFFFFF; static thread_t exceptionThread = 0; extern task_t inferior_task; extern thread_t current_thread, step_thread, last_current_thread; #import "threads.h" #ifdef NO_SINGLE_STEP extern int one_stepped; /* From machine dependent code */ extern void single_step (); /* Same. */ #endif /* NO_SINGLE_STEP */ static char translate_state(int state) { switch (state) { case TH_STATE_RUNNING: return('R'); case TH_STATE_STOPPED: return('S'); case TH_STATE_WAITING: return('W'); case TH_STATE_UNINTERRUPTIBLE: return('U'); case TH_STATE_HALTED: return('H'); default: return('?'); } } char * getThreadNameFromState(USER_REG_STRUCT *userRegState, int n) { static char buf[10]; ur_cthread_t userReg; cthread_t incarnation; char *name; if ((userReg = WARP((ur_cthread_t)(USER_REG(*userRegState)))) && (incarnation = WARP(userReg->incarnation)) && (name = WARPSTRING((char *)incarnation->name))) return name; else { sprintf(buf, "_t%d", n); return buf; } } static char * get_thread_name(thread_t th, int n) { USER_REG_STRUCT threadState; unsigned int threadStateCount = USER_REG_COUNT; mach_call( thread_get_state(th, USER_REG_STATE, (thread_state_t)&threadState, &threadStateCount), "thread_get_state", "get_thread_name"); return getThreadNameFromState(&threadState, n); } CORE_ADDR getThreadPCAndNameFromState(REGS_STRUCT *regsState, char **pName) { struct minimal_symbol *minSym = lookup_minimal_symbol_by_pc(PC_FIELD(*regsState));; *pName = minSym ? SYMBOL_NAME(minSym) : "??"; return PC_FIELD(*regsState); } static CORE_ADDR get_thread_pc_and_name(thread_t th, char **pName) { REGS_STRUCT regsState; unsigned regsCount = REGS_COUNT; mach_call(thread_get_state(th, REGS_STATE, (thread_state_t)®sState, ®sCount), "thread_get_state", "get_thread_pc_and_name"); return getThreadPCAndNameFromState(®sState, pName); } void thread_list_command() { int i, current_thread_index; thread_basic_info_data_t ths; char *name, *fName; CORE_ADDR pc; unsigned int size; extern thread_t get_debug_thread(); thread_t debug_thread = 0; /* Identify the dyld debugging thread */ if (!inferior_pid) { core_thread_list(); return; } if (!threadList) mach_call(task_threads(inferior_task, &threadList, &threadCount), "task_threads", "thread_list_command"); if (threadCount == 1) printf("There is 1 thread.\n"); else { printf("There are %d threads.\n", threadCount); if (threadCount == 0) return; /* nothing more to do. */ debug_thread = get_debug_thread(inferior_task); } printf("Thread State Suspend Port PC Name Function\n"); for (i = 0; i < threadCount; i++) { if (threadList[i] == current_thread) current_thread_index = i; size = THREAD_BASIC_INFO_COUNT; mach_call(thread_info(threadList[i], THREAD_BASIC_INFO, (thread_info_t)&ths, &size), "thread_info", "thread_list_command"); name = get_thread_name(threadList[i], i); pc = get_thread_pc_and_name(threadList[i], &fName); if (threadList[i] == debug_thread) { name = "gdb dynamic lib"; /* MVS: identify the dyld */ fName = "debugging thread"; /* debugging thread */ } printf ("%-6d %c %-7d 0x%-8x 0x%-8x %-15s %-20s\n", i, translate_state (ths.run_state), ths.suspend_count, threadList[i], pc, name, fName); } printf("\nThe current thread is thread %d.\n", current_thread_index); } void thread_select_command(char *args, int from_tty) { int thread_index; kern_return_t ret; extern struct symbol *step_start_function; extern int stop_soon_quietly; extern int stop_print_frame; if (!inferior_pid) { core_thread_select(args, from_tty); } else { if (!args) error_no_arg ("thread index to select"); thread_index = atoi(args); if (thread_index < 0) { error ("no such thread"); return; } if (!threadList) mach_call(task_threads(inferior_task, &threadList, &threadCount), "task_threads", "thread_select_command"); if (thread_index >= threadCount) { error ("no such thread"); return; } current_thread = last_current_thread = threadList[thread_index]; } flush_cached_frames(); registers_changed (); stop_pc = read_pc(); step_start_function = find_pc_function(stop_pc); stop_soon_quietly = 1; stop_print_frame = 1; bpstat_clear (&stop_bpstat); normal_stop (); } void set_trace_bit (thread_t thread) { unsigned int stateCnt = TRACE_COUNT; kern_return_t ret; TRACE_STRUCT state; step_thread = thread; #ifdef NO_SINGLE_STEP one_stepped = 0; single_step(0); #else mach_call(thread_get_state(thread, TRACE_STATE, (thread_state_t)&state, &stateCnt), "thread_get_state", "set_trace_bit"); if (!TRACE_BIT_SET(state)) { SET_TRACE_BIT(state); if (!stopped_in_ptrace) mach_call(thread_abort(thread), "thread_abort", "set_trace_bit"); mach_call(thread_set_state(thread, TRACE_STATE, (thread_state_t)&state, stateCnt), "thread_set_state", "set_trace_bit"); } #endif NO_SINGLE_STEP } void clear_trace_bit (thread_t thread) { unsigned int stateCnt = TRACE_COUNT; kern_return_t ret; TRACE_STRUCT state; step_thread = 0; #ifdef NO_SINGLE_STEP if (one_stepped) single_step(0); #else mach_call(thread_get_state(thread, TRACE_STATE, (thread_state_t)&state, &stateCnt), "thread_get_state", "clear_trace_bit"); if (TRACE_BIT_SET(state)) { // printf("Clearing trace bit.\n"); CLEAR_TRACE_BIT(state); if (!stopped_in_ptrace) mach_call(thread_abort(thread), "thread_abort", "clear_trace_bit"); mach_call(thread_set_state(thread, TRACE_STATE, (thread_state_t)&state, stateCnt), "thread_set_state", "clear_trace_bit"); } #endif NO_SINGLE_STEP } void clearThreadState() { step_thread = 0; otherThreadsSuspended = FALSE; } void prepare_threads_before_run(int step) { int i; thread_basic_info_data_t ths; unsigned int size; thread_t thread; if (!threadList) mach_call(task_threads(inferior_task, &threadList, &threadCount), "task_threads", "prepare_threads_before_run"); if (step_range_end) { for (i = 0; i < threadCount; i++) { thread = threadList[i]; size = THREAD_BASIC_INFO_COUNT; mach_call(thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&ths, &size), "thread_info", "prepare_threads_before_run"); if (thread != exceptionThread) { if (thread == current_thread) { if (ths.suspend_count) mach_call(thread_resume(thread), "thread_resume", "prepare_threads_before_run"); } else { if (!ths.suspend_count) { mach_call(thread_suspend(thread), "thread_suspend", "prepare_threads_before_run"); otherThreadsSuspended = TRUE; } } } } } else { if (otherThreadsSuspended) { for (i = 0; i < threadCount; i++) thread_resume(threadList[i]); otherThreadsSuspended = FALSE; } } /* This can be used to set anything interesting about the thread * just before it gets run. */ #ifdef SET_THREADSTATE_BEFORE_RUN for (i = 0; i < threadCount; i++) SET_THREADSTATE_BEFORE_RUN(threadList[i]); #endif if (step_thread) clear_trace_bit(step_thread); if (step) set_trace_bit(current_thread); vm_deallocate(task_self(), (vm_address_t)threadList, (threadCount * sizeof(int))); threadList = NULL; } void prepare_threads_after_stop() { int i; static int firstTime = NO; if (firstTime) { firstTime = NO; } else if (abortThreads) { mach_call(task_threads(inferior_task, &threadList, &threadCount), "task_threads", "prepare_threads_after_stop"); for (i = 0; i < threadCount; i++) { if (!stopped_in_ptrace) mach_call(thread_abort(threadList[i]), "thread_abort", "prepare_threads_after_stop"); } } } void dontSuspendThread() { exceptionThread = current_thread; thread_resume(exceptionThread); current_thread = last_current_thread; } const static char breakpoint_insn[] = BREAKPOINT; static char oldBreakpointData[sizeof(breakpoint_insn) / sizeof(*breakpoint_insn)]; void insertNoSuspendBreakpoint() { struct minimal_symbol *minSym; if (minSym = lookup_minimal_symbol("tellDebuggerNotToSuspend", NULL, NULL)) { dontSuspendThreadAddress = SYMBOL_VALUE_ADDRESS(minSym); [regionManager getDataAt: (void *)dontSuspendThreadAddress for: sizeof(breakpoint_insn) into: (void *)oldBreakpointData]; [regionManager putDataAt: (void *)dontSuspendThreadAddress for: sizeof(breakpoint_insn) from: (void *)breakpoint_insn]; } } void _initialize_threads () { add_com ("thread-select", class_stack, thread_select_command, "Select and print a thread."); add_com_alias ("ts", "thread-select", class_stack, 0); add_com ("thread-list", class_stack, thread_list_command, "List all of threads."); add_com_alias ("tl", "thread-list", class_stack, 0); add_show_from_set( add_set_cmd("abort-threads", class_obscure, var_boolean, (char *)&abortThreads, "Set if gdb should abort all threads after stop.", &setlist), &showlist); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.