This is TellDisplayer.m in view mode; [Download] [Up]
#import <stdio.h> #import <Foundation/Foundation.h> #import "GdbManager.h" #import "DisplayMisc.h" #import "TellDisplayer.h" #import "ViewDisplayProvider_Protocol.h" #import "GuiDisplayProvider_Protocol.h" #import "debug.h" #import "gdb.h" #include <sys/param.h> #include <sys/stat.h> #include <fcntl.h> // gdbManager is the object which manages GDB and the thread it runs in. // This object communicates with the client (in another process) // and the DebuggerServer object in our process but in // another thread. static GdbManager *gdbManager = nil; // The autorelease pool is needed because the DO facilities use it. // Since the gdb thread isn't in a Run Loop, we have to manage // the pool ourself and when it gets released. NSAutoreleasePool *pool; int pool_num_times = 0; extern WindowHookFunction window_hook; static int disp_is_view; int setup_display_system(const char *connection_name) { pool = [[NSAutoreleasePool alloc] init]; if (connection_name) { const char *conn_host; const char *c; char new_conn[256]; char *nc; c = connection_name; nc = new_conn; conn_host = NULL; while (*c != '\0') { *nc = *c; if (*c == ':') { *nc = '\0'; conn_host = c + 1; connection_name = new_conn; break; } nc++; c++; } gdbManager = make_gui_gdb_manager(); [gdbManager setDisplayProviderConnectionName:connection_name host:conn_host]; disp_is_view = 0; } else { extern char *get_view_connection(); extern char *get_view_host(); gdbManager = make_view_gdb_manager(); [gdbManager setDisplayProviderConnectionName:get_view_connection() host:get_view_host()]; disp_is_view = 1; } #if 0 { /* utility code which causes gdb to wait. We can then attach with another gdb.*/ static volatile wait = 1; while (wait) { sleep(10); } } #endif if ([gdbManager establishConnection] == 0) { [gdbManager release]; [pool release]; return 0; } window_hook = [gdbManager windowHookFunction]; return 1; } void shut_down_display_system() { window_hook = NULL; if (gdbManager) { [gdbManager release]; gdbManager = nil; } if (pool) { [pool release]; pool_num_times = 0; pool = nil; } if (disp_is_view) (void)turn_off_viewing(); else { extern int do_display_lines; do_display_lines = 0; } } static void get_full_path_name(char *filename, char **fullname) { extern char *source_path; int fd; fd = openp (source_path, 0, filename, O_RDONLY, 0, fullname); if (fd > 0) close(fd); } // 'localException' is defined by NS_HANDLER #define EXCEPTION_MSG(func) \ NSLog(@"Exception sending remote message(%@); name: %@, reason: %@", \ func, [localException name], [localException reason]); void tell_displayer_display_lines(struct symtab *symtab, int first_line, int last_line) { id<ViewDisplayProvider> displayProvider; if (gdbManager == nil) return; if (symtab->fullname == NULL) get_full_path_name(symtab->filename, &symtab->fullname); NS_DURING { displayProvider = [gdbManager displayProviderForProtocol:@protocol(ViewDisplayProvider)]; if (displayProvider) { /* rooted path */ NSString *fileString = [NSString stringWithCString: symtab->fullname]; /* is this NSString malloc'd? is it freed? is it pooled? */ [displayProvider lineChangedForThread: -1 inFile: fileString atStartLine: first_line toEndLine: last_line]; } } NS_HANDLER { EXCEPTION_MSG(@"display_lines"); shut_down_display_system(); } NS_ENDHANDLER; return; } void tell_displayer_state_changed(DebuggerState newState) { id<ViewDisplayProvider> displayProvider; static DebuggerState prevState = DBG_STATE_NOT_ACTIVE; if (gdbManager == nil) return; /* This is a workaround. For some reason, the NeXT code calls us many (e.g. 8) times with newState == DBG_STATE_INFERIOR_RUNNING. This results in unnecessary DO communication and makes single stepping slow. So, don't send multiple messages with the same state. */ if ((newState == DBG_STATE_INFERIOR_RUNNING) && (newState == prevState)) return; prevState = newState; NS_DURING { displayProvider = [gdbManager displayProviderForProtocol:@protocol(ViewDisplayProvider)]; if (displayProvider) { [displayProvider inferiorStateChanged: newState]; } } NS_HANDLER { EXCEPTION_MSG(@"state_changed"); shut_down_display_system(); } NS_ENDHANDLER; return; } void tell_displayer_breakpoint_changed(struct breakpoint *bp, BreakpointState newState) { char fullname[2048], *fp; id<GuiDisplayProvider> displayProvider; if (gdbManager == nil) return; /* for now, only care about real breakpoints */ /* will need to deal with other types too */ if ((bp->number == 0) || (bp->type != bp_breakpoint)) return; #if 0 /* * the breakpoint structure no longer contains a symtab member. * Instead, it just has a char pointer that holds a file name * (which is evidently the main thing that the symtab member * was used for). */ if (bp->symtab->fullname == NULL) get_full_path_name(bp->symtab); #else /* 1 */ /* * I do not know whether the filename pointer of the breakpoint struct * is normally a full path or not. If it is not a full path, I do not * know what effect it might have, if we replaced it with a full path. * Since I don't know, for the time being I'm not going to do it. * * This means that we may be recomputing the full path over and over. * That needs to be addressed (FIXME). Moreover, I don't think that * the way get_full_path_name works (ie. by calling open) is very * efficient. MVS */ fp = bp->source_file; if (fp == NULL) return; else if (fp[0] != '/') { /* rooted path? */ get_full_path_name(fp, &fp); /* could copy back into bp if considered safe */ /* AND... the sonofabitch is malloc'd. We're leaking it. */ if ((fp == NULL) || (fp[0] != '/')) return; } #endif NS_DURING { displayProvider = [gdbManager displayProviderForProtocol:@protocol(GuiDisplayProvider)]; if (displayProvider) { /* rooted path */ NSString *fileString = [NSString stringWithCString: fp]; /* full path */ [displayProvider breakpointChanged:bp->number newState:newState inFile:fileString atLine:bp->line_number]; } } NS_HANDLER { EXCEPTION_MSG(@"breakpoint_changed"); shut_down_display_system(); } NS_ENDHANDLER; return; } void tell_displayer_frame_changed(int newFrame) { id<GuiDisplayProvider> displayProvider; if (gdbManager == nil) return; NS_DURING { displayProvider = [gdbManager displayProviderForProtocol:@protocol(GuiDisplayProvider)]; if (displayProvider) { [displayProvider frameChanged: newFrame]; } } NS_HANDLER { EXCEPTION_MSG(@"frame_changed"); shut_down_display_system(); } NS_ENDHANDLER; return; } #define STACK_LIMIT (99) void tell_displayer_stack_changed() { id<GuiDisplayProvider> displayProvider; struct frame_info *frame0; int numFrames; struct frame_info *f; BOOL maxedOut; if (gdbManager == nil) return; frame0 = get_current_frame(); if (frame0 == NULL) { /* no stack... */ return; } /* count how many frames there are; include frame 0, so start at 1*/ numFrames = 1; maxedOut = NO; for (f = get_prev_frame(frame0); f && (f != frame0); f = get_prev_frame(f)) { numFrames++; if (numFrames >= STACK_LIMIT) { maxedOut = YES; break; } } NS_DURING { displayProvider = [gdbManager displayProviderForProtocol:@protocol(GuiDisplayProvider)]; if (displayProvider) { [displayProvider stackChanged:numFrames limitReached:maxedOut]; } } NS_HANDLER { EXCEPTION_MSG(@"stack_changed"); shut_down_display_system(); } NS_ENDHANDLER; return; } void gui_inferior_stopped(int newFrame /* true current frame is different from previous one */ ) { }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.