Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 274 lines (236 sloc) 6.114 kB
cf73725 experimental debugger
Laurent Sansonetti authored
1 /*
2 * MacRuby Debugger Connector.
3 *
4 * This file is covered by the Ruby license. See COPYING for more details.
7d7d3e8 @ferrous26 Change ownership to The MacRuby Team and update copyrights
ferrous26 authored
5 *
6 * Copyright (C) 2012, The MacRuby Team. All rights reserved.
9595725 update copyrights to 2011
Laurent Sansonetti authored
7 * Copyright (C) 2010-2011, Apple Inc. All rights reserved.
cf73725 experimental debugger
Laurent Sansonetti authored
8 */
9
10 #import "MacRubyDebuggerConnector.h"
11
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <sys/un.h>
15
16 @implementation MacRubyDebuggerConnector
17
18 - (NSData *)_recv
19 {
20 assert(_socket != nil);
21 return [_socket availableData];
22 }
23
24 - (const char *)_recvCString
25 {
26 return (const char *)[[self _recv] bytes];
27 }
28
29 - (NSString *)_recvString
30 {
31 return [[NSString alloc] initWithData:[self _recv]
32 encoding:NSASCIIStringEncoding];
33 }
34
35 - (void)_send:(NSData *)data
36 {
37 assert(_socket != nil);
38 [_socket writeData:data];
39 }
40
41 - (void)_sendCString:(const char *)str
42 {
43 [self _send:[NSData dataWithBytes:str length:strlen(str)]];
44 }
45
46 -(void)_readLocation
47 {
48 _location = [self _recvString];
49 if ([_location length] == 0) {
50 _location = nil;
51 }
52 }
53
fb11b0a fixed internal debugger interpreter path
Laurent Sansonetti authored
54 - (id)initWithInterpreterPath:(NSString *)ipath arguments:(NSArray *)arguments
cf73725 experimental debugger
Laurent Sansonetti authored
55 {
56 self = [super init];
57 if (self != nil) {
58 // Generate the socket path.
a2c929b relying on TMPDIR is a bad idea
Laurent Sansonetti authored
59 NSString *tmpdir = NSTemporaryDirectory();
60 assert(tmpdir != nil);
cf73725 experimental debugger
Laurent Sansonetti authored
61 char path[PATH_MAX];
a2c929b relying on TMPDIR is a bad idea
Laurent Sansonetti authored
62 snprintf(path, sizeof path, "%s/macrubyd-XXXXXX",
63 [tmpdir fileSystemRepresentation]);
cf73725 experimental debugger
Laurent Sansonetti authored
64 assert(mktemp(path) != NULL);
65 _socketPath = [[NSFileManager defaultManager]
66 stringWithFileSystemRepresentation:path length:strlen(path)];
67
68 // Setup arguments.
69 _arguments = [NSMutableArray new];
70 [_arguments addObject:@"--debug-mode"];
71 [_arguments addObject:_socketPath];
72 [_arguments addObjectsFromArray:arguments];
73
fb11b0a fixed internal debugger interpreter path
Laurent Sansonetti authored
74 _interpreterPath = ipath;
cf73725 experimental debugger
Laurent Sansonetti authored
75 _task = nil;
76 _socket = nil;
77 _location = nil;
78 }
79 return self;
80 }
81
82 - (void)finalize
83 {
84 [super finalize];
85 [self stopExecution];
86 }
87
88 - (void)startExecution
89 {
90 if (_task == nil || ![_task isRunning]) {
91 // Create task.
92 _task = [NSTask new];
fb11b0a fixed internal debugger interpreter path
Laurent Sansonetti authored
93 [_task setLaunchPath:_interpreterPath];
cf73725 experimental debugger
Laurent Sansonetti authored
94 [_task setArguments:_arguments];
95
96 // Launch the remote process.
97 [[NSFileManager defaultManager] removeItemAtPath:_socketPath error:nil];
98 [_task launch];
99
100 // Wait until the socket file is available.
101 while (true) {
102 if ([[NSFileManager defaultManager] fileExistsAtPath:_socketPath]) {
103 break;
104 }
105 if (![_task isRunning]) {
106 // Something wrong happened at the very beginning, most likely
107 // a command-line argument error.
108 _task = nil;
109 return;
110 }
111 assert([_task isRunning]); // XXX raise exception
112 usleep(500000);
113 }
114
115 // Create the socket.
116 const int fd = socket(PF_LOCAL, SOCK_STREAM, 0);
117 if (fd == -1) {
118 // XXX should raise exception.
119 perror("socket()");
120 exit(1);
121 }
122
123 // Prepare the name.
124 struct sockaddr_un name;
125 name.sun_family = PF_LOCAL;
126 strncpy(name.sun_path, [_socketPath fileSystemRepresentation],
127 sizeof(name.sun_path));
128
129 // Connect.
130 if (connect(fd, (struct sockaddr *)&name, SUN_LEN(&name)) == -1) {
131 // XXX should raise exception.
132 perror("connect()");
133 exit(1);
134 }
135
136 // Good!
137 _socket = [[NSFileHandle alloc] initWithFileDescriptor:fd];
138 [self _readLocation];
139 }
140 }
141
142 - (void)continueExecution
143 {
144 [self _sendCString:"continue"];
145 [self _readLocation];
146 }
147
148 - (void)stepExecution
149 {
150 [self _sendCString:"next"];
151 [self _readLocation];
152 }
153
154 - (void)stopExecution
155 {
156 if (_task != nil) {
157 [_task terminate];
158 _task = nil;
159 }
160 _location = nil;
161 [[NSFileManager defaultManager] removeItemAtPath:_socketPath error:nil];
162 }
163
164 - (NSString *)location
165 {
166 return _location;
167 }
168
169 - (NSArray *)localVariables
170 {
171 return nil;
172 }
173
174 - (NSArray *)backtrace
175 {
176 [self _sendCString:"backtrace"];
177 return [[self _recvString] componentsSeparatedByString:@"\n"];
178 }
179
180 - (void)setFrame:(unsigned int)frame
181 {
182 char buf[512];
183 snprintf(buf, sizeof buf, "frame %d", frame);
184 [self _sendCString:buf];
185 }
186
187 - (breakpoint_t)addBreakPointAtPath:(NSString *)path line:(unsigned int)line
188 condition:(NSString *)condition
189 {
190 char buf[512];
191 snprintf(buf, sizeof buf, "break %s:%d", [path fileSystemRepresentation],
192 line);
193 [self _sendCString:buf];
194 return [[self _recvString] integerValue];
195 }
196
197 - (void)enableBreakPoint:(breakpoint_t)bp
198 {
199 char buf[512];
200 snprintf(buf, sizeof buf, "enable %d", bp);
201 [self _sendCString:buf];
202 }
203
204 - (void)disableBreakPoint:(breakpoint_t)bp
205 {
206 char buf[512];
207 snprintf(buf, sizeof buf, "disable %d", bp);
208 [self _sendCString:buf];
209 }
210
211 - (void)deleteBreakPoint:(breakpoint_t)bp
212 {
213 char buf[512];
214 snprintf(buf, sizeof buf, "delete %d", bp);
215 [self _sendCString:buf];
216 }
217
218 - (void)setCondition:(NSString *)condition forBreakPoint:(breakpoint_t)bp
219 {
220 char buf[512];
221 snprintf(buf, sizeof buf, "condition %d %s", bp, [condition UTF8String]);
222 [self _sendCString:buf];
223 }
224
225 - (NSDictionary *)_parseBreakPointDescription:(NSString *)desc
226 {
227 NSArray *ary = [desc componentsSeparatedByString:@","];
228 if ([ary count] == 0) {
229 return nil;
230 }
231 NSMutableDictionary *dict = [NSMutableDictionary new];
232 unsigned i, count;
233 for (i = 0, count = [ary count]; i < count; i++) {
234 NSArray *fields = [[ary objectAtIndex:i]
235 componentsSeparatedByString:@"="];
236 if ([fields count] == 2) {
237 NSString *key = [fields objectAtIndex:0];
238 NSString *val = [fields objectAtIndex:1];
239 [dict setObject:val forKey:key];
240 }
241 }
242 if ([dict count] == 0) {
243 return nil;
244 }
245 return dict;
246 }
247
248
249 - (NSArray *)allBreakPoints
250 {
251 [self _sendCString:"info breakpoints"];
252 NSArray *ary = [[self _recvString] componentsSeparatedByString:@"\n"];
253 NSMutableArray *ary2 = [NSMutableArray new];
254 unsigned i, count;
255 for (i = 0, count = [ary count]; i < count; i++) {
256 NSString *desc = [ary objectAtIndex:i];
257 NSDictionary *dict = [self _parseBreakPointDescription:desc];
258 if (dict != nil) {
259 [ary2 addObject:dict];
260 }
261 }
262 return ary2;
263 }
264
265 - (NSString *)evaluateExpression:(NSString *)expression
266 {
267 char buf[512];
268 snprintf(buf, sizeof buf, "eval %s", [expression UTF8String]);
269 [self _sendCString:buf];
270 return [self _recvString];
271 }
272
273 @end
Something went wrong with that request. Please try again.