This is GuiGdbManager.m in view mode; [Download] [Up]
#import <Foundation/Foundation.h> #import "GuiGdbManager.h" #import "GuiDisplayProvider_Protocol.h" #import "DisplayMisc.h" #import "NSDistantObjectExtras.h" #import "gdb.h" #import <sys/ioctl.h> #define DEBUG_MAIN; #import "debug.h" #ifdef DEBUG FILE *debug_stream; #endif static void gui_display_window_hook(FILE *instream, char **prompt); @implementation GdbCmd - initWithCmd:(NSString*)c ofType:(Gdb_cmd_type)t { return [self initWithCmd:c ofType:t useTty:NO useAnnotation:NO]; } - initWithCmd:(NSString*)c ofType:(Gdb_cmd_type)t useTty:(BOOL) tty useAnnotation:(BOOL)anno { return [self initWithCmd:c ofType:t useTty:tty useAnnotation:anno catchOutput:NO]; } - initWithCmd:(NSString*)c ofType:(Gdb_cmd_type)t useTty:(BOOL) tty useAnnotation:(BOOL)annotation catchOutput:(BOOL)catch { [super init]; cmd = c; if (cmd != nil) [cmd retain]; type = t; useTty = tty; useAnnotation = annotation; catchOutput = catch; next = nil; return self; } - (void) dealloc { [cmd release]; } - (Gdb_cmd_type)getType { return type; } - (NSString *)getCmd { return cmd; } - (BOOL) useTty { return useTty; } - (BOOL) useAnnotation { return useAnnotation; } - (BOOL)catchOutput { return catchOutput; } @end // // To get started, the main thread sticks info into GuiGdbManager // which is then read by the Debugger Controller thead. GuiGdbManager, // in the main thread, waits until it is given a display provider // before it proceeds; // then it goes into command processing. // @implementation GuiGdbManager - init { [super init]; controller = nil; cmdQLock = [[NSConditionLock alloc] init]; cmdQHead = nil; execLock = [[NSConditionLock alloc] init]; displayProviderLock = [[NSConditionLock alloc] init]; DEBUG_INIT; #ifdef DEBUG debug_stream = stderr; #endif return self; } - (void) setDebuggerControllerConnectionName:(NSString *)n { controllerConnectionName = n; [controllerConnectionName retain]; } #define PROVIDER_NOT_AVAILABLE 0 #define PROVIDER_AVAILABLE 1 // called from controller thread; tells gdb thread a provider is available - (void) setDisplayProvider:(id)dP { [displayProviderLock lock]; [super setDisplayProvider: dP]; [displayProviderLock unlockWithCondition: PROVIDER_AVAILABLE]; DEBUG_PRINT("gdbManager: just set the provider and unlocked\n"); } // // called from gdb thread. // - (int) establishConnection { NSDistantObject *c; int i; fork_and_start_debugger_controller(self); DEBUG_PRINT("gdbManager: waiting for the PROVIDER to become available\n"); [displayProviderLock lockWhenCondition: PROVIDER_AVAILABLE]; [displayProviderLock unlock]; #if 0 // Dec 1995: this workaround no longer needed // workaround: the DO info for the display provider is valid // for the other (controller) thread; we have to make correct // for our thread. displayProvider = [(NSDistantObject *)displayProvider proxyWithProperConnection]; #endif /* Now, we, the gdb thread, and the debugger controller will only communicate via DO or the command queue. Most of our data is now Read-Only so we don't use locks to access it. */ for (i = 0; i < 10; i++) { c = [NSConnection rootProxyForConnectionWithRegisteredName: controllerConnectionName host: nil]; if (c) break; } if (c == nil) { NSLog(@"GuiGdbManager: could not get connection to debugger controller"); return 0; } [c setProtocolForProxy:@protocol(DebuggerControllerInternal)]; controller = (id<DebuggerControllerInternal>) c; [controller retain]; #if 1 displayProvider = [[controller displayProvider] retain]; #endif DEBUG_PRINT("gdbManager: waitForClient: got client & controller DO connection\n"); return 1; } - (void) tellControllerWeAreReadyForInput { [controller gdbReadyForInput]; } - (WindowHookFunction) windowHookFunction { return gui_display_window_hook; } // // Implementation of the GdbManagerExecLock protocol // - (void) lockExecLock { [execLock lock]; } - (void) unlockExecLock { [execLock unlock]; } #define NO_CMD 0 #define CMD_AVAILABLE 1 - (void)enqueueCmd:(GdbCmd*)newCmd { GdbCmd *cmd; [cmdQLock lock]; cmd = cmdQHead; if (cmd == nil) { cmdQHead = newCmd; } else { // we expect the cmd queue will be short; // so just find the end each time while (cmd->next != nil) { cmd = cmd->next; } cmd->next = newCmd; } [cmdQLock unlockWithCondition: CMD_AVAILABLE]; } - (GdbCmd*) dequeueCmd { GdbCmd *cmd; DEBUG_PRINT("gdbManager dequeCmd: waiting for command\n"); [cmdQLock lockWhenCondition: CMD_AVAILABLE]; cmd = cmdQHead; cmdQHead = cmd->next; if (cmdQHead) [cmdQLock unlockWithCondition: CMD_AVAILABLE]; else [cmdQLock unlockWithCondition: NO_CMD]; DEBUG_PRINT("gdbManager dequeCmd: got command\n"); return cmd; } // execute a gdb command; assumes we have the exec lock static void noop (foo) int foo; { } static int useTty = 0; static int catchOutput = 0; NSMutableString* stdoutOutput = nil; NSMutableString* stderrOutput = nil; NSMutableString* annotationOutput = nil; /* This variable is set to annotationOutput in -executeCommand: if the annotation is used. Otherwise it is set to nil. */ NSMutableString* annotationString = nil; static void my_fputs_unfiltered_hook(const char *linebuffer, FILE *stream) { id string; if (annotationString) string = annotationString; else if (stream == stdout) string = stdoutOutput; else if (stream == stderr) string = stderrOutput; else string = nil; [string appendString:[NSString stringWithCString:linebuffer]]; } static void execute_command_for_PB(char *command) { struct cleanup *old_chain = make_cleanup (noop, 0); execute_command(command, useTty); bpstat_do_actions (&stop_bpstat); do_cleanups (old_chain); } + (void)initialize { stdoutOutput = [NSMutableString new]; stderrOutput = [NSMutableString new]; annotationOutput = [NSMutableString new]; } -(void)executeCommand: (GdbCmd *)command { int wasError; const char *cmd; int old_verbose; extern int info_verbose; extern annotation_level; void (*old_fputs_hook)(const char*, FILE*) = fputs_unfiltered_hook; catchOutput = (int)[command catchOutput]; if (catchOutput) { fputs_unfiltered_hook = my_fputs_unfiltered_hook; [stdoutOutput setString:@""]; [stderrOutput setString:@""]; [annotationOutput setString:@""]; annotationString = annotationOutput; } else annotationString = nil; cmd = [[command getCmd] cString]; if ([command useAnnotation]) { annotation_level = 2; printf_unfiltered("\n\032\032annotation-begin\n"); } useTty = (int)[command useTty]; old_verbose = info_verbose; info_verbose = 0; catch_errors_was_error(execute_command_for_PB, cmd, &wasError, RETURN_MASK_ALL); info_verbose = old_verbose; if ([command useAnnotation]) { annotation_level = 0; printf_unfiltered("\n\032\032annotation-end\n"); } if (catchOutput) { id client = [self displayProviderForProtocol:@protocol(GuiDisplayProvider2)]; [client outputFromGDB:stdoutOutput type:GDB_OUTPUT_STDOUT]; [client outputFromGDB:stderrOutput type:GDB_OUTPUT_STDERR]; [client outputFromGDB:annotationOutput type:GDB_OUTPUT_ANNOTATION]; fputs_unfiltered_hook = old_fputs_hook; } if (wasError) { // fprintf(stderr, "Error occured processing DO command.\n"); } fflush(stdout); fflush(stderr); } @end static GuiGdbManager *guiGdbManager; GdbManager * make_gui_gdb_manager() { return (guiGdbManager = [[GuiGdbManager alloc] init]); } static void gui_display_window_hook(FILE *instream, char **prompt) { static int lock_is_pending = 0; // true if we have the lock GdbCmd *cmd; extern int noprompt; DEBUG_PRINT("in WindowHook\n"); // we will block waiting for input. So first we // send out prompt (if is OK to do so); if (noprompt == 0) fputs(*prompt, stdout); *prompt = NULL; // disable outputing of prompt by main cmd loop fflush(stdout); { int bytesAvail; int retVal; /* in our configuration, we know stdin is a pipe; FIONREAD may not work correctly on a pty. */ retVal = ioctl(0, FIONREAD, &bytesAvail); if (retVal < 0) { NSLog(@"gdb: GuiGdbManager: FIONREAD ioctl fails."); return; } if (bytesAvail > 0) return; /* keep processing stdin until it is empty */ } [guiGdbManager tellControllerWeAreReadyForInput]; if (lock_is_pending) { [guiGdbManager unlockExecLock]; lock_is_pending = 0; } // process cmds from server; will block waiting for cmds while (cmd = [guiGdbManager dequeueCmd]) { if ((++pool_num_times) >= POOL_RELEASE_MAX_TIMES) { [pool release]; pool_num_times = 0; pool = [[NSAutoreleasePool alloc] init]; } switch ([cmd getType]) { case GDB_CMD_EXEC: [guiGdbManager lockExecLock]; [guiGdbManager executeCommand:cmd]; #ifdef DEBUG { char buff[512]; sprintf(buff, "got command: %s\n", [[cmd getCmd] cString]); DEBUG_PRINT(buff); } #endif [guiGdbManager unlockExecLock]; [cmd release]; break; case GDB_CMD_INPUT_PENDING: [guiGdbManager lockExecLock]; [cmd release]; lock_is_pending = 1; return; // return to gdb tty-base IO & command processing default: //FIXME: report an error here break; } // end switch } // end while }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.