Revert "Instead of directly calling stack_get, get the depth first and then call...
[macgdbp.git] / Source / DebuggerConnection.m
1 /*
2 * MacGDBp
3 * Copyright (c) 2002 - 2007, Blue Static <http://www.bluestatic.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17 #import "DebuggerConnection.h"
18
19 @implementation DebuggerConnection
20
21 /**
22 * Creates a new DebuggerConnection and initializes the socket from the given connection
23 * paramters.
24 */
25 - (id)initWithPort: (int)port session: (NSString *)session
26 {
27 if (self = [super init])
28 {
29 _port = port;
30 _session = [session retain];
31 _connected = NO;
32
33 _windowController = [[DebuggerWindowController alloc] initWithConnection: self];
34 [[_windowController window] makeKeyAndOrderFront: self];
35
36 // now that we have our host information, open the socket
37 _socket = [[SocketWrapper alloc] initWithPort: port];
38 [_socket setDelegate: self];
39 [_windowController setStatus: @"Connecting"];
40 [_socket connect];
41
42 // clean up after ourselves
43 [[NSNotificationCenter defaultCenter] addObserver: self
44 selector: @selector(applicationWillTerminate:)
45 name: NSApplicationWillTerminateNotification
46 object: NSApp];
47 }
48 return self;
49 }
50
51 /**
52 * Release ourselves when we're about to die
53 */
54 - (void)applicationWillTerminate: (NSNotification *)notif
55 {
56 [self release];
57 }
58
59 /**
60 * Releases all of the object's data members and closes the streams
61 */
62 - (void)dealloc
63 {
64 [_session release];
65 [_socket release];
66
67 [super dealloc];
68 }
69
70 /**
71 * Gets the port number
72 */
73 - (int)port
74 {
75 return _port;
76 }
77
78 /**
79 * Gets the session name
80 */
81 - (NSString *)session
82 {
83 return _session;
84 }
85
86 /**
87 * Returns the name of the remote host
88 */
89 - (NSString *)remoteHost
90 {
91 if (!_connected)
92 {
93 return @"(DISCONNECTED)";
94 }
95 return [_socket remoteHost];
96 }
97
98 /**
99 * SocketWrapper delegate method that is called whenever new data is received
100 */
101 - (void)dataReceived: (NSString *)response deliverTo: (SEL)selector
102 {
103 NSLog(@"receive = %@", response);
104 // if the caller of [_socket receive:] specified a deliverTo, just forward the message to them
105 if (selector != nil)
106 {
107 [self performSelector: selector withObject: response];
108 }
109 }
110
111 /**
112 * SocketWrapper delegate method that is called after data is sent. This really
113 * isn't useful for much.
114 */
115 - (void)dataSent: (NSString *)data
116 {
117 NSLog(@"send = %@", data);
118 }
119
120 /**
121 * Called by SocketWrapper after the connection is successful. This immediately calls
122 * -[SocketWrapper receive] to clear the way for communication
123 */
124 - (void)socketDidAccept
125 {
126 _connected = YES;
127 [_socket receive: @selector(_handshake:)];
128 }
129
130 /**
131 * Receives errors from the SocketWrapper and updates the display
132 */
133 - (void)errorEncountered: (NSError *)error
134 {
135 [_windowController setError: [error domain]];
136 }
137
138 /**
139 * The initial packet handshake. This allows us to set things like the title of the window
140 * and glean information about hte server we are debugging
141 */
142 - (void)_handshake: (NSString *)packet
143 {
144 [self refreshStatus];
145 }
146
147 /**
148 * Handler used by dataReceived:deliverTo: for anytime the status command is issued. It sets
149 * the window controller's status text
150 */
151 - (void)_updateStatus: (NSString *)packet
152 {
153 NSXMLDocument *doc = [[NSXMLDocument alloc] initWithXMLString: packet options: NSXMLDocumentTidyXML error: nil];
154 [_windowController setStatus: [[[[doc rootElement] attributeForName: @"status"] stringValue] capitalizedString]];
155 [doc release];
156 }
157
158 /**
159 * Tells the debugger to continue running the script
160 */
161 - (void)run
162 {
163 [_socket send: [self _createCommand: @"run"]];
164 [self refreshStatus];
165 }
166
167 /**
168 * Method that runs tells the debugger to give us its status. This will call _updateStatus
169 * and will update the status text on the window
170 */
171 - (void)refreshStatus
172 {
173 [_socket send: [self _createCommand: @"status"]];
174 [_socket receive: @selector(_updateStatus:)];
175 }
176
177 /**
178 * Tells the debugger to step into the current command.
179 */
180 // TODO: populate the stack trace and registers list
181 - (void)stepIn
182 {
183 [_socket send: [self _createCommand: @"step_into"]];
184 [_socket receive: nil];
185 [self refreshStatus];
186 [self updateStackTraceAndRegisters];
187 }
188
189 /**
190 * This function queries the debug server for the current stacktrace and all the registers on
191 * level one. If a user then tries to expand past level one... TOOD: HOLY CRAP WHAT DO WE DO PAST LEVEL 1?
192 */
193 - (void)updateStackTraceAndRegisters
194 {
195 [_socket send: [self _createCommand: @"stack_get"]];
196 [_socket receive: @selector(_stackReceived:)];
197 }
198
199 /**
200 * Called by the dataReceived delivery delegate. This updates the window controller's data
201 * for the stack trace
202 */
203 - (void)_stackReceived: (NSString *)packet
204 {
205 NSXMLDocument *doc = [[NSXMLDocument alloc] initWithXMLString: packet options: NSXMLDocumentTidyXML error: nil];
206 NSArray *children = [[doc rootElement] children];
207 NSMutableArray *stack = [NSMutableArray array];
208 NSMutableDictionary *dict = [NSMutableDictionary dictionary];
209 for (int i = 0; i < [children count]; i++)
210 {
211 NSArray *attrs = [[children objectAtIndex: i] attributes];
212 for (int j = 0; j < [attrs count]; j++)
213 {
214 [dict setValue: [[attrs objectAtIndex: j] stringValue] forKey: [[attrs objectAtIndex: j] name]];
215 }
216 [stack addObject: dict];
217 dict = [NSMutableDictionary dictionary];
218 }
219 [_windowController setStack: stack];
220 }
221
222 /**
223 * Helper method to create a string command with the -i <session> automatically tacked on
224 */
225 - (NSString *)_createCommand: (NSString *)cmd
226 {
227 return [NSString stringWithFormat: @"%@ -i %@", cmd, _session];
228 }
229
230 @end