Skip to content

Commit 54818aa

Browse files
Andy Polyakovshazron
authored andcommitted
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)
1 parent e882932 commit 54818aa

File tree

1 file changed

+52
-54
lines changed

1 file changed

+52
-54
lines changed

ios-deploy.c

Lines changed: 52 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const char* lldb_prep_noninteractive_cmds = "\
6161
*/
6262
#define LLDB_FRUITSTRAP_MODULE CFSTR("\
6363
import lldb\n\
64+
import os\n\
6465
import sys\n\
6566
import shlex\n\
6667
\n\
@@ -90,13 +91,14 @@ def connect_command(debugger, command, result, internal_dict):\n\
9091
\n\
9192
def run_command(debugger, command, result, internal_dict):\n\
9293
device_app = internal_dict['fruitstrap_device_app']\n\
94+
args = command.split('--',1)\n\
9395
error = lldb.SBError()\n\
9496
lldb.target.modules[0].SetPlatformFileSpec(lldb.SBFileSpec(device_app))\n\
95-
lldb.target.Launch(lldb.SBLaunchInfo(shlex.split('{args}')), error)\n\
97+
lldb.target.Launch(lldb.SBLaunchInfo(shlex.split(args[1] and args[1] or '{args}')), error)\n\
9698
lockedstr = ': Locked'\n\
9799
if lockedstr in str(error):\n\
98100
print('\\nDevice Locked\\n')\n\
99-
sys.exit(254)\n\
101+
os._exit(254)\n\
100102
else:\n\
101103
print(str(error))\n\
102104
\n\
@@ -106,23 +108,33 @@ def safequit_command(debugger, command, result, internal_dict):\n\
106108
listener.StartListeningForEvents(process.GetBroadcaster(), lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDERR)\n\
107109
event = lldb.SBEvent()\n\
108110
while True:\n\
109-
if listener.WaitForEvent(1, event):\n\
110-
state = process.GetStateFromEvent(event)\n\
111+
if listener.WaitForEvent(1, event) and lldb.SBProcess.EventIsProcessEvent(event):\n\
112+
state = lldb.SBProcess.GetStateFromEvent(event)\n\
111113
else:\n\
112-
state = lldb.eStateInvalid\n\
113-
process.Detach()\n\
114-
sys.exit(0)\n\
114+
state = process.GetState()\n\
115+
\n\
116+
if state == lldb.eStateRunning:\n\
117+
process.Detach()\n\
118+
os._exit(0)\n\
119+
elif state > lldb.eStateRunning:\n\
120+
os._exit(state)\n\
115121
\n\
116122
def autoexit_command(debugger, command, result, internal_dict):\n\
117123
process = lldb.target.process\n\
118124
listener = debugger.GetListener()\n\
119125
listener.StartListeningForEvents(process.GetBroadcaster(), lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDERR)\n\
120126
event = lldb.SBEvent()\n\
121127
while True:\n\
122-
if listener.WaitForEvent(1, event):\n\
123-
state = process.GetStateFromEvent(event)\n\
128+
if listener.WaitForEvent(1, event) and lldb.SBProcess.EventIsProcessEvent(event):\n\
129+
state = lldb.SBProcess.GetStateFromEvent(event)\n\
124130
else:\n\
125-
state = lldb.eStateInvalid\n\
131+
state = process.GetState()\n\
132+
\n\
133+
if state == lldb.eStateExited:\n\
134+
os._exit(process.GetExitStatus())\n\
135+
elif state == lldb.eStateStopped:\n\
136+
debugger.HandleCommand('bt')\n\
137+
os._exit({exitcode_app_crash})\n\
126138
\n\
127139
stdout = process.GetSTDOUT(1024)\n\
128140
while stdout:\n\
@@ -133,14 +145,6 @@ def autoexit_command(debugger, command, result, internal_dict):\n\
133145
while stderr:\n\
134146
sys.stdout.write(stderr)\n\
135147
stderr = process.GetSTDERR(1024)\n\
136-
\n\
137-
if lldb.SBProcess.EventIsProcessEvent(event):\n\
138-
if state == lldb.eStateExited:\n\
139-
sys.exit(process.GetExitStatus())\n\
140-
if state == lldb.eStateStopped:\n\
141-
debugger.HandleCommand('frame select')\n\
142-
debugger.HandleCommand('bt')\n\
143-
sys.exit({exitcode_app_crash})\n\
144148
")
145149

146150
typedef struct am_device * AMDeviceRef;
@@ -164,7 +168,7 @@ char *device_id = NULL;
164168
char *args = NULL;
165169
char *list_root = NULL;
166170
int timeout = 0;
167-
int port = 12345;
171+
int port = 0; // 0 means "dynamically assigned"
168172
CFStringRef last_path = NULL;
169173
service_conn_t gdbfd;
170174
pid_t parent = 0;
@@ -822,22 +826,9 @@ server_callback (CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef add
822826
int res;
823827

824828
if (CFDataGetLength (data) == 0) {
825-
// FIXME: Close the socket
826-
//shutdown (CFSocketGetNative (lldb_socket), SHUT_RDWR);
827-
//close (CFSocketGetNative (lldb_socket));
828-
CFSocketInvalidate(lldb_socket);
829-
CFSocketInvalidate(server_socket);
830-
int mypid = getpid();
831-
assert((child != 0) && (child != mypid)); //child should not be here
832-
if ((parent != 0) && (parent == mypid) && (child != 0))
833-
{
834-
if (verbose)
835-
{
836-
printf("Got an empty packet hence killing child (%d) tree\n", child);
837-
}
838-
kill_ptree(child, SIGHUP);
839-
}
840-
exit(exitcode_error);
829+
// close the socket on which we've got end-of-file, the server_socket.
830+
CFSocketInvalidate(s);
831+
CFRelease(s);
841832
return;
842833
}
843834
res = write (CFSocketGetNative (lldb_socket), CFDataGetBytePtr (data), CFDataGetLength (data));
@@ -847,8 +838,12 @@ void lldb_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef a
847838
{
848839
//printf ("lldb: %s\n", CFDataGetBytePtr (data));
849840

850-
if (CFDataGetLength (data) == 0)
841+
if (CFDataGetLength (data) == 0) {
842+
// close the socket on which we've got end-of-file, the lldb_socket.
843+
CFSocketInvalidate(s);
844+
CFRelease(s);
851845
return;
846+
}
852847
write (gdbfd, CFDataGetBytePtr (data), CFDataGetLength (data));
853848
}
854849

@@ -859,21 +854,20 @@ void fdvendor_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataR
859854
//PRINT ("callback!\n");
860855

861856
lldb_socket = CFSocketCreateWithNative(NULL, socket, kCFSocketDataCallBack, &lldb_callback, NULL);
857+
int flag = 1;
858+
int res = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag));
859+
assert(res == 0);
862860
CFRunLoopAddSource(CFRunLoopGetMain(), CFSocketCreateRunLoopSource(NULL, lldb_socket, 0), kCFRunLoopCommonModes);
861+
862+
CFSocketInvalidate(s);
863+
CFRelease(s);
863864
}
864865

865866
void start_remote_debug_server(AMDeviceRef device) {
866-
char buf [256];
867-
int res, err, i;
868-
char msg [256];
869-
int chsum, len;
870-
struct stat s;
871-
socklen_t buflen;
872-
struct sockaddr name;
873-
int namelen;
874-
875-
assert(AMDeviceStartService(device, CFSTR("com.apple.debugserver"), &gdbfd, NULL) == 0);
876-
assert (gdbfd);
867+
868+
int res = AMDeviceStartService(device, CFSTR("com.apple.debugserver"), &gdbfd, NULL);
869+
assert(res == 0);
870+
assert(gdbfd > 0);
877871

878872
/*
879873
* The debugserver connection is through a fd handle, while lldb requires a host/port to connect, so create an intermediate
@@ -887,20 +881,24 @@ void start_remote_debug_server(AMDeviceRef device) {
887881
addr4.sin_len = sizeof(addr4);
888882
addr4.sin_family = AF_INET;
889883
addr4.sin_port = htons(port);
890-
addr4.sin_addr.s_addr = htonl(INADDR_ANY);
884+
addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
891885

892886
CFSocketRef fdvendor = CFSocketCreate(NULL, PF_INET, 0, 0, kCFSocketAcceptCallBack, &fdvendor_callback, NULL);
893887

894-
int yes = 1;
895-
setsockopt(CFSocketGetNative(fdvendor), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
896-
int flag = 1;
897-
res = setsockopt(CFSocketGetNative(fdvendor), IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
898-
assert (res == 0);
888+
if (port) {
889+
int yes = 1;
890+
setsockopt(CFSocketGetNative(fdvendor), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
891+
}
899892

900893
CFDataRef address_data = CFDataCreate(NULL, (const UInt8 *)&addr4, sizeof(addr4));
901894

902895
CFSocketSetAddress(fdvendor, address_data);
903896
CFRelease(address_data);
897+
socklen_t addrlen = sizeof(addr4);
898+
res = getsockname(CFSocketGetNative(fdvendor),(struct sockaddr *)&addr4,&addrlen);
899+
assert(res == 0);
900+
port = ntohs(addr4.sin_port);
901+
904902
CFRunLoopAddSource(CFRunLoopGetMain(), CFSocketCreateRunLoopSource(NULL, fdvendor, 0), kCFRunLoopCommonModes);
905903
}
906904

@@ -1665,7 +1663,7 @@ void usage(const char* app) {
16651663
" -L, --justlaunch just launch the app and exit lldb\n"
16661664
" -v, --verbose enable verbose output\n"
16671665
" -m, --noinstall directly start debugging without app install (-d not required)\n"
1668-
" -p, --port <number> port used for device, default: 12345 \n"
1666+
" -p, --port <number> port used for device, default: dynamic\n"
16691667
" -r, --uninstall uninstall the app before install (do not use with -m; app cache and data are cleared) \n"
16701668
" -1, --bundle_id <bundle id> specify bundle id for list and upload\n"
16711669
" -l, --list list files\n"

0 commit comments

Comments
 (0)