1 /*
2  * debugserver.c
3  * com.apple.debugserver service implementation.
4  *
5  * Copyright (c) 2019 Nikias Bassen, All Rights Reserved.
6  * Copyright (c) 2014-2015 Martin Szulecki All Rights Reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <string.h>
27 #include <stdlib.h>
28 #define _GNU_SOURCE 1
29 #define __USE_GNU 1
30 #include <stdio.h>
31 
32 #include "debugserver.h"
33 #include "lockdown.h"
34 #include "common/debug.h"
35 #include "common/utils.h"
36 #include "asprintf.h"
37 
38 /**
39  * Convert a service_error_t value to a debugserver_error_t value.
40  * Used internally to get correct error codes.
41  *
42  * @param err An service_error_t error code
43  *
44  * @return A matching debugserver_error_t error code,
45  *     DEBUGSERVER_E_UNKNOWN_ERROR otherwise.
46  */
debugserver_error(service_error_t err)47 static debugserver_error_t debugserver_error(service_error_t err)
48 {
49 	switch (err) {
50 		case SERVICE_E_SUCCESS:
51 			return DEBUGSERVER_E_SUCCESS;
52 		case SERVICE_E_INVALID_ARG:
53 			return DEBUGSERVER_E_INVALID_ARG;
54 		case SERVICE_E_MUX_ERROR:
55 			return DEBUGSERVER_E_MUX_ERROR;
56 		case SERVICE_E_SSL_ERROR:
57 			return DEBUGSERVER_E_SSL_ERROR;
58 		case SERVICE_E_TIMEOUT:
59 			return DEBUGSERVER_E_TIMEOUT;
60 		default:
61 			break;
62 	}
63 	return DEBUGSERVER_E_UNKNOWN_ERROR;
64 }
65 
debugserver_client_new(idevice_t device,lockdownd_service_descriptor_t service,debugserver_client_t * client)66 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t* client)
67 {
68 	*client = NULL;
69 
70 	if (!device || !service || service->port == 0 || !client || *client) {
71 		debug_info("Incorrect parameter passed to debugserver_client_new.");
72 		return DEBUGSERVER_E_INVALID_ARG;
73 	}
74 
75 	debug_info("Creating debugserver_client, port = %d.", service->port);
76 
77 	service_client_t parent = NULL;
78 	debugserver_error_t ret = debugserver_error(service_client_new(device, service, &parent));
79 	if (ret != DEBUGSERVER_E_SUCCESS) {
80 		debug_info("Creating base service client failed. Error: %i", ret);
81 		return ret;
82 	}
83 	service_disable_bypass_ssl(parent, 1);
84 
85 	debugserver_client_t client_loc = (debugserver_client_t) malloc(sizeof(struct debugserver_client_private));
86 	client_loc->parent = parent;
87 	client_loc->noack_mode = 0;
88 
89 	*client = client_loc;
90 
91 	debug_info("debugserver_client successfully created.");
92 	return DEBUGSERVER_E_SUCCESS;
93 }
94 
debugserver_client_start_service(idevice_t device,debugserver_client_t * client,const char * label)95 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_start_service(idevice_t device, debugserver_client_t * client, const char* label)
96 {
97 	debugserver_error_t err = DEBUGSERVER_E_UNKNOWN_ERROR;
98 	service_client_factory_start_service(device, DEBUGSERVER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(debugserver_client_new), &err);
99 	return err;
100 }
101 
debugserver_client_free(debugserver_client_t client)102 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_free(debugserver_client_t client)
103 {
104 	if (!client)
105 		return DEBUGSERVER_E_INVALID_ARG;
106 
107 	debugserver_error_t err = debugserver_error(service_client_free(client->parent));
108 	client->parent = NULL;
109 	free(client);
110 
111 	return err;
112 }
113 
debugserver_client_send(debugserver_client_t client,const char * data,uint32_t size,uint32_t * sent)114 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent)
115 {
116 	debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
117 	int bytes = 0;
118 
119 	if (!client || !data || (size == 0)) {
120 		return DEBUGSERVER_E_INVALID_ARG;
121 	}
122 
123 	debug_info("sending %d bytes", size);
124 	res = debugserver_error(service_send(client->parent, data, size, (uint32_t*)&bytes));
125 	if (bytes <= 0) {
126 		debug_info("ERROR: sending to device failed.");
127 	}
128 	if (sent) {
129 		*sent = (uint32_t)bytes;
130 	}
131 
132 	return res;
133 }
134 
debugserver_client_receive_with_timeout(debugserver_client_t client,char * data,uint32_t size,uint32_t * received,unsigned int timeout)135 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
136 {
137 	debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
138 	int bytes = 0;
139 
140 	if (!client || !data || (size == 0)) {
141 		return DEBUGSERVER_E_INVALID_ARG;
142 	}
143 
144 	res = debugserver_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout));
145 	if (bytes <= 0) {
146 		debug_info("Could not read data, error %d", res);
147 	}
148 	if (received) {
149 		*received = (uint32_t)bytes;
150 	}
151 
152 	return res;
153 }
154 
debugserver_client_receive(debugserver_client_t client,char * data,uint32_t size,uint32_t * received)155 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive(debugserver_client_t client, char* data, uint32_t size, uint32_t *received)
156 {
157 	return debugserver_client_receive_with_timeout(client, data, size, received, 1000);
158 }
159 
debugserver_command_new(const char * name,int argc,char * argv[],debugserver_command_t * command)160 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_new(const char* name, int argc, char* argv[], debugserver_command_t* command)
161 {
162 	int i;
163 	debugserver_command_t tmp = (debugserver_command_t) malloc(sizeof(struct debugserver_command_private));
164 
165 	/* copy name */
166 	tmp->name = strdup(name);
167 
168 	/* copy arguments */
169 	tmp->argc = argc;
170 	tmp->argv = NULL;
171 	if (argc > 0) {
172 		tmp->argv = malloc(sizeof(char*) * (argc + 2));
173 		for (i = 0; i < argc; i++) {
174 			tmp->argv[i] = strdup(argv[i]);
175 		}
176 		tmp->argv[i+1] = NULL;
177 	}
178 
179 	/* return */
180 	*command = tmp;
181 
182 	return DEBUGSERVER_E_SUCCESS;
183 }
184 
debugserver_command_free(debugserver_command_t command)185 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_command_free(debugserver_command_t command)
186 {
187 	int i;
188 	debugserver_error_t res = DEBUGSERVER_E_UNKNOWN_ERROR;
189 
190 	if (!command)
191 		return DEBUGSERVER_E_INVALID_ARG;
192 
193 	if (command) {
194 		if (command->name)
195 			free(command->name);
196 		if (command->argv && command->argc) {
197 			for (i = 0; i < command->argc; i++) {
198 				free(command->argv[i]);
199 			}
200 			free(command->argv);
201 		}
202 		free(command);
203 		res = DEBUGSERVER_E_SUCCESS;
204 	}
205 
206 	return res;
207 }
208 
debugserver_hex2int(char c)209 static int debugserver_hex2int(char c)
210 {
211 	if (c >= '0' && c <= '9')
212 		return c - '0';
213 	else if (c >= 'a' && c <= 'f')
214 		return 10 + c - 'a';
215 	else if (c >= 'A' && c <= 'F')
216 		return 10 + c - 'A';
217 	else
218 		return c;
219 }
220 
debugserver_int2hex(int x)221 static char debugserver_int2hex(int x)
222 {
223 	const char *hexchars = "0123456789ABCDEF";
224 	return hexchars[x];
225 }
226 
227 #define DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(byte) debugserver_int2hex((byte >> 0x4) & 0xf)
228 #define DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(byte) debugserver_int2hex(byte & 0xf)
229 #define DEBUGSERVER_HEX_DECODE_FIRST_BYTE(byte) ((byte >> 0x4) & 0xf)
230 #define DEBUGSERVER_HEX_DECODE_SECOND_BYTE(byte) (byte & 0xf)
231 
debugserver_get_checksum_for_buffer(const char * buffer,uint32_t size)232 static uint32_t debugserver_get_checksum_for_buffer(const char* buffer, uint32_t size)
233 {
234 	uint32_t checksum = 0;
235 	uint32_t i;
236 
237 	for (i = 0; i < size; i++) {
238 		checksum += buffer[i];
239 	}
240 
241 	return checksum;
242 }
243 
debugserver_response_is_checksum_valid(const char * response,uint32_t size)244 static int debugserver_response_is_checksum_valid(const char* response, uint32_t size)
245 {
246 	uint32_t checksum = 0;
247 	if ((size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1) > 0)
248 		checksum = debugserver_get_checksum_for_buffer(&response[1], size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1);
249 
250 	debug_info("checksum: 0x%x", checksum);
251 
252 	if ((unsigned)debugserver_hex2int(response[size - 2]) != DEBUGSERVER_HEX_DECODE_FIRST_BYTE(checksum))
253 		return 0;
254 
255 	if ((unsigned)debugserver_hex2int(response[size - 1]) != DEBUGSERVER_HEX_DECODE_SECOND_BYTE(checksum))
256 		return 0;
257 
258 	debug_info("valid checksum");
259 
260 	return 1;
261 }
262 
debugserver_encode_string(const char * buffer,char ** encoded_buffer,uint32_t * encoded_length)263 LIBIMOBILEDEVICE_API void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length)
264 {
265 	uint32_t position;
266 	uint32_t index;
267 	uint32_t length = strlen(buffer);
268 	*encoded_length = (2 * length) + DEBUGSERVER_CHECKSUM_HASH_LENGTH + 1;
269 
270 	*encoded_buffer = malloc(sizeof(char) * (*encoded_length));
271 	memset(*encoded_buffer, '\0', *encoded_length);
272 	for (position = 0, index = 0; index < length; index++) {
273 		position = (index * (2 * sizeof(char)));
274 		(*encoded_buffer)[position] = DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(buffer[index]);
275 		(*encoded_buffer)[position + 1] = DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(buffer[index]);
276 	}
277 }
278 
debugserver_decode_string(const char * encoded_buffer,size_t encoded_length,char ** buffer)279 LIBIMOBILEDEVICE_API void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer)
280 {
281 	*buffer = malloc(sizeof(char) * ((encoded_length / 2)+1));
282 	char* t = *buffer;
283 	const char *f = encoded_buffer;
284 	const char *fend = f + encoded_length;
285 	while (f < fend) {
286 		*t++ = debugserver_hex2int(*f) << 4 | debugserver_hex2int(f[1]);
287 		f += 2;
288 	}
289 	*t = '\0';
290 }
291 
debugserver_format_command(const char * prefix,const char * command,const char * arguments,int calculate_checksum,char ** buffer,uint32_t * size)292 static void debugserver_format_command(const char* prefix, const char* command, const char* arguments, int calculate_checksum, char** buffer, uint32_t* size)
293 {
294 	char checksum_hash[DEBUGSERVER_CHECKSUM_HASH_LENGTH + 1] = {'#', '0', '0', '\0'};
295 	char* encoded = NULL;
296 	uint32_t encoded_length = 0;
297 
298 	if (arguments) {
299 		/* arguments must be hex encoded */
300 		debugserver_encode_string(arguments, &encoded, &encoded_length);
301 	} else {
302 		encoded = NULL;
303 	}
304 
305 	char* encoded_command = string_concat(command, encoded, NULL);
306 	encoded_length = strlen(encoded_command);
307 
308 	if (calculate_checksum) {
309 		uint32_t checksum = debugserver_get_checksum_for_buffer(encoded_command, encoded_length);
310 		checksum_hash[1] = DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(checksum);
311 		checksum_hash[2] = DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(checksum);
312 	}
313 
314 	*buffer = string_concat(prefix, encoded_command, checksum_hash, NULL);
315 	*size = strlen(prefix) + strlen(encoded_command) + DEBUGSERVER_CHECKSUM_HASH_LENGTH;
316 
317 	debug_info("formatted command: %s size: %d checksum: 0x%s", *buffer, *size, checksum_hash);
318 
319 	if (encoded_command)
320 		free(encoded_command);
321 
322 	if (encoded)
323 		free(encoded);
324 }
325 
debugserver_client_send_ack(debugserver_client_t client)326 static debugserver_error_t debugserver_client_send_ack(debugserver_client_t client)
327 {
328 	debug_info("sending ACK");
329 	return debugserver_client_send(client, "+", sizeof(char), NULL);
330 }
331 
debugserver_client_send_noack(debugserver_client_t client)332 static debugserver_error_t debugserver_client_send_noack(debugserver_client_t client)
333 {
334 	debug_info("sending !ACK");
335 	return debugserver_client_send(client, "-", sizeof(char), NULL);
336 }
337 
debugserver_client_set_ack_mode(debugserver_client_t client,int enabled)338 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_ack_mode(debugserver_client_t client, int enabled)
339 {
340 	if (!client)
341 		return DEBUGSERVER_E_INVALID_ARG;
342 
343 	client->noack_mode = (enabled == 0)? 1: 0;
344 
345 	debug_info("ack mode: %s", client->noack_mode == 0 ? "on": "off");
346 
347 	return DEBUGSERVER_E_SUCCESS;
348 }
349 
debugserver_client_receive_internal_check(debugserver_client_t client,char * received_char)350 static int debugserver_client_receive_internal_check(debugserver_client_t client, char* received_char)
351 {
352 	debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
353 	int did_receive_char = 0;
354 	char buffer = 0;
355 	uint32_t bytes = 0;
356 
357 	/* we loop here as we expect an answer */
358 	res = debugserver_client_receive_with_timeout(client, &buffer, sizeof(char), &bytes, 1000);
359 	if (res == DEBUGSERVER_E_SUCCESS && received_char[0] != 0) {
360 		if (memcmp(&buffer, received_char, sizeof(char)) == 0) {
361 			did_receive_char = 1;
362 		}
363 	} else {
364 		did_receive_char = 0;
365 	}
366 
367 	if (!did_receive_char) {
368 		memcpy(received_char, &buffer, sizeof(char));
369 	}
370 
371 	return did_receive_char;
372 }
373 
debugserver_client_receive_response(debugserver_client_t client,char ** response,size_t * response_size)374 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size)
375 {
376 	debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
377 
378 	int should_receive = 1;
379 	int skip_prefix = 0;
380 	char* command_prefix = strdup("$");
381 
382 	char* buffer = NULL;
383 	uint32_t buffer_size = 0;
384 	uint32_t buffer_capacity = 0;
385 
386 	if (response)
387 		*response = NULL;
388 
389 	if (!client->noack_mode) {
390 		char ack[2] = {'+', '\0'};
391 		debug_info("attempting to receive ACK %c", *ack);
392 		should_receive = debugserver_client_receive_internal_check(client, ack);
393 		debug_info("received char: %c", *ack);
394 		if (strncmp(ack, command_prefix, sizeof(char)) == 0) {
395 			should_receive = 1;
396 			skip_prefix = 1;
397 			buffer = malloc(1024);
398 			buffer_capacity = 1024;
399 			strcpy(buffer, command_prefix);
400 			buffer_size += sizeof(char);
401 			debug_info("received ACK");
402 		}
403 	}
404 
405 	debug_info("should_receive: %d, skip_prefix: %d", should_receive, skip_prefix);
406 
407 	if (should_receive && !skip_prefix) {
408 		debug_info("attempting to receive prefix");
409 		should_receive = debugserver_client_receive_internal_check(client, command_prefix);
410 		debug_info("received command_prefix: %c", *command_prefix);
411 		if (should_receive) {
412 			if (buffer) {
413 				strcpy(buffer, command_prefix);
414 			} else {
415 				buffer = malloc(1024);
416 				buffer_capacity = 1024;
417 				strcpy(buffer, command_prefix);
418 				buffer_size += sizeof(char);
419 			}
420 		}
421 	}
422 
423 	debug_info("buffer: %*s, should_receive: %d, skip_prefix: %d", buffer_size, buffer, should_receive, skip_prefix);
424 
425 	if (should_receive) {
426 		uint32_t checksum_length = DEBUGSERVER_CHECKSUM_HASH_LENGTH;
427 		int receiving_checksum_response = 0;
428 		debug_info("attempting to read up response until checksum");
429 
430 		while ((checksum_length > 0)) {
431 			char data[2] = {'#', '\0'};
432 			if (debugserver_client_receive_internal_check(client, data)) {
433 				receiving_checksum_response = 1;
434 			}
435 			if (receiving_checksum_response) {
436 				checksum_length--;
437 			}
438 			if (buffer_size + 1 >= buffer_capacity) {
439 				char* newbuffer = realloc(buffer, buffer_capacity+1024);
440 				if (!newbuffer) {
441 					return DEBUGSERVER_E_UNKNOWN_ERROR;
442 				}
443 				buffer = newbuffer;
444 				buffer[buffer_capacity] = '\0';
445 				buffer_capacity += 1024;
446 			}
447 			strcat(buffer, data);
448 			buffer_size += sizeof(char);
449 		}
450 		debug_info("validating response checksum...");
451 		if (client->noack_mode || debugserver_response_is_checksum_valid(buffer, buffer_size)) {
452 			if (response) {
453 				/* assemble response string */
454 				uint32_t resp_size = sizeof(char) * (buffer_size - DEBUGSERVER_CHECKSUM_HASH_LENGTH - 1);
455 				*response = (char*)malloc(resp_size + 1);
456 				memcpy(*response, buffer + 1, resp_size);
457 				(*response)[resp_size] = '\0';
458 				if (response_size) *response_size = resp_size;
459 			}
460 			if (!client->noack_mode) {
461 				/* confirm valid command */
462 				debugserver_client_send_ack(client);
463 			}
464 		} else {
465 			/* response was invalid */
466 			res = DEBUGSERVER_E_RESPONSE_ERROR;
467 			if (!client->noack_mode) {
468 				/* report invalid command */
469 				debugserver_client_send_noack(client);
470 			}
471 		}
472 	}
473 
474 	if (response) {
475 		debug_info("response: %s", *response);
476 	}
477 
478 	if (buffer)
479 		free(buffer);
480 
481 	if (command_prefix)
482 		free(command_prefix);
483 
484 	return res;
485 }
486 
debugserver_client_send_command(debugserver_client_t client,debugserver_command_t command,char ** response,size_t * response_size)487 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size)
488 {
489 	debugserver_error_t res = DEBUGSERVER_E_SUCCESS;
490 	int i;
491 	uint32_t bytes = 0;
492 
493 	char* send_buffer = NULL;
494 	uint32_t send_buffer_size = 0;
495 
496 	char* command_arguments = NULL;
497 
498 	/* concat all arguments */
499 	for (i = 0; i < command->argc; i++) {
500 		debug_info("argv[%d]: %s", i, command->argv[i]);
501 		command_arguments = string_append(command_arguments, command->argv[i], NULL);
502 	}
503 
504 	debug_info("command_arguments(%d): %s", command->argc, command_arguments);
505 
506 	/* encode command arguments, add checksum if required and assemble entire command */
507 	debugserver_format_command("$", command->name, command_arguments, 1, &send_buffer, &send_buffer_size);
508 
509 	debug_info("sending encoded command: %s", send_buffer);
510 
511 	res = debugserver_client_send(client, send_buffer, send_buffer_size, &bytes);
512 	debug_info("command result: %d", res);
513 	if (res != DEBUGSERVER_E_SUCCESS) {
514 		goto cleanup;
515 	}
516 
517 	/* receive response */
518 	res = debugserver_client_receive_response(client, response, response_size);
519 	debug_info("response result: %d", res);
520 	if (res != DEBUGSERVER_E_SUCCESS) {
521 		goto cleanup;
522 	}
523 
524 	if (response) {
525 		debug_info("received response: %s", *response);
526 	}
527 
528 	/* disable sending ack on the client */
529 	if (!strncmp(command->name, "QStartNoAckMode", 16)) {
530 		debugserver_client_set_ack_mode(client, 0);
531 	}
532 
533 cleanup:
534 	if (command_arguments)
535 		free(command_arguments);
536 
537 	if (send_buffer)
538 		free(send_buffer);
539 
540 	return res;
541 }
542 
debugserver_client_set_environment_hex_encoded(debugserver_client_t client,const char * env,char ** response)543 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response)
544 {
545 	if (!client || !env)
546 		return DEBUGSERVER_E_INVALID_ARG;
547 
548 	debugserver_error_t result = DEBUGSERVER_E_UNKNOWN_ERROR;
549 	char* env_tmp = strdup(env);
550 	char* env_arg[2] = { env_tmp, NULL };
551 
552 	debugserver_command_t command = NULL;
553 	debugserver_command_new("QEnvironmentHexEncoded:", 1, env_arg, &command);
554 	result = debugserver_client_send_command(client, command, response, NULL);
555 	debugserver_command_free(command);
556 
557 	free(env_tmp);
558 
559 	return result;
560 }
561 
debugserver_client_set_argv(debugserver_client_t client,int argc,char * argv[],char ** response)562 LIBIMOBILEDEVICE_API debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response)
563 {
564 	if (!client || !argc)
565 		return DEBUGSERVER_E_INVALID_ARG;
566 
567 	debugserver_error_t result = DEBUGSERVER_E_UNKNOWN_ERROR;
568 	char *pkt = NULL;
569 	int pkt_len = 0;
570 	int i = 0;
571 
572 	/* calculate total length */
573 	while (i < argc && argv && argv[i]) {
574 		char *prefix = NULL;
575 		asprintf(&prefix, ",%d,%d,", (int)strlen(argv[i]) * 2, i);
576 		pkt_len += (int)strlen(prefix) + (int)strlen(argv[i]) * 2;
577 		free(prefix);
578 		i++;
579 	}
580 
581 	/* allocate packet and initialize it */
582 	pkt = (char *) malloc(pkt_len + 1);
583 	memset(pkt, 0, pkt_len + 1);
584 
585 	char *pktp = pkt;
586 
587 	i = 0;
588 	while (i < argc && argv && argv[i]) {
589 		debug_info("argv[%d] = \"%s\"", i, argv[i]);
590 
591 		char *prefix = NULL;
592 		char *m = NULL;
593 		int arg_len = strlen(argv[i]);
594 		int arg_hexlen = arg_len * 2;
595 
596 		asprintf(&prefix, ",%d,%d,", arg_hexlen, i);
597 
598 		m = (char *) malloc(arg_hexlen);
599 		char *p = m;
600 		char *q = (char*)argv[i];
601 		while (*q) {
602 			*p++ = DEBUGSERVER_HEX_ENCODE_FIRST_BYTE(*q);
603 			*p++ = DEBUGSERVER_HEX_ENCODE_SECOND_BYTE(*q);
604 			q++;
605 		}
606 
607 		memcpy(pktp, prefix, strlen(prefix));
608 		pktp += strlen(prefix);
609 
610 		memcpy(pktp, m, arg_hexlen);
611 		pktp += arg_hexlen;
612 
613 		free(prefix);
614 		free(m);
615 
616 		i++;
617 	}
618 
619 	pkt[0] = 'A';
620 
621 	debugserver_command_t command = NULL;
622 	debugserver_command_new(pkt, 0, NULL, &command);
623 	result = debugserver_client_send_command(client, command, response, NULL);
624 	debugserver_command_free(command);
625 
626 	if (pkt)
627 		free(pkt);
628 
629 	return result;
630 }
631