mirror of
https://github.com/gnustep/apps-projectcenter.git
synced 2025-02-21 02:41:18 +00:00
550 lines
13 KiB
Objective-C
550 lines
13 KiB
Objective-C
/*
|
|
** PCDebugger.m
|
|
**
|
|
** Copyright (c) 2008-2021
|
|
**
|
|
** Author: Gregory Casamento <greg.casamento@gmail.com>
|
|
** Riccardo Mottola <rm@gnu.org>>
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation; either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#ifdef __MINGW32__
|
|
#undef _WIN32_WINNT
|
|
#define _WIN32_WINNT 0x0501 // Minimal target is Windows XP
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
#import <AppKit/AppKit.h>
|
|
#import "PCDebugger.h"
|
|
#import "PCDebuggerView.h"
|
|
|
|
#import <ProjectCenter/PCProjectManager.h>
|
|
#import <ProjectCenter/PCEditorManager.h>
|
|
#import "PCAppController.h"
|
|
|
|
#import "Modules/Preferences/EditorFSC/PCEditorFSCPrefs.h"
|
|
#import "PCDebuggerWrapperProtocol.h"
|
|
#import "GDBWrapper.h"
|
|
|
|
|
|
#ifndef NOTIFICATION_CENTER
|
|
#define NOTIFICATION_CENTER [NSNotificationCenter defaultCenter]
|
|
#endif
|
|
|
|
static NSImage *goImage = nil;
|
|
static NSImage *pauseImage = nil;
|
|
static NSImage *continueImage = nil;
|
|
static NSImage *restartImage = nil;
|
|
static NSImage *nextImage = nil;
|
|
static NSImage *stepInImage = nil;
|
|
static NSImage *stepOutImage = nil;
|
|
static NSImage *upImage = nil;
|
|
static NSImage *downImage = nil;
|
|
|
|
NSString *PCBreakTypeKey = @"BreakType";
|
|
NSString *PCBreakTypeByLine = @"BreakTypeLine";
|
|
NSString *PCBreakTypeMethod = @"BreakTypeMethod";
|
|
NSString *PCBreakMethod = @"BreakMethod";
|
|
NSString *PCBreakFilename = @"BreakFilename";
|
|
NSString *PCBreakLineNumber = @"BreakLineNumber";
|
|
NSString *PCDBDebuggerStartedNotification = @"PCDBDebuggerStartedNotification";
|
|
|
|
@implementation PCDebugger
|
|
+ (void) initialize
|
|
{
|
|
if (self == [PCDebugger class])
|
|
{
|
|
NSBundle *bundle;
|
|
NSString *path;
|
|
|
|
bundle = [NSBundle bundleForClass: self];
|
|
path = [bundle pathForImageResource: @"go_button"];
|
|
if (path != nil)
|
|
{
|
|
goImage = [[NSImage alloc] initWithContentsOfFile: path];
|
|
}
|
|
path = [bundle pathForImageResource: @"pause_button"];
|
|
if (path != nil)
|
|
{
|
|
pauseImage = [[NSImage alloc] initWithContentsOfFile: path];
|
|
}
|
|
path = [bundle pathForImageResource: @"continue_button"];
|
|
if (path != nil)
|
|
{
|
|
continueImage = [[NSImage alloc] initWithContentsOfFile: path];
|
|
}
|
|
path = [bundle pathForImageResource: @"restart_button"];
|
|
if (path != nil)
|
|
{
|
|
restartImage = [[NSImage alloc] initWithContentsOfFile: path];
|
|
}
|
|
path = [bundle pathForImageResource: @"next_button"];
|
|
if (path != nil)
|
|
{
|
|
nextImage = [[NSImage alloc] initWithContentsOfFile: path];
|
|
}
|
|
path = [bundle pathForImageResource: @"stepin_button"];
|
|
if (path != nil)
|
|
{
|
|
stepInImage = [[NSImage alloc] initWithContentsOfFile: path];
|
|
}
|
|
path = [bundle pathForImageResource: @"stepout_button"];
|
|
if (path != nil)
|
|
{
|
|
stepOutImage = [[NSImage alloc] initWithContentsOfFile: path];
|
|
}
|
|
path = [bundle pathForImageResource: @"up_button"];
|
|
if (path != nil)
|
|
{
|
|
upImage = [[NSImage alloc] initWithContentsOfFile: path];
|
|
}
|
|
path = [bundle pathForImageResource: @"down_button"];
|
|
if (path != nil)
|
|
{
|
|
downImage = [[NSImage alloc] initWithContentsOfFile: path];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSFont *)consoleFont
|
|
{
|
|
NSUserDefaults *defs;
|
|
NSString *fontName;
|
|
CGFloat fontSize;
|
|
NSFont *font = nil;
|
|
|
|
defs = [NSUserDefaults standardUserDefaults];
|
|
fontName = [defs stringForKey:ConsoleFixedFont];
|
|
fontSize = [defs floatForKey:ConsoleFixedFontSize];
|
|
|
|
font = [NSFont fontWithName:fontName size:fontSize];
|
|
if (font == nil)
|
|
font = [NSFont userFixedPitchFontOfSize:0];
|
|
|
|
return font;
|
|
}
|
|
|
|
- (id) init
|
|
{
|
|
if((self = [super init]) != nil)
|
|
{
|
|
NSLog(@"PCDebugger Init");
|
|
// initialization here...
|
|
if([NSBundle loadNibNamed: @"PCDebugger" owner: self] == NO)
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
[(PCDebuggerView *)debuggerView setDebugger:self];
|
|
debuggerWrapper = [[GDBWrapper alloc] init];
|
|
[debuggerWrapper setTextView:debuggerView];
|
|
[debuggerWrapper setDebugger:self];
|
|
[debuggerView setFont: [self consoleFont]];
|
|
|
|
subProcessId = 0;
|
|
lastInfoParsed = nil;
|
|
lastFileNameParsed = nil;
|
|
lastLineNumberParsed = NSNotFound;
|
|
|
|
breakpoints = nil;
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver: self
|
|
selector: @selector(handleNotification:)
|
|
name: PCDBDebuggerStartedNotification
|
|
object: nil];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(void) debugExecutableAtPath: (NSString *)filePath
|
|
withDebugger: (NSString *)debugger
|
|
{
|
|
ASSIGN(executablePath,filePath);
|
|
[debuggerWrapper setDebuggerPath: debugger];
|
|
[debuggerWindow setTitle: [NSString stringWithFormat: @"Debugger (%@)",filePath]];
|
|
[self show];
|
|
}
|
|
|
|
- (void) show
|
|
{
|
|
[debuggerWindow makeKeyAndOrderFront: self];
|
|
if (![debuggerWrapper debuggerStarted])
|
|
[self startDebugger];
|
|
}
|
|
|
|
- (void) startDebugger
|
|
{
|
|
[debuggerView runProgram: executablePath
|
|
inCurrentDirectory: [executablePath stringByDeletingLastPathComponent]
|
|
logStandardError: YES];
|
|
|
|
}
|
|
|
|
- (void) initBreakpoints
|
|
{
|
|
breakpoints = [[NSMutableArray alloc] init];
|
|
/* CRUDE EXAMPLES * TODO FIXME *
|
|
NSDictionary *dP;
|
|
NSLog(@"initing breakpoints");
|
|
|
|
dP = [NSDictionary dictionaryWithObjectsAndKeys: PCBreakTypeMethod, PCBreakTypeKey, @"[NSException raise]", PCBreakMethod, nil];
|
|
// [breakpoints addObject:dP];
|
|
dP = [NSDictionary dictionaryWithObjectsAndKeys: PCBreakTypeByLine, PCBreakTypeKey, @"AppController.m", PCBreakFilename, [NSNumber numberWithInt:100], PCBreakLineNumber, nil];
|
|
[breakpoints addObject:dP];
|
|
*/
|
|
[debuggerWrapper setBreakpoints:breakpoints];
|
|
}
|
|
|
|
- (void) debuggerSetup
|
|
{
|
|
[debuggerWrapper debuggerSetup];
|
|
}
|
|
|
|
- (void) handleNotification: (NSNotification *)notification
|
|
{
|
|
[self initBreakpoints];
|
|
[self debuggerSetup];
|
|
}
|
|
|
|
|
|
- (void) awakeFromNib
|
|
{
|
|
NSToolbar *toolbar = [(NSToolbar *)[NSToolbar alloc] initWithIdentifier: @"PCDebuggerToolbar"];
|
|
[toolbar setAllowsUserCustomization: NO];
|
|
[toolbar setDelegate: self];
|
|
[debuggerWindow setToolbar: toolbar];
|
|
RELEASE(toolbar);
|
|
|
|
[debuggerWindow setFrameAutosaveName: @"PCDebuggerWindow"];
|
|
[self setStatus: @"Idle."];
|
|
}
|
|
|
|
- (id <PCDebuggerWrapperProtocol>)debuggerWrapper
|
|
{
|
|
return debuggerWrapper;
|
|
}
|
|
|
|
- (NSWindow *)debuggerWindow
|
|
{
|
|
return debuggerWindow;
|
|
}
|
|
|
|
- (void)setDebuggerWindow: (NSWindow *)window
|
|
{
|
|
debuggerWindow = window;
|
|
}
|
|
|
|
- (NSView *)debuggerView
|
|
{
|
|
return debuggerView;
|
|
}
|
|
|
|
- (void)setDebuggerView: (id)view
|
|
{
|
|
debuggerView = view;
|
|
}
|
|
|
|
- (NSString *)executablePath
|
|
{
|
|
return executablePath;
|
|
}
|
|
|
|
- (void)setExecutablePath:(NSString *)p
|
|
{
|
|
ASSIGN(executablePath,p);
|
|
}
|
|
|
|
- (int) subProcessId
|
|
{
|
|
return subProcessId;
|
|
}
|
|
|
|
- (void) setSubProcessId: (int)pid
|
|
{
|
|
NSLog(@"PCDebugger setSubProcessId: %d", pid);
|
|
subProcessId = pid;
|
|
}
|
|
|
|
- (NSDictionary *)lastInfoParsed
|
|
{
|
|
return lastInfoParsed;
|
|
}
|
|
|
|
- (void)setSetInfoParsed: (NSDictionary *)dict
|
|
{
|
|
lastInfoParsed = dict;
|
|
}
|
|
|
|
- (NSString *)lastFileNameParsed
|
|
{
|
|
return lastFileNameParsed;
|
|
}
|
|
|
|
- (void) setLastFileNameParsed: (NSString *)fname
|
|
{
|
|
lastFileNameParsed = fname;
|
|
}
|
|
|
|
- (NSUInteger)lastLineNumberParsed
|
|
{
|
|
return lastLineNumberParsed;
|
|
}
|
|
|
|
- (void)setLastLineNumberParsed: (NSUInteger)num
|
|
{
|
|
lastLineNumberParsed = num;
|
|
}
|
|
|
|
- (void) updateEditor
|
|
{
|
|
PCAppController *controller = (PCAppController *)[NSApp delegate];
|
|
PCProjectManager *pm = [controller projectManager];
|
|
PCEditorManager *em = [pm editorManager];
|
|
[em gotoFile: lastFileNameParsed
|
|
atLine: lastLineNumberParsed];
|
|
}
|
|
|
|
// kill process
|
|
- (void) interrupt
|
|
{
|
|
if(subProcessId != 0)
|
|
{
|
|
#ifndef __MINGW32__
|
|
kill(subProcessId,SIGINT);
|
|
#else
|
|
HANDLE proc;
|
|
|
|
proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)subProcessId);
|
|
if (proc == NULL)
|
|
{
|
|
DWORD lastError = GetLastError();
|
|
NSLog(@"error opening process %lu", (unsigned long)lastError);
|
|
return;
|
|
}
|
|
if (DebugBreakProcess(proc))
|
|
{
|
|
DWORD lastError = GetLastError();
|
|
NSLog(@"error sending break %lu", (unsigned long)lastError);
|
|
}
|
|
else
|
|
{
|
|
NSLog(@"break sent successfully");
|
|
}
|
|
CloseHandle(proc);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// action methods for toolbar...
|
|
- (void) go: (id) sender
|
|
{
|
|
/* each run makes a new PID but we parse it only if non-zero */
|
|
[self setSubProcessId:0];
|
|
[debuggerView putString: @"run\n"];
|
|
}
|
|
|
|
- (void) pause: (id) sender
|
|
{
|
|
[self setStatus: @"Stopped."];
|
|
[self interrupt];
|
|
}
|
|
|
|
- (void) continue: (id) sender
|
|
{
|
|
[debuggerView putString: @"continue\n"];
|
|
}
|
|
|
|
- (void) restart: (id) sender
|
|
{
|
|
[self interrupt];
|
|
/* each run makes a new PID but we parse it only if non-zero */
|
|
[self setSubProcessId:0];
|
|
[debuggerView putString: @"run\n"];
|
|
}
|
|
|
|
- (void) next: (id) sender
|
|
{
|
|
[debuggerView putString: @"next\n"];
|
|
}
|
|
|
|
- (void) stepInto: (id) sender
|
|
{
|
|
[debuggerView putString: @"step\n"];
|
|
}
|
|
|
|
- (void) stepOut: (id) sender
|
|
{
|
|
[debuggerView putString: @"finish\n"];
|
|
}
|
|
|
|
- (void) up: (id) sender
|
|
{
|
|
[debuggerView putString: @"up\n"];
|
|
}
|
|
|
|
- (void) down: (id) sender
|
|
{
|
|
[debuggerView putString: @"down\n"];
|
|
}
|
|
|
|
// Status..
|
|
- (void) setStatus: (NSString *) status
|
|
{
|
|
[statusField setStringValue: status];
|
|
}
|
|
|
|
- (NSString *) status
|
|
{
|
|
return [statusField stringValue];
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
[debuggerWrapper release];
|
|
[breakpoints release];
|
|
[super dealloc];
|
|
}
|
|
@end
|
|
|
|
@implementation PCDebugger (NSToolbarDelegate)
|
|
|
|
- (NSToolbarItem*)toolbar: (NSToolbar*)toolbar
|
|
itemForItemIdentifier: (NSString*)itemIdentifier
|
|
willBeInsertedIntoToolbar: (BOOL)flag
|
|
{
|
|
NSToolbarItem *toolbarItem = AUTORELEASE([[NSToolbarItem alloc]
|
|
initWithItemIdentifier: itemIdentifier]);
|
|
|
|
if([itemIdentifier isEqual: @"GoItem"])
|
|
{
|
|
[toolbarItem setLabel: @"Go"];
|
|
[toolbarItem setImage: goImage];
|
|
[toolbarItem setTarget: self];
|
|
[toolbarItem setAction: @selector(go:)];
|
|
[toolbarItem setTag: 0];
|
|
}
|
|
else if([itemIdentifier isEqual: @"PauseItem"])
|
|
{
|
|
[toolbarItem setLabel: @"Pause"];
|
|
[toolbarItem setImage: pauseImage];
|
|
[toolbarItem setTarget: self];
|
|
[toolbarItem setAction: @selector(pause:)];
|
|
[toolbarItem setTag: 1];
|
|
}
|
|
else if([itemIdentifier isEqual: @"ContinueItem"])
|
|
{
|
|
[toolbarItem setLabel: @"Continue"];
|
|
[toolbarItem setImage: continueImage];
|
|
[toolbarItem setTarget: self];
|
|
[toolbarItem setAction: @selector(continue:)];
|
|
[toolbarItem setTag: 1];
|
|
}
|
|
else if([itemIdentifier isEqual: @"RestartItem"])
|
|
{
|
|
[toolbarItem setLabel: @"Restart"];
|
|
[toolbarItem setImage: restartImage];
|
|
[toolbarItem setTarget: self];
|
|
[toolbarItem setAction: @selector(restart:)];
|
|
[toolbarItem setTag: 2];
|
|
}
|
|
else if([itemIdentifier isEqual: @"NextItem"])
|
|
{
|
|
[toolbarItem setLabel: @"Next"];
|
|
[toolbarItem setImage: nextImage];
|
|
[toolbarItem setTarget: self];
|
|
[toolbarItem setAction: @selector(next:)];
|
|
[toolbarItem setTag: 3];
|
|
}
|
|
else if([itemIdentifier isEqual: @"StepIntoItem"])
|
|
{
|
|
[toolbarItem setLabel: @"Step Into"];
|
|
[toolbarItem setImage: stepInImage];
|
|
[toolbarItem setTarget: self];
|
|
[toolbarItem setAction: @selector(stepInto:)];
|
|
[toolbarItem setTag: 4];
|
|
}
|
|
else if([itemIdentifier isEqual: @"StepOutItem"])
|
|
{
|
|
[toolbarItem setLabel: @"Step Out"];
|
|
[toolbarItem setImage: stepOutImage];
|
|
[toolbarItem setTarget: self];
|
|
[toolbarItem setAction: @selector(stepOut:)];
|
|
[toolbarItem setTag: 5];
|
|
}
|
|
else if([itemIdentifier isEqual: @"UpItem"])
|
|
{
|
|
[toolbarItem setLabel: @"Up"];
|
|
[toolbarItem setImage: upImage];
|
|
[toolbarItem setTarget: self];
|
|
[toolbarItem setAction: @selector(up:)];
|
|
[toolbarItem setTag: 6];
|
|
}
|
|
else if([itemIdentifier isEqual: @"DownItem"])
|
|
{
|
|
[toolbarItem setLabel: @"Down"];
|
|
[toolbarItem setImage: downImage];
|
|
[toolbarItem setTarget: self];
|
|
[toolbarItem setAction: @selector(down:)];
|
|
[toolbarItem setTag: 7];
|
|
}
|
|
|
|
return toolbarItem;
|
|
}
|
|
|
|
- (NSArray*) toolbarAllowedItemIdentifiers: (NSToolbar*)toolbar
|
|
{
|
|
return [NSArray arrayWithObjects: @"GoItem",
|
|
@"PauseItem",
|
|
@"ContinueItem",
|
|
@"RestartItem",
|
|
@"NextItem",
|
|
@"StepIntoItem",
|
|
@"StepOutItem",
|
|
@"UpItem",
|
|
@"DownItem",
|
|
nil];
|
|
}
|
|
|
|
- (NSArray*) toolbarDefaultItemIdentifiers: (NSToolbar*)toolbar
|
|
{
|
|
return [NSArray arrayWithObjects: @"GoItem",
|
|
@"PauseItem",
|
|
@"ContinueItem",
|
|
@"RestartItem",
|
|
@"NextItem",
|
|
@"StepIntoItem",
|
|
@"StepOutItem",
|
|
@"UpItem",
|
|
@"DownItem",
|
|
nil];
|
|
}
|
|
|
|
- (NSArray*) toolbarSelectableItemIdentifiers: (NSToolbar*)toolbar
|
|
{
|
|
return [NSArray arrayWithObjects: @"GoItem",
|
|
@"PauseItem",
|
|
@"ContinueItem",
|
|
@"RestartItem",
|
|
@"NextItem",
|
|
@"StepIntoItem",
|
|
@"StepOutItem",
|
|
@"UpItem",
|
|
@"DownItem",
|
|
nil];
|
|
}
|
|
@end
|