debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response) { if (!client || !env) return DEBUGSERVER_E_INVALID_ARG; debugserver_error_t result = DEBUGSERVER_E_UNKNOWN_ERROR; const char* env_arg[] = { env, NULL }; debugserver_command_t command = NULL; debugserver_command_new("QEnvironmentHexEncoded:", 1, env_arg, &command); result = debugserver_client_send_command(client, command, response); debugserver_command_free(command); return result; }
debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response) { if (!client || !argc) return DEBUGSERVER_E_INVALID_ARG; debugserver_error_t result = DEBUGSERVER_E_UNKNOWN_ERROR; char *pkt = NULL; int pkt_len = 0; int i = 0; /* calculate total length */ while (i < argc && argv && argv[i]) { char *prefix = NULL; asprintf(&prefix, ",%d,%d,", (int)strlen(argv[i]) * 2, i); pkt_len += (int)strlen(prefix) + (int)strlen(argv[i]) * 2; free(prefix); i++; } /* allocate packet and initialize it */ pkt = (char *) malloc(pkt_len + 1); memset(pkt, 0, pkt_len + 1); char *pktp = pkt; i = 0; while (i < argc && argv && argv[i]) { debug_info("argv[%d] = \"%s\"", i, argv[i]); char *prefix = NULL; char *m = NULL; int arg_len = strlen(argv[i]); int arg_hexlen = arg_len * 2; asprintf(&prefix, ",%d,%d,", arg_hexlen, i); m = (char *) malloc(arg_hexlen); char *p = m; char *q = (char*)argv[i]; while (*q) { *p++ = debugserver_int2hex(*q >> 4); *p++ = debugserver_int2hex(*q & 0xf); q++; } memcpy(pktp, prefix, strlen(prefix)); pktp += strlen(prefix); memcpy(pktp, m, arg_hexlen); pktp += arg_hexlen; free(prefix); free(m); i++; } pkt[0] = 'A'; debugserver_command_t command = NULL; debugserver_command_new(pkt, 0, NULL, &command); result = debugserver_client_send_command(client, command, response); debugserver_command_free(command); if (pkt) free(pkt); return result; }
int main(int argc, char *argv[]) { int res = -1; idevice_t device = NULL; idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; instproxy_client_t instproxy_client = NULL; debugserver_client_t debugserver_client = NULL; int i; int debug_level = 0; int cmd = CMD_NONE; const char* udid = NULL; const char* bundle_identifier = NULL; char* path = NULL; char* working_directory = NULL; char **newlist = NULL; char** environment = NULL; int environment_index = 0; int environment_count = 0; char* response = NULL; debugserver_command_t command = NULL; debugserver_error_t dres = DEBUGSERVER_E_UNKNOWN_ERROR; /* map signals */ signal(SIGINT, on_signal); signal(SIGTERM, on_signal); #ifndef WIN32 signal(SIGQUIT, on_signal); signal(SIGPIPE, SIG_IGN); #endif /* parse command line arguments */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { debug_level++; idevice_set_debug_level(debug_level); continue; } else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) { i++; if (!argv[i] || (strlen(argv[i]) != 40)) { print_usage(argc, argv); res = 0; goto cleanup; } udid = argv[i]; continue; } else if (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--env")) { i++; if (!argv[i] || (strlen(argv[i]) <= 1) || strchr(argv[i], '=') == NULL) { print_usage(argc, argv); res = 0; goto cleanup; } /* add environment variable */ if (!newlist) newlist = malloc((environment_count + 1) * sizeof(char*)); else newlist = realloc(environment, (environment_count + 1) * sizeof(char*)); newlist[environment_count++] = strdup(argv[i]); environment = newlist; continue; } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { print_usage(argc, argv); res = 0; goto cleanup; } else if (!strcmp(argv[i], "run")) { cmd = CMD_RUN; i++; if (!argv[i]) { /* make sure at least the bundle identifier was provided */ printf("Please supply the bundle identifier of the app to run.\n"); print_usage(argc, argv); res = 0; goto cleanup; } /* read bundle identifier */ bundle_identifier = argv[i]; break; } else { print_usage(argc, argv); res = 0; goto cleanup; } } if (environment) { newlist = realloc(environment, (environment_count + 1) * sizeof(char*)); newlist[environment_count] = NULL; environment = newlist; } /* verify options */ if (cmd == CMD_NONE) { print_usage(argc, argv); goto cleanup; } /* connect to the device */ ret = idevice_new(&device, udid); if (ret != IDEVICE_E_SUCCESS) { if (udid) { printf("No device found with udid %s, is it plugged in?\n", udid); } else { printf("No device found, is it plugged in?\n"); } goto cleanup; } switch (cmd) { case CMD_RUN: default: /* get the path to the app and it's working directory */ if (instproxy_client_start_service(device, &instproxy_client, "idevicerun") != INSTPROXY_E_SUCCESS) { fprintf(stderr, "Could not start installation proxy service.\n"); goto cleanup; } plist_t container = NULL; instproxy_client_get_object_by_key_from_info_directionary_for_bundle_identifier(instproxy_client, bundle_identifier, "Container", &container); instproxy_client_get_path_for_bundle_identifier(instproxy_client, bundle_identifier, &path); instproxy_client_free(instproxy_client); instproxy_client = NULL; if (container && (plist_get_node_type(container) == PLIST_STRING)) { plist_get_string_val(container, &working_directory); debug_info("working_directory: %s\n", working_directory); plist_free(container); } else { plist_free(container); fprintf(stderr, "Could not determine container path for bundle identifier %s.\n", bundle_identifier); goto cleanup; } /* start and connect to debugserver */ if (debugserver_client_start_service(device, &debugserver_client, "idevicerun") != DEBUGSERVER_E_SUCCESS) { fprintf(stderr, "Could not start com.apple.debugserver!\n" "Please make sure to mount the developer disk image first:\n" " 1) Get the iOS version from `ideviceinfo -k ProductVersion`.\n" " 2) Find the matching iPhoneOS DeveloperDiskImage.dmg files.\n" " 3) Run `ideviceimagemounter` with the above path.\n"); goto cleanup; } /* enable logging for the session in debug mode */ if (debug_level) { debug_info("Setting logging bitmask..."); debugserver_command_new("QSetLogging:bitmask=LOG_ALL|LOG_RNB_REMOTE|LOG_RNB_PACKETS", 0, NULL, &command); dres = debugserver_client_send_command(debugserver_client, command, &response); debugserver_command_free(command); command = NULL; if (response) { if (strncmp(response, "OK", 2)) { debugserver_client_handle_response(debugserver_client, &response, 0); goto cleanup; } free(response); response = NULL; } } /* set maximum packet size */ debug_info("Setting maximum packet size..."); char* packet_size[2] = {strdup("1024"), NULL}; debugserver_command_new("QSetMaxPacketSize:", 1, packet_size, &command); free(packet_size[0]); dres = debugserver_client_send_command(debugserver_client, command, &response); debugserver_command_free(command); command = NULL; if (response) { if (strncmp(response, "OK", 2)) { debugserver_client_handle_response(debugserver_client, &response, 0); goto cleanup; } free(response); response = NULL; } /* set working directory */ debug_info("Setting working directory..."); char* working_dir[2] = {working_directory, NULL}; debugserver_command_new("QSetWorkingDir:", 1, working_dir, &command); dres = debugserver_client_send_command(debugserver_client, command, &response); debugserver_command_free(command); command = NULL; if (response) { if (strncmp(response, "OK", 2)) { debugserver_client_handle_response(debugserver_client, &response, 0); goto cleanup; } free(response); response = NULL; } /* set environment */ if (environment) { debug_info("Setting environment..."); for (environment_index = 0; environment_index < environment_count; environment_index++) { debug_info("setting environment variable: %s", environment[environment_index]); debugserver_client_set_environment_hex_encoded(debugserver_client, environment[environment_index], NULL); } } /* set arguments and run app */ debug_info("Setting argv..."); i++; /* i is the offset of the bundle identifier, thus skip it */ int app_argc = (argc - i + 2); char **app_argv = (char**)malloc(sizeof(char*) * app_argc); app_argv[0] = path; debug_info("app_argv[%d] = %s", 0, app_argv[0]); app_argc = 1; while (i < argc && argv && argv[i]) { debug_info("app_argv[%d] = %s", app_argc, argv[i]); app_argv[app_argc++] = argv[i]; i++; } app_argv[app_argc] = NULL; debugserver_client_set_argv(debugserver_client, app_argc, app_argv, NULL); free(app_argv); /* check if launch succeeded */ debug_info("Checking if launch succeeded..."); debugserver_command_new("qLaunchSuccess", 0, NULL, &command); dres = debugserver_client_send_command(debugserver_client, command, &response); debugserver_command_free(command); command = NULL; if (response) { if (strncmp(response, "OK", 2)) { debugserver_client_handle_response(debugserver_client, &response, 0); goto cleanup; } free(response); response = NULL; } /* set thread */ debug_info("Setting thread..."); debugserver_command_new("Hc0", 0, NULL, &command); dres = debugserver_client_send_command(debugserver_client, command, &response); debugserver_command_free(command); command = NULL; if (response) { if (strncmp(response, "OK", 2)) { debugserver_client_handle_response(debugserver_client, &response, 0); goto cleanup; } free(response); response = NULL; } /* continue running process */ debug_info("Continue running process..."); debugserver_command_new("c", 0, NULL, &command); dres = debugserver_client_send_command(debugserver_client, command, &response); debugserver_command_free(command); command = NULL; /* main loop which is parsing/handling packets during the run */ debug_info("Entering run loop..."); while (!quit_flag) { if (dres != DEBUGSERVER_E_SUCCESS) { debug_info("failed to receive response"); break; } if (response) { debug_info("response: %s", response); dres = debugserver_client_handle_response(debugserver_client, &response, 1); } sleep(1); } /* kill process after we finished */ debug_info("Killing process..."); debugserver_command_new("k", 0, NULL, &command); dres = debugserver_client_send_command(debugserver_client, command, &response); debugserver_command_free(command); command = NULL; if (response) { if (strncmp(response, "OK", 2)) { debugserver_client_handle_response(debugserver_client, &response, 0); goto cleanup; } free(response); response = NULL; } res = (dres == DEBUGSERVER_E_SUCCESS) ? 0: -1; break; } cleanup: /* cleanup the house */ if (environment) { for (environment_index = 0; environment_index < environment_count; environment_index++) { free(environment[environment_index]); } free(environment); } if (working_directory) free(working_directory); if (path) free(path); if (response) free(response); if (debugserver_client) debugserver_client_free(debugserver_client); if (device) idevice_free(device); return res; }
static debugserver_error_t debugserver_client_handle_response(debugserver_client_t client, char** response, int send_reply) { debugserver_error_t dres = DEBUGSERVER_E_SUCCESS; debugserver_command_t command = NULL; char* o = NULL; char* r = *response; if (r[0] == 'O') { /* stdout/stderr */ debugserver_decode_string(r + 1, strlen(r) - 1, &o); printf("%s", o); fflush(stdout); if (o != NULL) { free(o); o = NULL; } free(*response); *response = NULL; if (!send_reply) return dres; /* send reply */ debugserver_command_new("OK", 0, NULL, &command); dres = debugserver_client_send_command(client, command, response); debug_info("result: %d", dres); debugserver_command_free(command); command = NULL; } else if (r[0] == 'T') { /* thread stopped information */ debug_info("Thread stopped. Details:\n%s", r + 1); free(*response); *response = NULL; if (!send_reply) return dres; dres = DEBUGSERVER_E_UNKNOWN_ERROR; } else if (r[0] == 'E' || r[0] == 'W') { printf("%s: %s\n", (r[0] == 'E' ? "ERROR": "WARNING") , r + 1); free(*response); *response = NULL; if (!send_reply) return dres; /* send reply */ debugserver_command_new("OK", 0, NULL, &command); dres = debugserver_client_send_command(client, command, response); debug_info("result: %d", dres); debugserver_command_free(command); command = NULL; } else if (r && strlen(r) == 0) { if (!send_reply) return dres; free(*response); *response = NULL; /* no command */ debugserver_command_new("OK", 0, NULL, &command); dres = debugserver_client_send_command(client, command, response); debug_info("result: %d", dres); debugserver_command_free(command); command = NULL; } else { debug_info("ERROR: unhandled response", r); } return dres; }