1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3     disassemble.c
4     Copyright (C) 2006 Sebastien Granjoux
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 /*#define DEBUG*/
26 #include <libanjuta/anjuta-debug.h>
27 
28 #include <libanjuta/interfaces/ianjuta-markable.h>
29 
30 
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include <string.h>
34 
35 #include "disassemble.h"
36 
37 #include "sparse_buffer.h"
38 #include "sparse_view.h"
39 
40 #include "plugin.h"
41 #include "queue.h"
42 
43 /* Constants
44  *---------------------------------------------------------------------------*/
45 
46 enum {DMA_DISASSEMBLY_BUFFER_BLOCK_SIZE = 256,
47 	DMA_DISASSEMBLY_SKIP_BEGINNING_LINE = 4,
48 	DMA_DISASSEMBLY_TAB_LENGTH = 4,
49 	DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH = 8,
50 	DMA_DISASSEMBLY_PAGE_DISTANCE = 4 * 60,
51 	DMA_DISASSEMBLY_VALID_ADDRESS = 0,
52 	DMA_DISASSEMBLY_KNOW_ADDRESS = -1,
53 	DMA_DISASSEMBLY_UNKNOWN_ADDRESS = -2};
54 
55 enum {DMA_DISASSEMBLY_KEEP_ALL,
56 	DMA_DISASSEMBLY_SKIP_BEGINNING};
57 
58 /* Types
59  *---------------------------------------------------------------------------*/
60 
61 typedef struct _DmaDisassemblyLine DmaDisassemblyLine;
62 typedef struct _DmaDisassemblyBufferNode DmaDisassemblyBufferNode;
63 
64 typedef struct _DmaDisassemblyBuffer DmaDisassemblyBuffer;
65 typedef struct _DmaDisassemblyBufferClass DmaDisassemblyBufferClass;
66 
67 typedef struct _DmaDisassemblyView DmaDisassemblyView;
68 typedef struct _DmaDisassemblyViewClass DmaDisassemblyViewClass;
69 
70 struct _DmaDisassemble
71 {
72 	DmaDebuggerQueue *debugger;
73 	DebugManagerPlugin *plugin;
74 	GtkWidget *window;
75 	GtkWidget *menu;
76 	DmaSparseBuffer* buffer;
77 	DmaSparseView* view;
78 };
79 
80 /* Disassembly buffer object
81  *---------------------------------------------------------------------------*/
82 
83 struct _DmaDisassemblyBuffer
84 {
85 	DmaSparseBuffer parent;
86 	DmaDebuggerQueue *debugger;
87 	gboolean pending;
88 };
89 
90 struct _DmaDisassemblyBufferClass
91 {
92 	DmaSparseBufferClass parent;
93 };
94 
95 struct _DmaDisassemblyLine
96 {
97 	gulong address;
98 	gchar* text;
99 };
100 
101 struct _DmaDisassemblyBufferNode
102 {
103 	DmaSparseBufferNode parent;
104 	guint size;
105 
106 	DmaDisassemblyLine data[];
107 };
108 
109 #define DMA_DISASSEMBLY_BUFFER_TYPE              (dma_disassembly_buffer_get_type ())
110 #define DMA_DISASSEMBLY_BUFFER(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), DMA_DISASSEMBLY_BUFFER_TYPE, DmaDisassemblyBuffer))
111 #define DMA_DISASSEMBLY_BUFFER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass),  DMA_DISASSEMBLY_BUFFER_TYPE, DmaDisassemblyBufferClass))
112 #define IS_DMA_DISASSEMBLY_BUFFER(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DMA_DISASSEMBLY_BUFFER_TYPE))
113 #define IS_DMA_DISASSEMBLY_BUFFER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass),  DMA_DISASSEMBLY_BUFFER_TYPE))
114 #define GET_DMA_DISASSEMBLY_BUFFER_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj),  DMA_DISASSEMBLY_BUFFER_TYPE, DmaDisassemblyBufferClass))
115 
116 static DmaSparseBufferClass *parent_buffer_class = NULL;
117 
118 static GType dma_disassembly_buffer_get_type (void);
119 
120 /* Disassembly iterator function
121  *---------------------------------------------------------------------------*/
122 
123 /*
124  * Iterator can be divided in 3 cases:
125  * 1. Iterator on valid address:
126  *		node != NULL
127  *		base = address
128  *		offset = 0
129  *		line = line number in node
130  * 2. Iterator on know address:
131  *		base = address
132  *		offset = 0
133  *		line = -1
134  * 3. Iterator on unknown address:
135  *		base = address (often known)
136  *	 	offset != 0 (could be 0 too)
137  *		line = -2
138  *---------------------------------------------------------------------------*/
139 
140 static gulong
dma_disassembly_get_address(DmaSparseIter * iter)141 dma_disassembly_get_address (DmaSparseIter *iter)
142 {
143 	return iter->base + iter->offset;
144 }
145 
146 static gboolean
dma_disassembly_iter_refresh(DmaSparseIter * iter)147 dma_disassembly_iter_refresh (DmaSparseIter *iter)
148 {
149 	/* Call this after updating node according to base */
150 	gint line = -1;
151 	DmaDisassemblyBufferNode *node = (DmaDisassemblyBufferNode *)iter->node;
152 
153 	if (iter->node != NULL)
154 	{
155 		/* Find line corresponding to base */
156 		if ((iter->node->lower <= iter->base) && (iter->base <= iter->node->upper))
157 		{
158 			/* Iterator in current node */
159 			if ((iter->line >= 0) && (iter->line < ((DmaDisassemblyBufferNode *)iter->node)->size)
160 				&& (((DmaDisassemblyBufferNode *)iter->node)->data[iter->line].address == iter->base))
161 			{
162 				/* Already get the right node */
163 				line = iter->line;
164 			}
165 			else
166 			{
167 				/* Search for correct line */
168 
169 				if (iter->offset >= 0)
170 				{
171 					for (line = 0; line < node->size; line++)
172 					{
173 						if (node->data[line].address >= iter->base) break;
174 					}
175 				}
176 				else
177 				{
178 					for (line = node->size - 1; line >= 0; line--)
179 					{
180 						if (node->data[line].address <= iter->base) break;
181 					}
182 				}
183 
184 				if (node->data[line].address == iter->base)
185 				{
186 					iter->line = line;
187 				}
188 				else if (iter->line >= DMA_DISASSEMBLY_VALID_ADDRESS)
189 				{
190 					iter->line = iter->offset == 0  ? DMA_DISASSEMBLY_KNOW_ADDRESS : DMA_DISASSEMBLY_UNKNOWN_ADDRESS;
191 				}
192 			}
193 		}
194 		else if (iter->base == iter->node->upper + 1)
195 		{
196 			line = node->size;
197 			if (iter->line >= DMA_DISASSEMBLY_VALID_ADDRESS)
198 			{
199 				iter->line = iter->offset == 0  ? DMA_DISASSEMBLY_KNOW_ADDRESS : DMA_DISASSEMBLY_UNKNOWN_ADDRESS;
200 			}
201 		}
202 		else
203 		{
204 			/* Invalid base address */
205 			if (iter->line >= DMA_DISASSEMBLY_VALID_ADDRESS)
206 			{
207 				iter->line = iter->offset == 0  ? DMA_DISASSEMBLY_KNOW_ADDRESS : DMA_DISASSEMBLY_UNKNOWN_ADDRESS;
208 			}
209 		}
210 	}
211 	else
212 	{
213 		/* Invalid base address */
214 		if (iter->line >= DMA_DISASSEMBLY_VALID_ADDRESS)
215 		{
216 			iter->line = iter->offset == 0  ? DMA_DISASSEMBLY_KNOW_ADDRESS : DMA_DISASSEMBLY_UNKNOWN_ADDRESS;
217 		}
218 	}
219 
220 	/* Try to reduce offset */
221 	if (line != -1)
222 	{
223 		if (iter->offset > 0)
224 		{
225 			/* Need to go upper if possible */
226 			guint up = (DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH + iter->offset - 1)/ DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH;
227 
228 			for (;;)
229 			{
230 				gint len = node->size - line;
231 
232 				if (up < len)
233 				{
234 					iter->node = (DmaSparseBufferNode *)node;
235 					iter->line = line + up;
236 					iter->base = node->data[iter->line].address;
237 					iter->offset = 0;
238 
239 					return TRUE;
240 				}
241 
242 				if (iter->node->upper == dma_sparse_buffer_get_upper (iter->buffer))
243 				{
244 					gboolean move = iter->line != node->size - 1;
245 
246 					iter->node = (DmaSparseBufferNode *)node;
247 					iter->line = node->size - 1;
248 					iter->base = node->data[iter->line].address;
249 					iter->offset = 0;
250 
251 					return move;
252 				}
253 
254 				up -= len;
255 
256 				if ((node->parent.next == NULL) || (node->parent.upper != node->parent.next->lower - 1))
257 				{
258 					/* No following node */
259 
260 					iter->node = (DmaSparseBufferNode *)node;
261 					iter->base = node->parent.upper + 1;
262 					iter->offset = up * DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH;
263 
264 					if (iter->line >= DMA_DISASSEMBLY_VALID_ADDRESS)
265 					{
266 						iter->line = iter->offset == 0  ? DMA_DISASSEMBLY_KNOW_ADDRESS : DMA_DISASSEMBLY_UNKNOWN_ADDRESS;
267 					}
268 
269 					break;
270 				}
271 
272 				node = (DmaDisassemblyBufferNode *)node->parent.next;
273 				line = 0;
274 			}
275 		}
276 		else if (iter->offset < 0)
277 		{
278 			/* Need to go down if possible */
279 			gint down = (- iter->offset) / DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH;
280 
281 			for (;;)
282 			{
283 				guint len = line;
284 
285 				if (down <= len)
286 				{
287 					iter->node = (DmaSparseBufferNode *)node;
288 					iter->line = line - down;
289 					iter->base = node->data[iter->line].address;
290 					iter->offset = 0;
291 
292 					return TRUE;
293 				}
294 
295 				if (iter->node->lower == dma_sparse_buffer_get_lower (iter->buffer))
296 				{
297 					gboolean move = iter->line != 0;
298 
299 					iter->node = (DmaSparseBufferNode *)node;
300 					iter->line = 0;
301 					iter->base = node->data[0].address;
302 					iter->offset = 0;
303 
304 					return move;
305 				}
306 
307 				down -= len;
308 
309 				if ((node->parent.prev == NULL) || (node->parent.lower != node->parent.prev->upper + 1))
310 				{
311 					/* No following node */
312 
313 					iter->node = (DmaSparseBufferNode *)node;
314 					iter->base = node->parent.lower;
315 					iter->offset = -down * DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH;
316 					if (iter->line >= DMA_DISASSEMBLY_VALID_ADDRESS)
317 					{
318 						iter->line = iter->offset == 0  ? DMA_DISASSEMBLY_KNOW_ADDRESS : DMA_DISASSEMBLY_UNKNOWN_ADDRESS;
319 					}
320 					break;
321 				}
322 
323 				node = (DmaDisassemblyBufferNode *)node->parent.prev;
324 				line = node->size;
325 			}
326 		}
327 	}
328 
329 	/* Round offset */
330 	if (iter->offset < 0)
331 	{
332 		gulong address;
333 		gboolean move = TRUE;
334 
335 		address = iter->offset + iter->base;
336 		if ((address < dma_sparse_buffer_get_lower (iter->buffer)) || (address > iter->base))
337 		{
338 			address = dma_sparse_buffer_get_lower (iter->buffer);
339 			move = FALSE;
340 		}
341 		address -= address % DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH;
342 		iter->offset = address - iter->base;
343 
344 		return move;
345 	}
346 	else if ((iter->offset > 0) || (iter->line == DMA_DISASSEMBLY_UNKNOWN_ADDRESS))
347 	{
348 		gulong address;
349 		gboolean move = TRUE;
350 
351 		address = iter->offset + iter->base;
352 		if ((address > dma_sparse_buffer_get_upper (iter->buffer)) || (address < iter->base))
353 		{
354 			address = dma_sparse_buffer_get_upper (iter->buffer);
355 			move = FALSE;
356 		}
357 		address -= address % DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH;
358 		iter->offset = address - iter->base;
359 
360 		return move;
361 	}
362 
363 	/* return FALSE if iterator reach the lower or upper limit */
364 	return TRUE;
365 }
366 
367 static gboolean
dma_disassembly_iter_backward_line(DmaSparseIter * iter)368 dma_disassembly_iter_backward_line (DmaSparseIter *iter)
369 {
370 	iter->offset -= DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH;
371 	return dma_disassembly_iter_refresh (iter);
372 }
373 
374 static gboolean
dma_disassembly_iter_forward_line(DmaSparseIter * iter)375 dma_disassembly_iter_forward_line (DmaSparseIter *iter)
376 {
377 	iter->offset += DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH;
378 	return dma_disassembly_iter_refresh (iter);
379 }
380 
381 
382 static void
dma_disassembly_iter_round(DmaSparseIter * iter,gboolean round_up)383 dma_disassembly_iter_round (DmaSparseIter *iter, gboolean round_up)
384 {
385 	iter->offset += round_up ? 1 : -1;
386 	dma_disassembly_iter_refresh (iter);
387 }
388 
389 static void
on_disassemble(const IAnjutaDebuggerInstructionDisassembly * block,DmaSparseBufferTransport * trans,GError * err)390 on_disassemble (const IAnjutaDebuggerInstructionDisassembly *block, DmaSparseBufferTransport *trans, GError *err)
391 {
392 	DmaDisassemblyBufferNode *node;
393 	DmaDisassemblyBuffer *buffer = (DmaDisassemblyBuffer *)trans->buffer;
394 	DmaSparseBufferNode *next;
395 	guint i;
396 	char *dst;
397 
398 	DEBUG_PRINT ("on disassemble %p", block);
399 
400 	if ((err != NULL) && !g_error_matches (err, IANJUTA_DEBUGGER_ERROR, IANJUTA_DEBUGGER_UNABLE_TO_ACCESS_MEMORY))
401 
402 	{
403 		/* Command has been cancelled */
404 		dma_sparse_buffer_free_transport (trans);
405 
406 		return;
407 	}
408 
409 	/* Find following block */
410 	DEBUG_PRINT("trans %p buffer %p trans->buffer %p trans->start %lu", trans, buffer, trans == NULL ? NULL : trans->buffer, trans == NULL ? 0 : trans->start);
411 	next = dma_sparse_buffer_lookup (DMA_SPARSE_BUFFER (buffer), trans->start + trans->length - 1);
412 	if ((next != NULL) && (next->upper <= trans->start)) next = NULL;
413 
414 	if (err != NULL)
415 	{
416 		gulong address = trans->start;
417 		gint len;
418 
419 		/* Create a dummy node */
420 		len = (trans->length + DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH - 1) / DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH;
421 		node = (DmaDisassemblyBufferNode *)g_malloc0 (sizeof(DmaDisassemblyBufferNode) + sizeof(DmaDisassemblyLine) * len);
422 		node->parent.lower = address;
423 		for (i = 0; i < len; i++)
424 		{
425 			if ((next != NULL) && (address >= next->lower)) break;
426 			node->data[i].address = address;
427 			node->data[i].text = "????????";
428 			address += DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH;
429 			address -= address % DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH;
430 		}
431 		node->size = i;
432 		if ((next != NULL) && (address >= next->lower))
433 		{
434 			address = next->lower -1;
435 		}
436 		else
437 		{
438 			address = trans->start + trans->length - 1;
439 		}
440 		node->parent.upper = address;
441 	}
442 	else
443 	{
444 		guint size = 0;
445 		guint line = 0;
446 
447 		/* Compute size of all data */
448 		/* use size -1 because last block has no data (NULL) */
449 		for (i = trans->tag == DMA_DISASSEMBLY_KEEP_ALL ? 0 : 4; i < block->size - 1; i++)
450 		{
451 			if (block->data[i].label)
452 			{
453 				size += strlen(block->data[i].label) + 2;
454 				line++;
455 			}
456 			size += strlen(block->data[i].text) + 1 + DMA_DISASSEMBLY_TAB_LENGTH;
457 			line++;
458 		}
459 
460 		node = (DmaDisassemblyBufferNode *)g_malloc0 (sizeof(DmaDisassemblyBufferNode) + sizeof(DmaDisassemblyLine) * line + size);
461 
462 		/* Copy all data */
463 		dst = (gchar *)&(node->data[line]);
464 		line = 0;
465 		for (i = trans->tag == DMA_DISASSEMBLY_KEEP_ALL ? 0 : DMA_DISASSEMBLY_SKIP_BEGINNING_LINE; i < block->size - 1; i++)
466 		{
467 			gsize len;
468 
469 			if ((next != NULL) && (block->data[i].address == next->lower)) break;
470 
471 			/* Add label if exist */
472 			if (block->data[i].label != NULL)
473 			{
474 				len = strlen(block->data[i].label);
475 
476 				node->data[line].address = block->data[i].address;
477 				node->data[line].text = dst;
478 
479 				memcpy(dst, block->data[i].label, len);
480 				dst[len] = ':';
481 				dst[len + 1] = '\0';
482 
483 				dst += len + 2;
484 				line++;
485 			}
486 
487 			/* Add disassembled instruction */
488 			len = strlen(block->data[i].text) + 1;
489 
490 			node->data[line].address = block->data[i].address;
491 			node->data[line].text = dst;
492 
493 			memset (dst, ' ', DMA_DISASSEMBLY_TAB_LENGTH);
494 			memcpy (dst + DMA_DISASSEMBLY_TAB_LENGTH, block->data[i].text, len);
495 			dst += len + DMA_DISASSEMBLY_TAB_LENGTH;
496 			line++;
497 		}
498 
499 		/* fill last block */
500 		node->size = line;
501 		node->parent.lower = node->data[0].address;
502 		node->parent.upper = block->data[i].address - 1;
503 
504 	}
505 
506 	dma_sparse_buffer_insert (DMA_SPARSE_BUFFER (buffer), (DmaSparseBufferNode *)node);
507 	dma_sparse_buffer_free_transport (trans);
508 	dma_sparse_buffer_changed (DMA_SPARSE_BUFFER (buffer));
509 }
510 
511 static void
dma_disassembly_buffer_insert_line(DmaSparseIter * iter,GtkTextIter * dst)512 dma_disassembly_buffer_insert_line (DmaSparseIter *iter, GtkTextIter *dst)
513 {
514 	DmaDisassemblyBuffer * dis = (DmaDisassemblyBuffer *)iter->buffer;
515 	GtkTextBuffer *buffer = gtk_text_iter_get_buffer (dst);
516 
517 	if (dis->debugger != NULL)
518 	{
519 		dma_sparse_iter_refresh (iter);
520 		if (iter->line < DMA_DISASSEMBLY_VALID_ADDRESS)
521 		{
522 			if (iter->buffer->pending == NULL)
523 			{
524 				DmaSparseIter end;
525 				DmaSparseBufferTransport *trans;
526 				gint i, j;
527 				gulong start_adr;
528 				gulong end_adr;
529 				gint margin;
530 
531 				/* If following line is define, get a block stopping here */
532 				dma_sparse_iter_copy (&end, iter);
533 				margin = 0;
534 				for (j = 0; j < DMA_DISASSEMBLY_BUFFER_BLOCK_SIZE / DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH; j++)
535 				{
536 					if (!dma_disassembly_iter_forward_line (&end))
537 					{
538 						end.offset = 0;
539 						end.base = dma_sparse_buffer_get_upper (end.buffer);
540 						break;
541 					}
542 					if (margin > DMA_DISASSEMBLY_SKIP_BEGINNING_LINE) break;
543 					if ((margin != 0) || (end.line >= DMA_DISASSEMBLY_VALID_ADDRESS)) margin++;
544 				}
545 				i = j;
546 				if (iter->line == DMA_DISASSEMBLY_UNKNOWN_ADDRESS)
547 				{
548 					for (i = j; i < DMA_DISASSEMBLY_BUFFER_BLOCK_SIZE / DMA_DISASSEMBLY_DEFAULT_LINE_LENGTH; i++)
549 					{
550 						if (!dma_disassembly_iter_backward_line (iter)) break;
551 						if (iter->line >= DMA_DISASSEMBLY_VALID_ADDRESS) break;
552 					}
553 				}
554 				start_adr = dma_sparse_iter_get_address (iter);
555 				end_adr = dma_sparse_iter_get_address (&end);
556 				trans = dma_sparse_buffer_alloc_transport (DMA_SPARSE_BUFFER (dis), i, 0);
557 				trans->tag = i != j ? DMA_DISASSEMBLY_SKIP_BEGINNING : DMA_DISASSEMBLY_KEEP_ALL;
558 				trans->start = start_adr;
559 				trans->length = end_adr - start_adr;
560 				if (end_adr == dma_sparse_buffer_get_upper (DMA_SPARSE_BUFFER (dis)))
561 				{
562 					trans->length++;
563 				}
564 				DEBUG_PRINT("get disassemble %lx %lx %ld trans %p buffer %p", start_adr, end_adr, trans->length, trans, trans->buffer);
565 				dma_queue_disassemble (dis->debugger, start_adr, end_adr + 1 - start_adr, (IAnjutaDebuggerCallback)on_disassemble, trans);
566 			}
567 		}
568 		else
569 		{
570 			/* Fill with known data */
571 			gtk_text_buffer_insert (buffer, dst, ((DmaDisassemblyBufferNode *)(iter->node))->data[iter->line].text, -1);
572 
573 			return;
574 		}
575 	}
576 
577 	/* Fill with unknow data */
578 	gtk_text_buffer_insert (buffer, dst, "??", 2);
579 }
580 
581 static void
dma_disassembly_buffer_class_init(DmaDisassemblyBufferClass * klass)582 dma_disassembly_buffer_class_init (DmaDisassemblyBufferClass *klass)
583 {
584 	DmaSparseBufferClass* buffer_class;
585 
586 	g_return_if_fail (klass != NULL);
587 
588 	parent_buffer_class = (DmaSparseBufferClass*) g_type_class_peek_parent (klass);
589 
590 	buffer_class = DMA_SPARSE_BUFFER_CLASS (klass);
591 
592 	buffer_class->refresh_iter = dma_disassembly_iter_refresh;
593 	buffer_class->round_iter = dma_disassembly_iter_round;
594 	buffer_class->insert_line = dma_disassembly_buffer_insert_line;
595 	buffer_class->forward_line = dma_disassembly_iter_forward_line;
596 	buffer_class->backward_line = dma_disassembly_iter_backward_line;
597 	buffer_class->get_address = dma_disassembly_get_address;
598 }
599 
600 static GType
dma_disassembly_buffer_get_type(void)601 dma_disassembly_buffer_get_type (void)
602 {
603 	static GType type = 0;
604 
605 	if (!type)
606 	{
607 		static const GTypeInfo type_info =
608 		{
609 			sizeof (DmaDisassemblyBufferClass),
610 			(GBaseInitFunc) NULL,
611 			(GBaseFinalizeFunc) NULL,
612 			(GClassInitFunc) dma_disassembly_buffer_class_init,
613 			(GClassFinalizeFunc) NULL,
614 			NULL,           /* class_data */
615 			sizeof (DmaDisassemblyBuffer),
616 			0,              /* n_preallocs */
617 			(GInstanceInitFunc) NULL,
618 			NULL            /* value_table */
619 		};
620 
621 		type = g_type_register_static (DMA_SPARSE_BUFFER_TYPE,
622 		                            "DmaDisassemblyBuffer", &type_info, 0);
623 	}
624 
625 	return type;
626 }
627 
628 
629 static DmaDisassemblyBuffer*
dma_disassembly_buffer_new(DmaDebuggerQueue * debugger,gulong lower,gulong upper)630 dma_disassembly_buffer_new (DmaDebuggerQueue *debugger, gulong lower, gulong upper)
631 {
632 	DmaDisassemblyBuffer *buffer;
633 
634 	buffer = g_object_new (DMA_DISASSEMBLY_BUFFER_TYPE, NULL);
635 	g_assert (buffer != NULL);
636 
637 	buffer->debugger = debugger;
638 
639 	DMA_SPARSE_BUFFER (buffer)->lower = lower;
640 	DMA_SPARSE_BUFFER (buffer)->upper = upper;
641 
642 	return buffer;
643 }
644 
645 /* Disassembly view object
646  *---------------------------------------------------------------------------*/
647 
648 struct _DmaDisassemblyView
649 {
650 	DmaSparseView parent;
651 	DmaDebuggerQueue *debugger;
652 	gboolean pending;
653 };
654 
655 struct _DmaDisassemblyViewClass
656 {
657 	DmaSparseViewClass parent;
658 };
659 
660 #define DMA_DISASSEMBLY_VIEW_TYPE              (dma_disassembly_view_get_type ())
661 #define DMA_DISASSEMBLY_VIEW(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), DMA_DISASSEMBLY_VIEW_TYPE, DmaDisassemblyView))
662 #define DMA_DISASSEMBLY_VIEW_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass),  DMA_DISASSEMBLY_VIEW_TYPE, DmaDisassemblyViewClass))
663 #define IS_DMA_DISASSEMBLY_VIEW(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DMA_DISASSEMBLY_VIEW_TYPE))
664 #define IS_DMA_DISASSEMBLY_VIEW_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass),  DMA_DISASSEMBLY_VIEW_TYPE))
665 #define GET_DMA_DISASSEMBLY_VIEW_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj),  DMA_DISASSEMBLY_VIEW_TYPE, DmaDisassemblyViewClass))
666 
667 static DmaSparseViewClass *parent_class = NULL;
668 
669 static GType dma_disassembly_view_get_type (void);
670 
671 /* instance_init is the constructor. All functions should work after this
672  * call. */
673 
674 static void
dma_disassembly_view_instance_init(DmaSparseView * view)675 dma_disassembly_view_instance_init (DmaSparseView *view)
676 {
677 	gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
678 }
679 
680 /* class_init intialize the class itself not the instance */
681 
682 static void
dma_disassembly_view_class_init(DmaDisassemblyViewClass * klass)683 dma_disassembly_view_class_init (DmaDisassemblyViewClass *klass)
684 {
685 	g_return_if_fail (klass != NULL);
686 
687 	parent_class = (DmaSparseViewClass*) g_type_class_peek_parent (klass);
688 }
689 
690 static GType
dma_disassembly_view_get_type(void)691 dma_disassembly_view_get_type (void)
692 {
693 	static GType type = 0;
694 
695 	if (!type)
696 	{
697 		static const GTypeInfo type_info =
698 		{
699 			sizeof (DmaDisassemblyViewClass),
700 			(GBaseInitFunc) NULL,
701 			(GBaseFinalizeFunc) NULL,
702 			(GClassInitFunc) dma_disassembly_view_class_init,
703 			(GClassFinalizeFunc) NULL,
704 			NULL,           /* class_data */
705 			sizeof (DmaDisassemblyView),
706 			0,              /* n_preallocs */
707 			(GInstanceInitFunc) dma_disassembly_view_instance_init,
708 			NULL            /* value_table */
709 		};
710 
711 		type = g_type_register_static (DMA_SPARSE_VIEW_TYPE,
712 		                            "DmaDisassemblyView", &type_info, 0);
713 	}
714 
715 	return type;
716 }
717 
718 
719 static DmaDisassemblyView*
dma_disassembly_view_new_with_buffer(DmaDebuggerQueue * debugger,DmaSparseBuffer * buffer)720 dma_disassembly_view_new_with_buffer (DmaDebuggerQueue *debugger, DmaSparseBuffer *buffer)
721 {
722 	DmaDisassemblyView *view;
723 
724 	view = g_object_new (DMA_DISASSEMBLY_VIEW_TYPE, "buffer", buffer, NULL);
725 	g_assert (view != NULL);
726 
727 	view->debugger = debugger;
728 
729 	return view;
730 }
731 
732 /* Private functions
733  *---------------------------------------------------------------------------*/
734 
735 static void
on_disassembly_buffer_changed(DmaDisassemblyBuffer * buffer,DmaSparseView * view)736 on_disassembly_buffer_changed (DmaDisassemblyBuffer *buffer, DmaSparseView *view)
737 {
738 	dma_sparse_view_refresh (view);
739 }
740 
741 static void
on_breakpoint_changed(DmaDisassemble * self,IAnjutaDebuggerBreakpointItem * bp)742 on_breakpoint_changed (DmaDisassemble *self, IAnjutaDebuggerBreakpointItem *bp)
743 {
744 	g_return_if_fail (bp != NULL);
745 
746 	dma_sparse_view_unmark (self->view, bp->address, IANJUTA_MARKABLE_BREAKPOINT_DISABLED);
747 	dma_sparse_view_unmark (self->view, bp->address, IANJUTA_MARKABLE_BREAKPOINT_ENABLED);
748 	if (!(bp->type & IANJUTA_DEBUGGER_BREAKPOINT_REMOVED))
749 	{
750 		dma_sparse_view_mark (self->view, bp->address, bp->enable ? IANJUTA_MARKABLE_BREAKPOINT_ENABLED : IANJUTA_MARKABLE_BREAKPOINT_DISABLED);
751 	}
752 }
753 
754 static void
destroy_disassemble_gui(DmaDisassemble * self)755 destroy_disassemble_gui (DmaDisassemble *self)
756 {
757 	/* Destroy menu */
758 	if (self->menu != NULL)
759 	{
760 		gtk_widget_destroy (self->menu);
761 		self->menu = NULL;
762 	}
763 
764 	if (self->window != NULL)
765 	{
766 		gtk_widget_destroy (self->window);
767 		self->window = NULL;
768 		self->view = NULL;
769 	}
770 
771 	/* Destroy buffer */
772 	if (self->buffer)
773 	{
774 		dma_sparse_buffer_free (DMA_SPARSE_BUFFER (self->buffer));
775 		self->buffer = NULL;
776 	}
777 }
778 
779 static void
on_program_running(DmaDisassemble * self)780 on_program_running (DmaDisassemble *self)
781 {
782 	dma_sparse_view_delete_all_markers (self->view, IANJUTA_MARKABLE_PROGRAM_COUNTER);
783 }
784 
785 static void
on_program_moved(DmaDisassemble * self,guint pid,guint tid,gulong address,const gchar * file,guint line)786 on_program_moved (DmaDisassemble *self, guint pid, guint tid, gulong address, const gchar* file, guint line)
787 {
788 	dma_sparse_view_delete_all_markers (self->view, IANJUTA_MARKABLE_PROGRAM_COUNTER);
789 
790 	if (address != 0)
791 	{
792 		dma_sparse_view_mark (self->view, address, IANJUTA_MARKABLE_PROGRAM_COUNTER);
793 		dma_sparse_view_goto (self->view, address);
794 	}
795 }
796 
797 static void
on_location_changed(DmaDisassemble * self,gulong address,GFile * file,guint line)798 on_location_changed (DmaDisassemble *self, gulong address, GFile* file, guint line)
799 {
800 	dma_sparse_view_goto (self->view, address);
801 }
802 
803 static void
on_program_unloaded(DmaDisassemble * self)804 on_program_unloaded (DmaDisassemble *self)
805 {
806 	g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_program_unloaded), self);
807 	g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_breakpoint_changed), self);
808 	g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_program_running), self);
809 	g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_program_moved), self);
810 	g_signal_handlers_disconnect_by_func (self->plugin, G_CALLBACK (on_location_changed), self);
811 
812 	dma_sparse_view_delete_all_markers (self->view, IANJUTA_MARKABLE_PROGRAM_COUNTER);
813 
814 	destroy_disassemble_gui (self);
815 }
816 
817 static gboolean
create_disassemble_gui(DmaDisassemble * self)818 create_disassemble_gui (DmaDisassemble *self)
819 {
820 	GtkWidget *dataview;
821 
822 	g_return_val_if_fail (self->buffer == NULL, FALSE);
823 	g_return_val_if_fail (self->window == NULL, FALSE);
824 
825 	/* Create buffer */
826 	self->buffer = DMA_SPARSE_BUFFER (dma_disassembly_buffer_new (self->debugger, 0x00000000U,0xFFFFFFFFU));
827 	if (self->buffer == NULL) return FALSE;
828 
829 	dataview = GTK_WIDGET (dma_disassembly_view_new_with_buffer (self->debugger, self->buffer));
830 	self->view = DMA_SPARSE_VIEW (dataview);
831 	DMA_DISASSEMBLY_VIEW (dataview)->pending = FALSE;
832 	g_signal_connect (G_OBJECT (self->buffer), "changed", G_CALLBACK (on_disassembly_buffer_changed), self->view);
833 
834 	/* Add disassembly window */
835 	self->window = gtk_scrolled_window_new (NULL, NULL);
836 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->window),
837 									GTK_POLICY_AUTOMATIC,
838 									GTK_POLICY_AUTOMATIC);
839 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self->window),
840 									 GTK_SHADOW_IN);
841 	gtk_container_add (GTK_CONTAINER (self->window), GTK_WIDGET (dataview));
842 
843 	gtk_widget_show_all (self->window);
844 	anjuta_shell_add_widget (ANJUTA_PLUGIN (self->plugin)->shell,
845 							 self->window,
846                              "AnjutaDebuggerDisassemble", _("Disassembly"),
847                              "debugger-disassembly", ANJUTA_SHELL_PLACEMENT_NONE,
848 							 NULL);
849 
850 	return TRUE;
851 }
852 
853 static void
on_program_loaded(DmaDisassemble * self)854 on_program_loaded (DmaDisassemble *self)
855 {
856 	if (!dma_debugger_queue_is_supported (self->debugger, HAS_INSTRUCTION)) return;
857 
858 	if (!create_disassemble_gui (self)) return;
859 
860 	/* Connect signals */
861 	g_signal_connect_swapped (self->plugin, "program-unloaded", G_CALLBACK (on_program_unloaded), self);
862 	g_signal_connect_swapped (self->plugin, "breakpoint-changed", G_CALLBACK (on_breakpoint_changed), self);
863 	g_signal_connect_swapped (self->plugin, "program-running", G_CALLBACK (on_program_running), self);
864 	g_signal_connect_swapped (self->plugin, "program-moved", G_CALLBACK (on_program_moved), self);
865 	g_signal_connect_swapped (self->plugin, "location-changed", G_CALLBACK (on_location_changed), self);
866 }
867 
868 /* Public functions
869  *---------------------------------------------------------------------------*/
870 
871 gboolean
dma_disassemble_is_focus(DmaDisassemble * self)872 dma_disassemble_is_focus (DmaDisassemble *self)
873 {
874 	return gtk_widget_is_focus (GTK_WIDGET(self->view));
875 }
876 
877 guint
dma_disassemble_get_current_address(DmaDisassemble * self)878 dma_disassemble_get_current_address (DmaDisassemble *self)
879 {
880 	return dma_sparse_view_get_location (self->view);
881 }
882 
883 /* Constructor & Destructor
884  *---------------------------------------------------------------------------*/
885 
886 DmaDisassemble*
dma_disassemble_new(DebugManagerPlugin * plugin)887 dma_disassemble_new(DebugManagerPlugin *plugin)
888 {
889 	DmaDisassemble* self;
890 
891 	self = g_new0 (DmaDisassemble, 1);
892 
893 	self->plugin = plugin;
894 	self->debugger = dma_debug_manager_get_queue (plugin);;
895 
896 	g_signal_connect_swapped (self->plugin, "program-loaded", G_CALLBACK (on_program_loaded), self);
897 
898 	return self;
899 }
900 
901 void
dma_disassemble_free(DmaDisassemble * self)902 dma_disassemble_free(DmaDisassemble* self)
903 {
904 	g_return_if_fail (self != NULL);
905 
906 	g_signal_handlers_disconnect_matched (self->plugin, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
907 
908 	destroy_disassemble_gui (self);
909 
910 	g_free(self);
911 }
912 
913 
914