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