[geany/geany-plugins] eed4e1: debugger: Use the GDB/MI module to parse GDB output in the GDB module

Colomban Wendling git-noreply at xxxxx
Sun Nov 15 17:28:22 UTC 2015


Branch:      refs/heads/master
Author:      Colomban Wendling <ban at herbesfolles.org>
Committer:   Colomban Wendling <ban at herbesfolles.org>
Date:        Sat, 25 Oct 2014 22:05:41 UTC
Commit:      eed4e1391478298bd62a0179798b8d4fa0b9a2c8
             https://github.com/geany/geany-plugins/commit/eed4e1391478298bd62a0179798b8d4fa0b9a2c8

Log Message:
-----------
debugger: Use the GDB/MI module to parse GDB output in the GDB module

This is likely to *NOT* be completely compatible with what the original
code did.  There are some explicitly different things that may either
have been errors in the old code or changes in GDB output.

The changes seem (basic testing) to work fine on Debian's GDB 7.7.1.

NOTE: There is currently no conversion from the locale encoding to
UTF-8.  The GDB/MI module decodes the 7bit strings from GDB, but they
probably encode locale-encoded data.  This means this probably won't
work reliably on non-UTF-8 locales without an appropriate conversion.
"Appropriate conversion" yet has to be defined -- but as UTF-8 covers
all of Unicode it probably is OK to convert back and forth even when
not strictly required, it should at worse be useless.


Modified Paths:
--------------
    debugger/src/dbm_gdb.c

Modified: debugger/src/dbm_gdb.c
865 lines changed, 315 insertions(+), 550 deletions(-)
===================================================================
@@ -38,6 +38,7 @@ extern GeanyData		*geany_data;
 
 #include "breakpoint.h"
 #include "debug_module.h"
+#include "gdb_mi.h"
 
 /* module features */
 #define MODULE_FEATURES MF_ASYNC_BREAKS
@@ -312,19 +313,19 @@ static gboolean on_read_async_output(GIOChannel * src, GIOCondition cond, gpoint
 {
 	gchar *line;
 	gsize length;
+	struct gdb_mi_record *record;
 	
 	if (G_IO_STATUS_NORMAL != g_io_channel_read_line(src, &line, NULL, &length, NULL))
 		return TRUE;		
 
-	*(line + length) = '\0';
+	record = gdb_mi_record_parse(line);
 
-	if ('^' == line[0])
+	if (record && record->type == '^')
 	{
 		/* got some result */
 
 		GList *lines;
 		GList *commands = (GList*)data;
-		gchar *coma;
 
 		if (gdb_id_out)
 		{
@@ -336,16 +337,7 @@ static gboolean on_read_async_output(GIOChannel * src, GIOCondition cond, gpoint
 		g_list_foreach(lines, (GFunc)g_free, NULL);
 		g_list_free (lines);
 
-		coma = strchr(line, ',');
-		if (coma)
-		{
-			*coma = '\0';
-			coma++;
-		}
-		else
-			coma = line + strlen(line);
-		
-		if (!strcmp(line, "^done"))
+		if (!strcmp(record->klass, "done"))
 		{
 			/* command completed succesfully - run next command if exists */
 			if (commands->next)
@@ -392,13 +384,12 @@ static gboolean on_read_async_output(GIOChannel * src, GIOCondition cond, gpoint
 			{
 				if (item->format_error_message)
 				{
-					gchar* gdb_msg = g_strcompress(strstr(coma, "msg=\"") + strlen("msg=\""));
+					const gchar* gdb_msg = gdb_mi_result_var(record->first, "msg", GDB_MI_VAL_STRING);
 
 					GString *msg = g_string_new("");
 					g_string_printf(msg, item->error_message->str, gdb_msg);
 					dbg_cbs->report_error(msg->str);
 
-					g_free(gdb_msg);
 					g_string_free(msg, FALSE);
 				}
 				else
@@ -414,6 +405,7 @@ static gboolean on_read_async_output(GIOChannel * src, GIOCondition cond, gpoint
 		}
 	}
 
+	gdb_mi_record_free(record);
 	g_free(line);
 
 	return TRUE;
@@ -428,18 +420,18 @@ static gboolean on_read_from_gdb(GIOChannel * src, GIOCondition cond, gpointer d
 {
 	gchar *line;
 	gsize length;
-	gboolean prompt;
+	const gchar *id;
+	struct gdb_mi_record *record;
 	
 	if (G_IO_STATUS_NORMAL != g_io_channel_read_line(src, &line, NULL, &length, NULL))
 		return TRUE;		
 
-	prompt = !strcmp(line, GDB_PROMPT);
-	
-	*(line + length) = '\0';
+	record = gdb_mi_record_parse(line);
 
-	if (!prompt)
+	if (! record || record->type != GDB_MI_TYPE_PROMPT)
 	{
-		if ('~' == line[0])
+		line[length] = '\0';
+		if ((record && '~' == record->type) || '~' == line[0])
 		{
 			colorize_message(line);
 		}
@@ -450,147 +442,116 @@ static gboolean on_read_from_gdb(GIOChannel * src, GIOCondition cond, gpointer d
 			g_free(compressed);
 		}
 	}
-		
-	if (!target_pid && g_str_has_prefix(line, "=thread-group-created"))
+
+	if (! record)
 	{
-		*(strrchr(line, '\"')) = '\0';
-		target_pid = atoi(line + strlen("=thread-group-created,id=\""));
+		g_free(line);
+		return TRUE;
 	}
-	else if (!target_pid && g_str_has_prefix(line, "=thread-group-started"))
+
+	if (!target_pid &&
+		/* FIXME: =thread-group-created doesn't seem to exist, at least not in latest GDB docs */
+		(gdb_mi_record_matches(record, '=', "thread-group-created", "id", &id, NULL) ||
+		 gdb_mi_record_matches(record, '=', "thread-group-started", "pid", &id, NULL)))
 	{
-		*(strrchr(line, '\"')) = '\0';
-		target_pid = atoi(strrchr(line, '\"') + 1);
+		target_pid = atoi(id);
 	}
-	else if (g_str_has_prefix(line, "=thread-created"))
+	else if (gdb_mi_record_matches(record, '=', "thread-created", "id", &id, NULL))
 	{
-		int thread_id;
-
-		*(strrchr(line, ',') - 1) = '\0';
-		thread_id = atoi(line + strlen("=thread-created,id=\""));
-		dbg_cbs->add_thread(thread_id);
+		dbg_cbs->add_thread(atoi(id));
 	}
-	else if (g_str_has_prefix(line, "=thread-exited"))
+	else if (gdb_mi_record_matches(record, '=', "thread-exited", "id", &id, NULL))
 	{
-		int thread_id;
-
-		*(strrchr(line, ',') - 1) = '\0';
-		thread_id = atoi(line + strlen("=thread-exited,id=\""));
-		dbg_cbs->remove_thread(thread_id);
+		dbg_cbs->remove_thread(atoi(id));
 	}
-	else if (g_str_has_prefix(line, "=library-loaded") || g_str_has_prefix(line, "=library-unloaded"))
+	else if (gdb_mi_record_matches(record, '=', "library-loaded", NULL) ||
+			 gdb_mi_record_matches(record, '=', "library-unloaded", NULL))
 	{
 		file_refresh_needed = TRUE;
 	}
-	else if (*line == '*')
+	else if (gdb_mi_record_matches(record, '*', "running", NULL))
+		dbg_cbs->set_run();
+	else if (gdb_mi_record_matches(record, '*', "stopped", NULL))
 	{
-		/* asyncronous record found */
-		char *record = NULL;
-		if ( (record = strchr(line, ',')) )
+		const gchar *reason;
+
+		/* removing read callback (will pulling all output left manually) */
+		if (gdb_id_out)
 		{
-			*record = '\0';
-			record++;
+			g_source_remove(gdb_id_out);
+			gdb_id_out = 0;
+		}
+
+		/* looking for a reason to stop */
+		stop_reason = SR_EXITED_NORMALLY; /* somehow, sometimes there can be no stop reason */
+		if ((reason = gdb_mi_result_var(record->first, "reason", GDB_MI_VAL_STRING)) != NULL)
+		{
+			if (!strcmp(reason, "breakpoint-hit"))
+				stop_reason = SR_BREAKPOINT_HIT;
+			else if (!strcmp(reason, "end-stepping-range"))
+				stop_reason = SR_END_STEPPING_RANGE;
+			else if (!strcmp(reason, "signal-received"))
+				stop_reason = SR_SIGNAL_RECIEVED;
+			else if (!strcmp(reason, "exited-normally"))
+				stop_reason = SR_EXITED_NORMALLY;
+			else if (!strcmp(reason, "exited-signalled"))
+				stop_reason = SR_EXITED_SIGNALLED;
+			else if (!strcmp(reason, "exited"))
+				stop_reason = SR_EXITED_WITH_CODE;
 		}
-		else
-			record = line + strlen(line);
 		
-		if (!strcmp(line, "*running"))
-			dbg_cbs->set_run();
-		else if (!strcmp(line, "*stopped"))
+		if (SR_BREAKPOINT_HIT == stop_reason || SR_END_STEPPING_RANGE == stop_reason || SR_SIGNAL_RECIEVED == stop_reason)
 		{
-			char *reason;
+			const gchar *thread_id = gdb_mi_result_var(record->first, "thread-id", GDB_MI_VAL_STRING);
 
-			/* removing read callback (will pulling all output left manually) */
-			if (gdb_id_out)
-			{
-				g_source_remove(gdb_id_out);
-				gdb_id_out = 0;
-			}
+			active_frame = 0;
 
-			/* looking for a reason to stop */
-			reason = strstr(record, "reason=\"");
-			if (reason)
-			{
-				char *next;
-
-				reason += strlen("reason=\"");
-				next = strstr(reason, "\"") + 1;
-				*(next - 1) = '\0';
-				if (!strcmp(reason, "breakpoint-hit"))
-					stop_reason = SR_BREAKPOINT_HIT;
-				else if (!strcmp(reason, "end-stepping-range"))
-					stop_reason = SR_END_STEPPING_RANGE;
-				else if (!strcmp(reason, "signal-received"))
-					stop_reason = SR_SIGNAL_RECIEVED;
-				else if (!strcmp(reason, "exited-normally"))
-					stop_reason = SR_EXITED_NORMALLY;
-				else if (!strcmp(reason, "exited-signalled"))
-					stop_reason = SR_EXITED_SIGNALLED;
-				else if (!strcmp(reason, "exited"))
-					stop_reason = SR_EXITED_WITH_CODE;
-			}
-			else
+			if (SR_BREAKPOINT_HIT == stop_reason || SR_END_STEPPING_RANGE == stop_reason)
 			{
-				/* somehow, sometimes there can be no stop reason */
-				stop_reason = SR_EXITED_NORMALLY;
-			}
-			
-			if (SR_BREAKPOINT_HIT == stop_reason || SR_END_STEPPING_RANGE == stop_reason || SR_SIGNAL_RECIEVED == stop_reason)
-			{
-				gchar *thread_id = strstr(reason + strlen(reason) + 1,"thread-id=\"") + strlen("thread-id=\"");
-				*(strchr(thread_id, '\"')) = '\0'; 
-				
-				active_frame = 0;
+				/* update autos */
+				update_autos();
 
-				if (SR_BREAKPOINT_HIT == stop_reason || SR_END_STEPPING_RANGE == stop_reason)
-				{
-					/* update autos */
-					update_autos();
-			
-					/* update watches */
-					update_watches();
-			
-					/* update files */
-					if (file_refresh_needed)
-					{
-						update_files();
-						file_refresh_needed = FALSE;
-					}
-
-					dbg_cbs->set_stopped(atoi(thread_id));
-				}
-				else
+				/* update watches */
+				update_watches();
+
+				/* update files */
+				if (file_refresh_needed)
 				{
-					if (!requested_interrupt)
-						dbg_cbs->report_error(_("Program received a signal"));
-					else
-						requested_interrupt = FALSE;
-						
-					dbg_cbs->set_stopped(atoi(thread_id));
+					update_files();
+					file_refresh_needed = FALSE;
 				}
 			}
-			else if (stop_reason == SR_EXITED_NORMALLY || stop_reason == SR_EXITED_SIGNALLED || stop_reason == SR_EXITED_WITH_CODE)
+			else
 			{
-				if (stop_reason == SR_EXITED_WITH_CODE)
-				{
-					gchar *code;
-					gchar *message;
+				if (!requested_interrupt)
+					dbg_cbs->report_error(_("Program received a signal"));
+				else
+					requested_interrupt = FALSE;
+			}
 
-					code = strstr(reason + strlen(reason) + 1,"exit-code=\"") + strlen("exit-code=\"");
-					*(strchr(code, '\"')) = '\0';
-					message = g_strdup_printf(_("Program exited with code \"%i\""), (int)(char)strtol(code, NULL, 8));
-					dbg_cbs->report_error(message);
+			dbg_cbs->set_stopped(thread_id ? atoi(thread_id) : 0);
+		}
+		else if (stop_reason == SR_EXITED_NORMALLY || stop_reason == SR_EXITED_SIGNALLED || stop_reason == SR_EXITED_WITH_CODE)
+		{
+			if (stop_reason == SR_EXITED_WITH_CODE)
+			{
+				const gchar *exit_code = gdb_mi_result_var(record->first, "exit-code", GDB_MI_VAL_STRING);
+				long int code = exit_code ? strtol(exit_code, NULL, 8) : 0;
+				gchar *message;
 
-					g_free(message);
-				}
+				message = g_strdup_printf(_("Program exited with code \"%i\""), (int)(char)code);
+				dbg_cbs->report_error(message);
 
-				stop();
+				g_free(message);
 			}
+
+			stop();
 		}
 	}
-	else if (g_str_has_prefix (line, "^error"))
+	else if (gdb_mi_record_matches(record, '^', "error", NULL))
 	{
 		GList *lines, *iter;
-		char *msg;
+		const gchar *msg = gdb_mi_result_var(record->first, "msg", GDB_MI_VAL_STRING);
 
 		/* removing read callback (will pulling all output left manually) */
 		if (gdb_id_out)
@@ -602,17 +563,12 @@ static gboolean on_read_from_gdb(GIOChannel * src, GIOCondition cond, gpointer d
 		/* set debugger stopped if is running */
 		if (DBS_STOPPED != debug_get_state())
 		{
-			gchar *thread_id = strstr(line + strlen(line) + 1,"thread-id=\"");
-			*(strchr(thread_id, '\"')) = '\0'; 
+			/* FIXME: does GDB/MI ever return a thread-id with an error?? */
+			const gchar *thread_id = gdb_mi_result_var(record->first, "thread-id", GDB_MI_VAL_STRING);
 
-			dbg_cbs->set_stopped(atoi(thread_id));
+			dbg_cbs->set_stopped(thread_id ? atoi(thread_id) : 0);
 		}
 
-		/* get message */
-		msg = strstr(line, "msg=\"") + strlen("msg=\"");
-		*strrchr(msg, '\"') = '\0';
-		msg = g_strcompress(msg);
-		
 		/* reading until prompt */
 		lines = read_until_prompt();
 		for (iter = lines; iter; iter = iter->next)
@@ -626,11 +582,10 @@ static gboolean on_read_from_gdb(GIOChannel * src, GIOCondition cond, gpointer d
 
 		/* send error message */
 		dbg_cbs->report_error(msg);
-
-		g_free(msg);
 	}
 
 	g_free(line);
+	gdb_mi_record_free(record);
 
 	return TRUE;
 }
@@ -658,7 +613,7 @@ static void exec_async_command(const gchar* command)
  * i.e. reading output right
  * after execution
  */ 
-static result_class exec_sync_command(const gchar* command, gboolean wait4prompt, gchar** command_record)
+static result_class exec_sync_command(const gchar* command, gboolean wait4prompt, struct gdb_mi_record ** command_record)
 {
 	GList *lines, *iter;
 	result_class rc;
@@ -673,6 +628,9 @@ static result_class exec_sync_command(const gchar* command, gboolean wait4prompt
 	if (!wait4prompt)
 		return RC_DONE;
 	
+	if (command_record)
+		*command_record = NULL;
+
 	lines = read_until_prompt();
 
 #ifdef DEBUG_OUTPUT
@@ -687,42 +645,34 @@ static result_class exec_sync_command(const gchar* command, gboolean wait4prompt
 	for (iter = lines; iter; iter = iter->next)
 	{
 		gchar *line = (gchar*)iter->data;
+		struct gdb_mi_record *record = gdb_mi_record_parse(line);
 
-		if ('^' == line[0])
+		if (record && '^' == record->type)
 		{
-			gchar* coma = strchr(line, ',');
-			if (coma)
-			{
-				*coma = '\0';
-				coma++;
-			}
-			else
-				coma = line + strlen(line);
-			
-			if (command_record)
-			{
-				*command_record = (gchar*)g_malloc(strlen(coma) + 1);
-				strcpy(*command_record, coma);
-			}
-			
-			if (!strcmp(line, "^done"))
+			if (gdb_mi_record_matches(record, '^', "done", NULL))
 				rc = RC_DONE;
-			else if (!strcmp(line, "^error"))
+			else if (gdb_mi_record_matches(record, '^', "error", NULL))
 			{
 				/* save error message */
-				gchar* msg = g_strcompress(strstr(coma, "msg=\"") + strlen("msg=\""));
-				strncpy(err_message, msg, G_N_ELEMENTS(err_message) - 1);
-				g_free(msg);
+				const gchar *msg = gdb_mi_result_var(record->first, "msg", GDB_MI_VAL_STRING);
+				strncpy(err_message, msg ? msg : "", G_N_ELEMENTS(err_message) - 1);
 				
 				rc = RC_ERROR;
 			}
-			else if (!strcmp(line, "^exit"))
+			else if (gdb_mi_record_matches(record, '^', "exit", NULL))
 				rc = RC_EXIT;
+
+			if (command_record)
+			{
+				*command_record = record;
+				record = NULL;
+			}
 		}
-		else if ('&' != line[0])
+		else if (! record || '&' != record->type)
 		{
 			colorize_message (line);
 		}
+		gdb_mi_record_free(record);
 	}
 	
 	g_list_foreach(lines, (GFunc)g_free, NULL);
@@ -973,43 +923,41 @@ static void execute_until(const gchar *file, int line)
  */
 static int get_break_number(char* file, int line)
 {
-	gchar *record, *bstart;
+	struct gdb_mi_record *record;
+	const struct gdb_mi_result *table, *body, *bkpt;
 
 	exec_sync_command("-break-list", TRUE, &record);
-	bstart = record;
+	if (! record)
+		return -1;
 
-	while ( (bstart = strstr(bstart, "bkpt=")) )
+	table = gdb_mi_result_var(record->first, "BreakpointTable", GDB_MI_VAL_LIST);
+	body = gdb_mi_result_var(table, "body", GDB_MI_VAL_LIST);
+	gdb_mi_result_foreach_matched (bkpt, body, "bkpt", GDB_MI_VAL_LIST)
 	{
-		gchar *fname, *file_quoted;
-		int num, bline;
-		gboolean break_found;
+		const gchar *number = gdb_mi_result_var(bkpt->val->list, "number", GDB_MI_VAL_STRING);
+		const gchar *location = gdb_mi_result_var(bkpt->val->list, "original-location", GDB_MI_VAL_STRING);
+		const gchar *colon;
+		gboolean break_found = FALSE;
 
-		bstart += strlen("bkpt={number=\"");
-		*strchr(bstart, '\"') = '\0';
-		num = atoi(bstart);
-		
-		bstart += strlen(bstart) + 1;
-		bstart = strstr(bstart, "original-location=\"") + strlen("original-location=\"");
-		*strchr(bstart, ':') = '\0';
-		fname = bstart;
-		
-		bstart += strlen(bstart) + 1;
-		*strchr(bstart, '\"') = '\0';
-		bline = atoi(bstart);
+		if (! number || ! location)
+			continue;
 		
-		file_quoted = g_strdup_printf("\\\"%s\\\"", file);
-		break_found = !strcmp(fname, file_quoted) && bline == line;
-		g_free(file_quoted);
-
+		colon = strrchr(location, ':');
+		if (colon && atoi(colon + 1) == line)
+		{
+			gchar *fname = g_strndup(location, colon - location);
+			/* FIXME: the check used to be made against \"file\" (e.g. file surrounded
+			 * by backslash-quote), but that's not at least how GDB 7.7 does it */
+			break_found = strcmp(fname, file) == 0;
+			g_free(fname);
+		}
 		if (break_found)
 		{
-			return num;
+			return atoi(number);
 		}
-		
-		bstart += strlen(bstart) + 1;
-	} 
+	}
 	
-	free(record);
+	gdb_mi_record_free(record);
 	
 	return -1;
 }
@@ -1023,45 +971,46 @@ static gboolean set_break(breakpoint* bp, break_set_activity bsa)
 	if (BSA_NEW_BREAK == bsa)
 	{
 		/* new breakpoint */
-
-		char *pos;
-		int number;
-		gchar *record = NULL;
+		struct gdb_mi_record *record;
+		const struct gdb_mi_result *bkpt;
+		const gchar *number;
+		int num = 0;
 
 		/* 1. insert breakpoint */
 		sprintf (command, "-break-insert \"\\\"%s\\\":%i\"", bp->file, bp->line);
-		if (RC_DONE != exec_sync_command(command, TRUE, &record))
+		if (RC_DONE != exec_sync_command(command, TRUE, &record) || !record)
 		{
-			g_free(record);
+			gdb_mi_record_free(record);
+			record = NULL;
 			sprintf (command, "-break-insert -f \"\\\"%s\\\":%i\"", bp->file, bp->line);
-			if (RC_DONE != exec_sync_command(command, TRUE, &record))
+			if (RC_DONE != exec_sync_command(command, TRUE, &record) || !record)
 			{
-				g_free(record);
+				gdb_mi_record_free(record);
 				return FALSE;
 			}
 		}
 		/* lookup break-number */
-		pos = strstr(record, "number=\"") + strlen("number=\"");
-		*strchr(pos, '\"') = '\0';
-		number = atoi(pos);
-		g_free(record);
+		bkpt = gdb_mi_result_var(record->first, "bkpt", GDB_MI_VAL_LIST);
+		if ((number = gdb_mi_result_var(bkpt, "number", GDB_MI_VAL_STRING)))
+			num = atoi(number);
+		gdb_mi_record_free(record);
 		/* 2. set hits count if differs from 0 */
 		if (bp->hitscount)
 		{
-			sprintf (command, "-break-after %i %i", number, bp->hitscount);
+			sprintf (command, "-break-after %i %i", num, bp->hitscount);
 			exec_sync_command(command, TRUE, NULL);
 		}
 		/* 3. set condition if exists */
 		if (strlen(bp->condition))
 		{
-			sprintf (command, "-break-condition %i %s", number, bp->condition);
+			sprintf (command, "-break-condition %i %s", num, bp->condition);
 			if (RC_DONE != exec_sync_command(command, TRUE, NULL))
 				return FALSE;
 		}
 		/* 4. disable if disabled */
 		if (!bp->enabled)
 		{
-			sprintf (command, "-break-disable %i", number);
+			sprintf (command, "-break-disable %i", num);
 			exec_sync_command(command, TRUE, NULL);
 		}
 		
@@ -1135,63 +1084,34 @@ static void set_active_frame(int frame_number)
  */
 static GList* get_stack(void)
 {
-	gchar* record = NULL;
+	struct gdb_mi_record *record = NULL;
+	const struct gdb_mi_result *stack_node, *frame_node;
 	GList *stack = NULL;
-	gchar **frames, **next;
-	result_class rc;
 
-	rc = exec_sync_command("-stack-list-frames", TRUE, &record);
-	if (RC_DONE != rc)
+	if (RC_DONE != exec_sync_command("-stack-list-frames", TRUE, &record) || ! record)
+	{
+		gdb_mi_record_free(record);
 		return NULL;
+	}
 
-	frames = g_strsplit(record, "frame=", 0);
-	next = frames + 1;
-	while (*next)
+	stack_node = gdb_mi_result_var(record->first, "stack", GDB_MI_VAL_LIST);
+	gdb_mi_result_foreach_matched (frame_node, stack_node, "frame", GDB_MI_VAL_LIST)
 	{
+		const gchar *addr = gdb_mi_result_var(frame_node->val->list, "addr", GDB_MI_VAL_STRING);
+		const gchar *func = gdb_mi_result_var(frame_node->val->list, "func", GDB_MI_VAL_STRING);
+		const gchar *line = gdb_mi_result_var(frame_node->val->list, "line", GDB_MI_VAL_STRING);
+		const gchar *file, *fullname;
 		frame *f = frame_new();
-		int line;
-		gchar *pos, *fullname, *file, *from;
-		
-		/* adresss */
-		pos = strstr(*next, "addr=\"") + strlen("addr=\"");
-		*strchr(pos, '\"') = '\0';
-		f->address = g_strdup(pos);
-		pos += strlen(pos) + 1;
-
-		/* function */
-		pos = strstr(pos, "func=\"") + strlen("func=\"");
-		*strchr(pos, '\"') = '\0';
-		f->function = g_strdup(pos);
-		pos += strlen(pos) + 1;
+
+		f->address = g_strdup(addr);
+		f->function = g_strdup(func);
 
 		/* file: fullname | file | from */
-		fullname = strstr(pos, "fullname=\"");
-		file = strstr(pos, "file=\"");
-		from = strstr(pos, "from=\"");
-		
-		if (fullname)
-		{
-			fullname += strlen("fullname=\"");
-			pos = fullname;
-			*strchr(pos, '\"') = '\0';
-			f->file = g_strdup(pos);
-			pos += strlen(pos) + 1;
-		}
-		else if (file)
-		{
-			file += strlen("file=\"");
-			pos = file;
-			*strchr(pos, '\"') = '\0';
-			f->file = g_strdup(pos);
-			pos += strlen(pos) + 1;
-		}
-		else if (from)
+		if ((fullname = file = gdb_mi_result_var(frame_node->val->list, "fullname", GDB_MI_VAL_STRING)) ||
+			(file = gdb_mi_result_var(frame_node->val->list, "file", GDB_MI_VAL_STRING)) ||
+			(file = gdb_mi_result_var(frame_node->val->list, "from", GDB_MI_VAL_STRING)))
 		{
-			from += strlen("from=\"");
-			pos = from;
-			*strchr(pos, '\"') = '\0';
-			f->file = g_strdup(pos);
-			pos += strlen(pos) + 1;
+			f->file = g_strdup(file);
 		}
 		else
 		{
@@ -1202,168 +1122,16 @@ static GList* get_stack(void)
 		f->have_source = fullname ? TRUE : FALSE;
 
 		/* line */
-		line = 0;
-		pos = strstr(pos, "line=\"");
-		if (pos)
-		{
-			pos += strlen("line=\"");
-			*strchr(pos, '\"') = '\0';
-			line = atoi(pos);
-			pos += strlen(pos) + 1;
-		}
-		f->line = line;
+		f->line = line ? atoi(line) : 0;
 
 		stack = g_list_append(stack, f);
-
-		next++;
 	}
-	g_strfreev(frames);	
-	
-	free(record);
+	gdb_mi_record_free(record);
 	
 	return stack;
 }
 
 /*
- * unescapes hex values (\0xXXX) to readable chars
- * converting it from wide character value to char
- */
-static gchar* unescape_hex_values(gchar *src)
-{
-	GString *dest = g_string_new("");
-	
-	gchar *slash;
-	while ( (slash = strstr(src, "\\x")) )
-	{
-		char hex[4] = { 0, 0, 0, '\0' };
-		wchar_t wc;
-
-		/* append what has been missed
-		unescaping it in advance */
-		if (slash - src)
-		{
-			gchar *missed = g_strndup(src, slash - src);
-			gchar *unescaped = g_strcompress(missed);
-			g_string_append(dest, unescaped);
-			g_free(missed);
-			g_free(unescaped);
-		}
-
-		strncpy(hex, slash + 2, 3);
-		wc = (wchar_t)strtol(hex, NULL, 16);
-
-		if (iswalpha(wc))
-		{
-			gchar mb[5];
-			int len = wctomb(mb, wc);
-			mb[len] = '\0';
-			g_string_append(dest, mb);
-		}
-		else
-			g_string_append_len(dest, slash, 5);
-		
-		src = slash + 5;
-	}
-	
-	if (strlen(src))
-	{
-		gchar *unescaped = g_strcompress(src);
-		g_string_append(dest, unescaped);
-		g_free(unescaped);
-	}
-
-	return g_string_free(dest, FALSE);
-}
-
-/*
- * checks if pc pointer points to the 
- * valid printable charater
- */
-static gboolean isvalidcharacter(gchar *pc, gboolean utf8)
-{
-	if (utf8)
-		return -1 != g_utf8_get_char_validated(pc, -1);
-	else
-		return isprint(*pc);
-}
-
-/*
- * unescapes string, handles octal characters representations
- */
-static gchar* unescape_octal_values(gchar *text)
-{
-	GString *value = g_string_new("");
-	
-	gboolean utf8 = g_str_has_suffix(getenv("LANG"), "UTF-8");
-
-	gchar *tmp = g_strdup(text);
-	gchar *unescaped = g_strcompress(tmp);
-
-	gchar *pos = unescaped;
-	while (*pos)
-	{
-		if (isvalidcharacter(pos, utf8))
-		{
-			if (utf8)
-			{
-				/* valid utf8 character, copy to output
-				 and move to the next character */
-				gchar *next = g_utf8_next_char(pos);
-				g_string_append_len(value, pos, next - pos);
-				pos = next;
-			}
-			else
-			{
-				g_string_append_len(value, pos++, 1);
-			}
-		}
-		else
-		{
-			/* not a valid character, convert it to its octal representation
-			 and append to the result string */
-			gchar *invalid = g_strndup(pos, 1);
-			gchar *escaped = g_strescape(invalid, NULL);
-
-			g_string_append(value, escaped);
-
-			g_free(escaped);
-			g_free(invalid);
-
-			pos += 1;
-		}
-	}
-
-	g_free(tmp);
-
-	return g_string_free (value, FALSE);
-}
-
-/*
- * unescapes value string, handles hexidecimal and octal characters representations
- */
-static gchar *unescape(gchar *text)
-{
-	gchar *retval = NULL;
-
-	/* create string copy */
-	gchar *value = g_strdup(text);
-
-	/* make first unescaping */
-	gchar *tmp = g_strcompress(value);
-
-	/* make first unescaping */
-	if (strstr(tmp, "\\x"))
-		retval = unescape_hex_values(tmp);
-	else
-		retval = unescape_octal_values(tmp);
-
-	g_free(tmp);
-	g_free(value);
-
-	return retval;
-}
-
-/*
  * updates variables from vars list 
  */
 static void get_variables (GList *vars)
@@ -1375,56 +1143,51 @@ static void get_variables (GList *vars)
 		variable *var = (variable*)vars->data;
 
 		gchar *varname = var->internal->str;
-		gchar *record = NULL;
-		gchar *pos;
-		gchar *expression;
-		int numchild;
-		gchar *value;
+		struct gdb_mi_record *record = NULL;
+		const gchar *expression = NULL;
+		const gchar *numchild = NULL;
+		const gchar *value = NULL;
+		const gchar *type = NULL;
 
 		/* path expression */
 		sprintf(command, "-var-info-path-expression \"%s\"", varname);
 		exec_sync_command(command, TRUE, &record);
-		pos = strstr(record, "path_expr=\"") + strlen("path_expr=\"");
-		*(strrchr(pos, '\"')) = '\0';
-		expression = unescape(pos);
-		g_string_assign(var->expression, expression);
-		g_free(expression);
-		g_free(record);
+		if (record)
+			expression = gdb_mi_result_var(record->first, "path_expr", GDB_MI_VAL_STRING);
+		g_string_assign(var->expression, expression ? expression : "");
+		gdb_mi_record_free(record);
 		
 		/* children number */
 		sprintf(command, "-var-info-num-children \"%s\"", varname);
 		exec_sync_command(command, TRUE, &record);
-		pos = strstr(record, "numchild=\"") + strlen("numchild=\"");
-		*(strchr(pos, '\"')) = '\0';
-		numchild = atoi(pos);
-		var->has_children = numchild > 0;
-		g_free(record);
+		if (record)
+			numchild = gdb_mi_result_var(record->first, "numchild", GDB_MI_VAL_STRING);
+		var->has_children = numchild && atoi(numchild) > 0;
+		gdb_mi_record_free(record);
 
 		/* value */
 		sprintf(command, "-data-evaluate-expression \"%s\"", var->expression->str);
 		exec_sync_command(command, TRUE, &record);
-		pos = strstr(record, "value=\"");
-		if (!pos)
+		if (record)
+			value = gdb_mi_result_var(record->first, "value", GDB_MI_VAL_STRING);
+		if (!value)
 		{
-			g_free(record);
+			gdb_mi_record_free(record);
 			sprintf(command, "-var-evaluate-expression \"%s\"", varname);
 			exec_sync_command(command, TRUE, &record);
-			pos = strstr(record, "value=\"");
+			if (record)
+				value = gdb_mi_result_var(record->first, "value", GDB_MI_VAL_STRING);
 		}
-		pos +=  + strlen("value=\"");
-		*(strrchr(pos, '\"')) = '\0';
-		value = unescape(pos);
-		g_string_assign(var->value, value);
-		g_free(value);
-		g_free(record);
+		g_string_assign(var->value, value ? value : "");
+		gdb_mi_record_free(record);
 
 		/* type */
 		sprintf(command, "-var-info-type \"%s\"", varname);
 		exec_sync_command(command, TRUE, &record);
-		pos = strstr(record, "type=\"") + strlen("type=\"");
-		*(strchr(pos, '\"')) = '\0';
-		g_string_assign(var->type, pos);
-		g_free(record);
+		if (record)
+			type = gdb_mi_result_var(record->first, "type", GDB_MI_VAL_STRING);
+		g_string_assign(var->type, type ? type : "");
+		gdb_mi_record_free(record);
 
 		vars = vars->next;
 	}
@@ -1435,9 +1198,9 @@ static void get_variables (GList *vars)
  */
 static void update_files(void)
 {
-	GHashTable *ht = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
-	gchar *record = NULL;
-	gchar *pos;
+	GHashTable *ht;
+	struct gdb_mi_record *record = NULL;
+	const struct gdb_mi_result *files_node;
 
 	if (files)
 	{
@@ -1448,22 +1211,25 @@ static void update_files(void)
 	}
 
 	exec_sync_command("-file-list-exec-source-files", TRUE, &record);
-	pos = record;
-	while ( (pos = strstr(pos, "fullname=\"")) )
+	if (! record)
+		return;
+
+	ht = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
+
+	files_node = gdb_mi_result_var(record->first, "files", GDB_MI_VAL_LIST);
+	gdb_mi_result_foreach_matched (files_node, files_node, NULL, GDB_MI_VAL_LIST)
 	{
-		pos += strlen("fullname=\"");
-		*(strchr(pos, '\"')) = '\0';
-		if (!g_hash_table_lookup(ht, pos))
+		const gchar *fullname = gdb_mi_result_var(files_node->val->list, "fullname", GDB_MI_VAL_STRING);
+
+		if (fullname && !g_hash_table_lookup(ht, fullname))
 		{
-			g_hash_table_insert(ht, (gpointer)pos, (gpointer)1);
-			files = g_list_append(files, g_strdup(pos));
+			g_hash_table_insert(ht, (gpointer)fullname, (gpointer)1);
+			files = g_list_append(files, g_strdup(fullname));
 		}
-			
-		pos += strlen(pos) + 1;
 	}
 
 	g_hash_table_destroy(ht);
-	g_free(record);
+	gdb_mi_record_free(record);
 }
 
 /*
@@ -1495,8 +1261,8 @@ static void update_watches(void)
 	for (iter = watches; iter; iter = iter->next)
 	{
 		variable *var = (variable*)iter->data;
-		gchar *record = NULL;
-		gchar *pos;
+		struct gdb_mi_record *record = NULL;
+		const gchar *name;
 		gchar *escaped;
 
 		/* try to create variable */
@@ -1504,23 +1270,22 @@ static void update_watches(void)
 		sprintf(command, "-var-create - * \"%s\"", escaped);
 		g_free(escaped);
 
-		if (RC_DONE != exec_sync_command(command, TRUE, &record))
+		if (RC_DONE != exec_sync_command(command, TRUE, &record) || !record)
 		{
 			/* do not include to updating list, move to next watch */
 			var->evaluated = FALSE;
 			g_string_assign(var->internal, "");
-			g_free(record);
+			gdb_mi_record_free(record);
 			
 			continue;
 		}
 		
 		/* find and assign internal name */
-		pos = strstr(record, "name=\"") + strlen("name=\"");
-		*strchr(pos, '\"') = '\0'; 
-		g_string_assign(var->internal, pos);
-		g_free(record);			
+		name = gdb_mi_result_var(record->first, "name", GDB_MI_VAL_STRING);
+		g_string_assign(var->internal, name ? name : "");
+		gdb_mi_record_free(record);
 		
-		var->evaluated = TRUE;
+		var->evaluated = name != NULL;
 
 		/* add to updating list */
 		updating = g_list_append(updating, var);
@@ -1539,9 +1304,7 @@ static void update_watches(void)
 static void update_autos(void)
 {
 	gchar command[1000];
-	GList *unevaluated = NULL, *iter;
-	const char *gdb_commands[2];
-	int i;
+	GList *unevaluated = NULL, *vars = NULL, *iter;
 
 	/* remove all previous GDB variables for autos */
 	for (iter = autos; iter; iter = iter->next)
@@ -1558,55 +1321,67 @@ static void update_autos(void)
 	
 	/* add current autos to the list */
 	
-	gdb_commands[0] = g_strdup_printf("-stack-list-arguments 0 %i %i", active_frame, active_frame);
-	gdb_commands[1] = "-stack-list-locals 0";
-	for (i = 0; i < sizeof (gdb_commands) / sizeof(*gdb_commands); i++)
-	{
-		gchar *record = NULL, *pos;
+	struct gdb_mi_record *record = NULL;
 
-		result_class rc = exec_sync_command(gdb_commands[i], TRUE, &record);
-		if (RC_DONE != rc)
-			break;
+	sprintf(command, "-stack-list-arguments 0 %i %i", active_frame, active_frame);
+	if (RC_DONE == exec_sync_command(command, TRUE, &record) && record)
+	{
+		const struct gdb_mi_result *stack_args = gdb_mi_result_var(record->first, "stack-args", GDB_MI_VAL_LIST);
 
-		pos = record;
-		while ((pos = strstr(pos, "name=\"")))
+		gdb_mi_result_foreach_matched (stack_args, stack_args, "frame", GDB_MI_VAL_LIST)
 		{
-			variable *var;
-			gchar *create_record = NULL, *escaped;
+			const struct gdb_mi_result *args = gdb_mi_result_var(stack_args->val->list, "args", GDB_MI_VAL_LIST);
 
-			pos += strlen("name=\"");
-			*(strchr(pos, '\"')) = '\0';
+			gdb_mi_result_foreach_matched (args, args, "name", GDB_MI_VAL_STRING)
+			{
+				variable *var = variable_new(args->val->string, VT_ARGUMENT);
+				vars = g_list_append(vars, var);
+			}
+		}
+	}
+	gdb_mi_record_free(record);
 
-			var = variable_new(pos, i ? VT_LOCAL : VT_ARGUMENT);
+	if (RC_DONE == exec_sync_command("-stack-list-locals 0", TRUE, &record) && record)
+	{
+		const struct gdb_mi_result *locals = gdb_mi_result_var(record->first, "locals", GDB_MI_VAL_LIST);
 
-			/* create new gdb variable */
-			escaped = g_strescape(pos, NULL);
-			sprintf(command, "-var-create - * \"%s\"", escaped);
-			g_free(escaped);
+		gdb_mi_result_foreach_matched (locals, locals, "name", GDB_MI_VAL_STRING)
+		{
+			variable *var = variable_new(locals->val->string, VT_LOCAL);
+			vars = g_list_append(vars, var);
+		}
+	}
+	gdb_mi_record_free(record);
 
-			/* form new variable */
-			if (RC_DONE == exec_sync_command(command, TRUE, &create_record))
-			{
-				gchar *intname = strstr(create_record, "name=\"") + strlen ("name=\"");
-				*strchr(intname, '\"') = '\0';
-				var->evaluated = TRUE;
-				g_string_assign(var->internal, intname);
-				autos = g_list_append(autos, var);
+	for (iter = vars; iter; iter = iter->next)
+	{
+		variable *var = iter->data;
+		struct gdb_mi_record *create_record = NULL;
+		gchar *escaped;
+		const gchar *intname;
 
-				g_free(create_record);
-			}
-			else
-			{
-				var->evaluated = FALSE;
-				g_string_assign(var->internal, "");
-				unevaluated = g_list_append(unevaluated, var);
-			}
-			
-			pos += strlen(pos) + 1;
+		/* create new gdb variable */
+		escaped = g_strescape(var->name->str, NULL);
+		sprintf(command, "-var-create - * \"%s\"", escaped);
+		g_free(escaped);
+
+		/* form new variable */
+		if (RC_DONE == exec_sync_command(command, TRUE, &create_record) && create_record &&
+			(intname = gdb_mi_result_var(create_record->first, "name", GDB_MI_VAL_STRING)))
+		{
+			var->evaluated = TRUE;
+			g_string_assign(var->internal, intname);
+			autos = g_list_append(autos, var);
+		}
+		else
+		{
+			var->evaluated = FALSE;
+			g_string_assign(var->internal, "");
+			unevaluated = g_list_append(unevaluated, var);
 		}
-		g_free(record);
+		gdb_mi_record_free(create_record);
 	}
-	g_free((void*)gdb_commands[0]);
+	g_list_free(vars);
 	
 	/* get values for the autos (without incorrect variables) */
 	get_variables(autos);
@@ -1648,56 +1423,47 @@ static GList* get_children (gchar* path)
 	
 	gchar command[1000];
 	result_class rc;
-	gchar *record = NULL;
-	gchar *pos = NULL;
-	int numchild;
+	struct gdb_mi_record *record = NULL;
+	const gchar *numchild;
+	int n;
 
 	/* children number */
 	sprintf(command, "-var-info-num-children \"%s\"", path);
 	rc = exec_sync_command(command, TRUE, &record);
-	if (RC_DONE != rc)
+	if (RC_DONE != rc || ! record)
+	{
+		gdb_mi_record_free(record);
 		return NULL;
-	pos = strstr(record, "numchild=\"") + strlen("numchild=\"");
-	*(strchr(pos, '\"')) = '\0';
-	numchild = atoi(pos);
-	g_free(record);
-	if (!numchild)
+	}
+	numchild = gdb_mi_result_var(record->first, "numchild", GDB_MI_VAL_STRING);
+	n = numchild ? atoi(numchild) : 0;
+	gdb_mi_record_free(record);
+	if (!n)
 		return NULL;
 	
 	/* recursive get children and put into list */
 	sprintf(command, "-var-list-children \"%s\"", path);
 	rc = exec_sync_command(command, TRUE, &record);
-	if (RC_DONE == rc)
+	if (RC_DONE == rc && record)
 	{
-		pos = record;
-		while ( (pos = strstr(pos, "child={")) )
+		const struct gdb_mi_result *child_node = gdb_mi_result_var(record->first, "children", GDB_MI_VAL_LIST);
+
+		gdb_mi_result_foreach_matched (child_node, child_node, "child", GDB_MI_VAL_LIST)
 		{
-			gchar *name, *internal;
+			const gchar *internal = gdb_mi_result_var(child_node->val->list, "name", GDB_MI_VAL_STRING);
+			const gchar *name = gdb_mi_result_var(child_node->val->list, "exp", GDB_MI_VAL_STRING);
 			variable *var;
-			
-			/* name */
-			pos = strstr(pos, "name=\"") + strlen("name=\"");
-			*(strstr(pos, "\",exp=\"")) = '\0';
-			internal = pos;
-			pos += strlen(pos) + 1;
-
-			/* exp */
-			pos = strstr(pos, "exp=\"") + strlen("exp=\"");
-			*(strstr(pos, "\",numchild=\"")) = '\0';
-			
-			name = g_strcompress(pos);
-			
+
+			if (! name || ! internal)
+				continue;
+
 			var = variable_new2(name, internal, VT_CHILD);
 			var->evaluated = TRUE;
-			
-			pos += strlen(pos) + 1;
 
 			children = g_list_append(children, var);
-		
-			g_free(name);
 		}
 	}
-	g_free(record);
+	gdb_mi_record_free(record);
 	
 	get_variables(children);
 
@@ -1710,7 +1476,9 @@ static GList* get_children (gchar* path)
 static variable* add_watch(gchar* expression)
 {
 	gchar command[1000];
-	gchar *record = NULL, *escaped, *pos;
+	gchar *escaped;
+	struct gdb_mi_record *record = NULL;
+	const gchar *name;
 	GList *vars = NULL;
 	variable *var = variable_new(expression, VT_WATCH);
 
@@ -1721,21 +1489,20 @@ static variable* add_watch(gchar* expression)
 	sprintf(command, "-var-create - * \"%s\"", escaped);
 	g_free(escaped);
 
-	if (RC_DONE != exec_sync_command(command, TRUE, &record))
+	if (RC_DONE != exec_sync_command(command, TRUE, &record) || !record)
 	{
-		g_free(record);
+		gdb_mi_record_free(record);
 		return var;
 	}
 	
-	pos = strstr(record, "name=\"") + strlen("name=\"");
-	*strchr(pos, '\"') = '\0'; 
-	g_string_assign(var->internal, pos);
-	var->evaluated = TRUE;
+	name = gdb_mi_result_var(record->first, "name", GDB_MI_VAL_STRING);
+	g_string_assign(var->internal, name ? name : "");
+	var->evaluated = name != NULL;
 
 	vars = g_list_append(NULL, var);
 	get_variables(vars);
 
-	g_free(record);
+	gdb_mi_record_free(record);
 	g_list_free(vars);
 
 	return var;	
@@ -1767,23 +1534,21 @@ static void remove_watch(gchar* internal)
  */
 static gchar *evaluate_expression(gchar *expression)
 {
-	gchar *record = NULL, *pos;
+	struct gdb_mi_record *record = NULL;
+	gchar *value;
 	char command[1000];
-	result_class rc;
 
 	sprintf (command, "-data-evaluate-expression \"%s\"", expression);
-	rc = exec_sync_command(command, TRUE, &record);
-	
-	if (RC_DONE != rc)
+	if (RC_DONE != exec_sync_command(command, TRUE, &record) || ! record)
 	{
-		g_free(record);
+		gdb_mi_record_free(record);
 		return NULL;
 	}
 
-	pos = strstr(record, "value=\"") + strlen("value=\"");
-	*(strrchr(pos, '\"')) = '\0';
+	value = g_strdup(gdb_mi_result_var(record->first, "value", GDB_MI_VAL_STRING));
+	gdb_mi_record_free(record);
 
-	return unescape(pos);
+	return value;
 }
 
 /*



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Plugins-Commits mailing list