Number of fixes:
- allow to pass command line arguments from (lldb) prompt;
- make lldb exit as opposite to relying on kill (which is problematics
because it messes up tty settings);
- handle event timeout in autoexit_command to avoid endless loop;
- use dynamic TCP port and listen on localhost (no need to expose the
port to Internet);
- close accept socket once connection is established;
(fixes #112)
diff --git a/ios-deploy.c b/ios-deploy.c
index cad9ec3..dfc4d29 100644
--- a/ios-deploy.c
+++ b/ios-deploy.c
@@ -61,6 +61,7 @@
*/
#define LLDB_FRUITSTRAP_MODULE CFSTR("\
import lldb\n\
+import os\n\
import sys\n\
import shlex\n\
\n\
@@ -90,13 +91,14 @@
\n\
def run_command(debugger, command, result, internal_dict):\n\
device_app = internal_dict['fruitstrap_device_app']\n\
+ args = command.split('--',1)\n\
error = lldb.SBError()\n\
lldb.target.modules[0].SetPlatformFileSpec(lldb.SBFileSpec(device_app))\n\
- lldb.target.Launch(lldb.SBLaunchInfo(shlex.split('{args}')), error)\n\
+ lldb.target.Launch(lldb.SBLaunchInfo(shlex.split(args[1] and args[1] or '{args}')), error)\n\
lockedstr = ': Locked'\n\
if lockedstr in str(error):\n\
print('\\nDevice Locked\\n')\n\
- sys.exit(254)\n\
+ os._exit(254)\n\
else:\n\
print(str(error))\n\
\n\
@@ -106,12 +108,16 @@
listener.StartListeningForEvents(process.GetBroadcaster(), lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDERR)\n\
event = lldb.SBEvent()\n\
while True:\n\
- if listener.WaitForEvent(1, event):\n\
- state = process.GetStateFromEvent(event)\n\
+ if listener.WaitForEvent(1, event) and lldb.SBProcess.EventIsProcessEvent(event):\n\
+ state = lldb.SBProcess.GetStateFromEvent(event)\n\
else:\n\
- state = lldb.eStateInvalid\n\
- process.Detach()\n\
- sys.exit(0)\n\
+ state = process.GetState()\n\
+\n\
+ if state == lldb.eStateRunning:\n\
+ process.Detach()\n\
+ os._exit(0)\n\
+ elif state > lldb.eStateRunning:\n\
+ os._exit(state)\n\
\n\
def autoexit_command(debugger, command, result, internal_dict):\n\
process = lldb.target.process\n\
@@ -119,10 +125,16 @@
listener.StartListeningForEvents(process.GetBroadcaster(), lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDERR)\n\
event = lldb.SBEvent()\n\
while True:\n\
- if listener.WaitForEvent(1, event):\n\
- state = process.GetStateFromEvent(event)\n\
+ if listener.WaitForEvent(1, event) and lldb.SBProcess.EventIsProcessEvent(event):\n\
+ state = lldb.SBProcess.GetStateFromEvent(event)\n\
else:\n\
- state = lldb.eStateInvalid\n\
+ state = process.GetState()\n\
+\n\
+ if state == lldb.eStateExited:\n\
+ os._exit(process.GetExitStatus())\n\
+ elif state == lldb.eStateStopped:\n\
+ debugger.HandleCommand('bt')\n\
+ os._exit({exitcode_app_crash})\n\
\n\
stdout = process.GetSTDOUT(1024)\n\
while stdout:\n\
@@ -133,14 +145,6 @@
while stderr:\n\
sys.stdout.write(stderr)\n\
stderr = process.GetSTDERR(1024)\n\
-\n\
- if lldb.SBProcess.EventIsProcessEvent(event):\n\
- if state == lldb.eStateExited:\n\
- sys.exit(process.GetExitStatus())\n\
- if state == lldb.eStateStopped:\n\
- debugger.HandleCommand('frame select')\n\
- debugger.HandleCommand('bt')\n\
- sys.exit({exitcode_app_crash})\n\
")
typedef struct am_device * AMDeviceRef;
@@ -164,7 +168,7 @@
char *args = NULL;
char *list_root = NULL;
int timeout = 0;
-int port = 12345;
+int port = 0; // 0 means "dynamically assigned"
CFStringRef last_path = NULL;
service_conn_t gdbfd;
pid_t parent = 0;
@@ -822,22 +826,9 @@
int res;
if (CFDataGetLength (data) == 0) {
- // FIXME: Close the socket
- //shutdown (CFSocketGetNative (lldb_socket), SHUT_RDWR);
- //close (CFSocketGetNative (lldb_socket));
- CFSocketInvalidate(lldb_socket);
- CFSocketInvalidate(server_socket);
- int mypid = getpid();
- assert((child != 0) && (child != mypid)); //child should not be here
- if ((parent != 0) && (parent == mypid) && (child != 0))
- {
- if (verbose)
- {
- printf("Got an empty packet hence killing child (%d) tree\n", child);
- }
- kill_ptree(child, SIGHUP);
- }
- exit(exitcode_error);
+ // close the socket on which we've got end-of-file, the server_socket.
+ CFSocketInvalidate(s);
+ CFRelease(s);
return;
}
res = write (CFSocketGetNative (lldb_socket), CFDataGetBytePtr (data), CFDataGetLength (data));
@@ -847,8 +838,12 @@
{
//printf ("lldb: %s\n", CFDataGetBytePtr (data));
- if (CFDataGetLength (data) == 0)
+ if (CFDataGetLength (data) == 0) {
+ // close the socket on which we've got end-of-file, the lldb_socket.
+ CFSocketInvalidate(s);
+ CFRelease(s);
return;
+ }
write (gdbfd, CFDataGetBytePtr (data), CFDataGetLength (data));
}
@@ -859,21 +854,20 @@
//PRINT ("callback!\n");
lldb_socket = CFSocketCreateWithNative(NULL, socket, kCFSocketDataCallBack, &lldb_callback, NULL);
+ int flag = 1;
+ int res = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag));
+ assert(res == 0);
CFRunLoopAddSource(CFRunLoopGetMain(), CFSocketCreateRunLoopSource(NULL, lldb_socket, 0), kCFRunLoopCommonModes);
+
+ CFSocketInvalidate(s);
+ CFRelease(s);
}
void start_remote_debug_server(AMDeviceRef device) {
- char buf [256];
- int res, err, i;
- char msg [256];
- int chsum, len;
- struct stat s;
- socklen_t buflen;
- struct sockaddr name;
- int namelen;
- assert(AMDeviceStartService(device, CFSTR("com.apple.debugserver"), &gdbfd, NULL) == 0);
- assert (gdbfd);
+ int res = AMDeviceStartService(device, CFSTR("com.apple.debugserver"), &gdbfd, NULL);
+ assert(res == 0);
+ assert(gdbfd > 0);
/*
* The debugserver connection is through a fd handle, while lldb requires a host/port to connect, so create an intermediate
@@ -887,20 +881,24 @@
addr4.sin_len = sizeof(addr4);
addr4.sin_family = AF_INET;
addr4.sin_port = htons(port);
- addr4.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
CFSocketRef fdvendor = CFSocketCreate(NULL, PF_INET, 0, 0, kCFSocketAcceptCallBack, &fdvendor_callback, NULL);
- int yes = 1;
- setsockopt(CFSocketGetNative(fdvendor), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
- int flag = 1;
- res = setsockopt(CFSocketGetNative(fdvendor), IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
- assert (res == 0);
+ if (port) {
+ int yes = 1;
+ setsockopt(CFSocketGetNative(fdvendor), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
+ }
CFDataRef address_data = CFDataCreate(NULL, (const UInt8 *)&addr4, sizeof(addr4));
CFSocketSetAddress(fdvendor, address_data);
CFRelease(address_data);
+ socklen_t addrlen = sizeof(addr4);
+ res = getsockname(CFSocketGetNative(fdvendor),(struct sockaddr *)&addr4,&addrlen);
+ assert(res == 0);
+ port = ntohs(addr4.sin_port);
+
CFRunLoopAddSource(CFRunLoopGetMain(), CFSocketCreateRunLoopSource(NULL, fdvendor, 0), kCFRunLoopCommonModes);
}
@@ -1665,7 +1663,7 @@
" -L, --justlaunch just launch the app and exit lldb\n"
" -v, --verbose enable verbose output\n"
" -m, --noinstall directly start debugging without app install (-d not required)\n"
- " -p, --port <number> port used for device, default: 12345 \n"
+ " -p, --port <number> port used for device, default: dynamic\n"
" -r, --uninstall uninstall the app before install (do not use with -m; app cache and data are cleared) \n"
" -1, --bundle_id <bundle id> specify bundle id for list and upload\n"
" -l, --list list files\n"