.newtype command added
[libfirm] / ir / debug / debugger.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/debug/debugger.c
4  * Purpose:     Helper function for integerated debug support
5  * Author:      Michael Beck
6  * Modified by:
7  * Created:     2005
8  * CVS-ID:      $Id$
9  * Copyright:   (c) 2001-2005 Universität Karlsruhe
10  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
11  */
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #ifndef NDEBUG
17
18 #ifdef _WIN32
19 #define WIN32_LEAN_AND_MEAN
20 #include <windows.h>
21 #endif
22
23 #ifdef HAVE_STDLIB_H
24 #include <stdlib.h>
25 #endif
26
27 #include <stdio.h>
28 #include <signal.h>
29
30 #ifdef HAVE_STRING_H
31 #include <string.h>
32 #endif
33
34 #include <ctype.h>
35
36 #include "set.h"
37 #include "ident.h"
38 #include "irhooks.h"
39 #include "irgraph_t.h"
40 #include "entity_t.h"
41 #include "irprintf.h"
42
43 #ifdef _WIN32
44 /** Break into the debugger. The Win32 way. */
45 static void firm_debug_break(void) {
46   DebugBreak();
47 }
48 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64))
49 /** Break into the debugger. The ia32/x86_64 way under GCC. */
50 static void firm_debug_break(void) {
51   __asm__ __volatile__("int3");
52 }
53 #else
54 /** Break into the debugger. Poor Unix way. */
55 static void firm_debug_break(void) {
56   raise(SIGINT);
57 }
58 #endif /* _WIN32 */
59
60 /** supported breakpoint kinds */
61 typedef enum {
62   BP_NODE  = 'n',   /**< break on node number. */
63   BP_IDENT = 'i'    /**< break on ident. */
64 } bp_kind;
65
66 /**
67  * Reasons for node number breakpoints.
68  */
69 typedef enum _bp_reasons_t {
70   BP_ON_NEW_NODE,    /**< break if node with number is created */
71   BP_ON_REPLACE,     /**< break if node with number is replaced */
72   BP_ON_LOWER,       /**< break if node with number is lowered */
73   BP_ON_REMIRG,      /**< break if an IRG is removed */
74   BP_ON_NEW_ENT,     /**< break if a new entity is created */
75   BP_ON_NEW_TYPE,    /**< break if a new type is created */
76   BP_MAX_REASON
77 } bp_reasons_t;
78
79 /** A breakpoint. */
80 typedef struct _breakpoint {
81   bp_kind      kind;        /**< the kind of this break point */
82   unsigned     bpnr;        /**< break point number */
83   int          active;      /**< non-zero, if this break point is active */
84   bp_reasons_t reason;      /**< reason for the breakpoint */
85   struct _breakpoint *next; /**< link to the next one */
86 } breakpoint;
87
88 /** A node number breakpoint. */
89 typedef struct {
90   breakpoint   bp;       /**< the breakpoint data */
91   long         nr;       /**< the node number */
92 } bp_node_t;
93
94 /** calculate the hash value for a node breakpoint */
95 #define HASH_NODE_BP(key) (((key).nr << 2) ^ (key).bp.reason)
96
97 /** A ident breakpoint. */
98 typedef struct {
99   breakpoint   bp;       /**< the breakpoint data */
100   ident        *id;      /**< the ident */
101 } bp_ident_t;
102
103 /** calculate the hash value for an ident breakpoint */
104 #define HASH_IDENT_BP(key) (HASH_PTR((key).id) ^ (key).bp.reason)
105
106 /** The set containing the breakpoints on node numbers. */
107 static set *bp_node_numbers;
108
109 /** The set containing the breakpoints on idents. */
110 static set *bp_idents;
111
112 /**< the list of all breakpoints */
113 static breakpoint *bp_list;
114
115 /** number of the current break point */
116 static unsigned bp_num = 0;
117
118 /** set if break on init command was issued. */
119 static int break_on_init = 0;
120
121 /** the hook entries for the Firm debugger module. */
122 static hook_entry_t debugger_hooks[hook_last];
123
124 /** number of active breakpoints to maintain hooks. */
125 static unsigned num_active_bp[BP_MAX_REASON];
126
127 /** hook the hook h with function fkt. */
128 #define HOOK(h, fkt) \
129   debugger_hooks[h].hook._##h = fkt; register_hook(h, &debugger_hooks[h])
130
131 /** unhook the hook h */
132 #define UNHOOK(h)   unregister_hook(h, &debugger_hooks[h])
133
134 /** returns non-zero if a entry hook h is used */
135 #define IS_HOOKED(h) (debugger_hooks[h].next != NULL)
136
137 /**
138  * A new node is created.
139  *
140  * @param ctx   the hook context
141  * @param irg   the IR graph on which the node is created
142  * @param node  the new IR node that was created
143  */
144 static void dbg_new_node(void *ctx, ir_graph *irg, ir_node *node)
145 {
146   bp_node_t key, *elem;
147
148   key.nr        = get_irn_node_nr(node);
149   key.bp.reason = BP_ON_NEW_NODE;
150
151   elem = set_find(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
152   if (elem && elem->bp.active) {
153     ir_printf("Firm BP %u reached, %+F created\n", elem->bp.bpnr, node);
154     firm_debug_break();
155   }
156 }
157
158 /**
159  * A node is replaced.
160  *
161  * @param ctx   the hook context
162  * @param old   the IR node the is replaced
163  * @param nw    the new IR node that will replace old
164  */
165 static void dbg_replace(void *ctx, ir_node *old, ir_node *nw)
166 {
167   bp_node_t key, *elem;
168
169   key.nr        = get_irn_node_nr(old);
170   key.bp.reason = BP_ON_REPLACE;
171
172   elem = set_find(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
173   if (elem && elem->bp.active) {
174     ir_printf("Firm BP %u reached, %+F will be replaced by %+F\n", elem->bp.bpnr, old, nw);
175     firm_debug_break();
176   }
177 }
178
179 /**
180  * A new node is lowered.
181  *
182  * @param ctx   the hook context
183  * @param node  the new IR node that will be lowered
184  */
185 static void dbg_lower(void *ctx, ir_node *node)
186 {
187   bp_node_t key, *elem;
188
189   key.nr        = get_irn_node_nr(node);
190   key.bp.reason = BP_ON_LOWER;
191
192   elem = set_find(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
193   if (elem && elem->bp.active) {
194     ir_printf("Firm BP %u reached, %+F will be lowered\n", elem->bp.bpnr, node);
195     firm_debug_break();
196   }
197 }
198
199 /**
200  * A graph will be deleted.
201  *
202  * @param ctx   the hook context
203  * @param irg   the IR graph that will be deleted
204  */
205 static void dbg_free_graph(void *ctx, ir_graph *irg)
206 {
207   bp_ident_t key, *elem;
208   entity *ent = get_irg_entity(irg);
209
210   if (! ent)
211     return;
212
213   key.id        = get_entity_ident(ent);
214   key.bp.reason = BP_ON_REMIRG;
215
216   elem = set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
217   if (elem && elem->bp.active) {
218     ir_printf("Firm BP %u reached, %+F will be deleted\n", elem->bp.bpnr, ent);
219     firm_debug_break();
220   }
221 }
222
223 /**
224  * An entity was created.
225  *
226  * @param ctx   the hook context
227  * @param ent   the newly created entity
228  */
229 static void dbg_new_entity(void *ctx, entity *ent)
230 {
231   bp_ident_t key, *elem;
232
233   key.id        = get_entity_ident(ent);
234   key.bp.reason = BP_ON_NEW_ENT;
235
236   elem = set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
237   if (elem && elem->bp.active) {
238     ir_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, ent);
239     firm_debug_break();
240   }
241 }
242
243 /**
244  * A type was created.
245  *
246  * @param ctx   the hook context
247  * @param tp    the newly created type
248  */
249 static void dbg_new_type(void *ctx, type *tp)
250 {
251   bp_ident_t key, *elem;
252
253   key.id        = get_type_ident(tp);
254   key.bp.reason = BP_ON_NEW_TYPE;
255
256   elem = set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
257   if (elem && elem->bp.active) {
258     ir_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, tp);
259     firm_debug_break();
260   }
261 }
262
263 /**
264  * return the reason string.
265  */
266 static const char *reason_str(bp_reasons_t reason)
267 {
268   switch (reason) {
269   case BP_ON_NEW_NODE: return "node creation";
270   case BP_ON_REPLACE:  return "node replace";
271   case BP_ON_LOWER:    return "node lowering";
272   case BP_ON_REMIRG:   return "removing IRG";
273   case BP_ON_NEW_ENT:  return "entity creation";
274   case BP_ON_NEW_TYPE: return "type creation";
275   default:             assert(0);
276   }
277   return "unknown";
278 }
279
280 /**
281  * Compare two node number breakpoints
282  */
283 static int cmp_node_bp(const void *elt, const void *key, size_t size)
284 {
285   const bp_node_t *e1 = elt;
286   const bp_node_t *e2 = key;
287
288   return (e1->nr - e2->nr) | (e1->bp.reason - e2->bp.reason);
289 }
290
291 /**
292  * Compare two ident breakpoints
293  */
294 static int cmp_ident_bp(const void *elt, const void *key, size_t size)
295 {
296   const bp_ident_t *e1 = elt;
297   const bp_ident_t *e2 = key;
298
299   return (e1->id != e2->id) | (e1->bp.reason - e2->bp.reason);
300 }
301
302 /**
303  * update the hooks
304  */
305 static void update_hooks(breakpoint *bp)
306 {
307 #define CASE_ON(a, b)  case a: if (! IS_HOOKED(hook_##b)) HOOK(hook_##b, dbg_##b); break
308 #define CASE_OFF(a, b) case a: if (IS_HOOKED(hook_##b)) UNHOOK(hook_##b); break
309
310   if (bp->active)
311     ++num_active_bp[bp->reason];
312   else
313     --num_active_bp[bp->reason];
314
315   if (num_active_bp[bp->reason] > 0) {
316     /* register the hooks on demand */
317     switch (bp->reason) {
318     CASE_ON(BP_ON_NEW_NODE, new_node);
319     CASE_ON(BP_ON_REPLACE, replace);
320     CASE_ON(BP_ON_LOWER, lower);
321     CASE_ON(BP_ON_REMIRG, free_graph);
322     CASE_ON(BP_ON_NEW_ENT, new_entity);
323     CASE_ON(BP_ON_NEW_TYPE, new_type);
324     default:
325       ;
326     }
327   }
328   else {
329     /* unregister the hook on demand */
330     switch (bp->reason) {
331     CASE_OFF(BP_ON_NEW_NODE, new_node);
332     CASE_OFF(BP_ON_REPLACE, replace);
333     CASE_OFF(BP_ON_LOWER, lower);
334     CASE_OFF(BP_ON_REMIRG, free_graph);
335     CASE_OFF(BP_ON_NEW_ENT, new_entity);
336     CASE_OFF(BP_ON_NEW_TYPE, new_type);
337     default:
338       ;
339     }
340   }
341 #undef CASE_ON
342 #undef CASE_OFF
343 }
344
345 /**
346  * Break if node nr is reached.
347  */
348 static void break_on_node(long nr, bp_reasons_t reason)
349 {
350   bp_node_t key, *elem;
351
352   key.bp.kind   = BP_NODE;
353   key.bp.bpnr   = 0;
354   key.bp.active = 1;
355   key.bp.reason = reason;
356   key.nr        = nr;
357
358   elem = set_insert(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
359
360   if (elem->bp.bpnr == 0) {
361     /* new break point */
362     elem->bp.bpnr = ++bp_num;
363     elem->bp.next = bp_list;
364     bp_list = &elem->bp;
365
366     printf("Firm BP %u: %s of Node %ld\n", elem->bp.bpnr, reason_str(reason), nr);
367
368     update_hooks(&elem->bp);
369   }
370 }
371
372 /**
373  * Break if ident name is reached.
374  */
375 static void break_on_ident(const char *name, bp_reasons_t reason) {
376   bp_ident_t key, *elem;
377
378   key.bp.kind   = BP_IDENT;
379   key.bp.bpnr   = 0;
380   key.bp.active = 1;
381   key.bp.reason = reason;
382   key.id        = new_id_from_str(name);
383
384   elem = set_insert(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
385
386   if (elem->bp.bpnr == 0) {
387     /* new break point */
388     elem->bp.bpnr = ++bp_num;
389     elem->bp.next = bp_list;
390     bp_list = &elem->bp;
391
392     printf("Firm BP %u: %s of ident \"%s\"\n", elem->bp.bpnr, reason_str(reason), name);
393
394     update_hooks(&elem->bp);
395   }
396 }
397
398 /**
399  * Sets/resets the active flag of breakpoint bp.
400  */
401 static void bp_activate(unsigned bp, int active)
402 {
403   breakpoint *p;
404
405   for (p = bp_list; p; p = p->next) {
406     if (p->bpnr == bp) {
407       if (p->active != active) {
408         p->active = active;
409         update_hooks(p);
410       }
411
412       printf("Firm BP %u is now %s\n", bp, active ? "enabled" : "disabled");
413       return;
414     }
415   }
416   printf("Error: Firm BP %u not exists.\n", bp);
417 }
418
419
420 /**
421  * Show a list of supported commands
422  */
423 static void show_commands(void) {
424   printf("Internal Firm debugger extension $Revision$ commands:\n"
425     ".init           break after initialization\n"
426     ".create nr      break if node nr was created\n"
427     ".replace nr     break if node nr is replaced by another node\n"
428     ".lower nr       break before node nr is lowered\n"
429     ".remirg name    break if the irg of entity name is deleted\n"
430     ".newent name    break if the entity name was created\n"
431     ".newtype name   break if the type name was created\n"
432     ".bp             show all breakpoints\n"
433     ".enable nr      enable breakpoint nr\n"
434     ".disable nr     disable breakpoint nr\n"
435     ".help           list all commands\n"
436   );
437 }
438
439 /**
440  * Shows all Firm breakpoints.
441  */
442 static void show_bp(void) {
443   breakpoint *p;
444   bp_node_t  *node_p;
445   bp_ident_t *ident_p;
446
447   for (p = bp_list; p; p = p->next) {
448     printf("Firm BP %u: ", p->bpnr);
449
450     switch (p->kind) {
451     case BP_NODE:
452       node_p = (bp_node_t *)p;
453       printf("%s of node %ld ", reason_str(p->reason), node_p->nr);
454       break;
455
456     case BP_IDENT:
457       ident_p = (bp_ident_t *)p;
458       printf("%s of ident \"%s\" ", reason_str(p->reason), get_id_str(ident_p->id));
459       break;
460     }
461
462     printf(p->active ? "enabled\n" : "disabled\n");
463   }
464 }
465
466 /**
467  * High level function to use from debugger interface
468  *
469  * Supported commands:
470  *  .create nr    break if node nr was created
471  *  .help         list all commands
472  */
473 void firm_break(const char *cmd) {
474   long nr;
475   unsigned bp;
476   char name[1024];
477
478   while (isspace(*cmd)) ++cmd;
479
480   if (sscanf(cmd, ".create %ld\n", &nr) == 1) {
481     break_on_node(nr, BP_ON_NEW_NODE);
482   }
483   else if (sscanf(cmd, ".replace %ld\n", &nr) == 1) {
484     break_on_node(nr, BP_ON_REPLACE);
485   }
486   else if (sscanf(cmd, ".lower %ld\n", &nr) == 1) {
487     break_on_node(nr, BP_ON_LOWER);
488   }
489   else if (sscanf(cmd, ".remirg %s\n", name) == 1) {
490     break_on_ident(name, BP_ON_REMIRG);
491   }
492   else if (sscanf(cmd, ".newent %s\n", name) == 1) {
493     break_on_ident(name, BP_ON_NEW_ENT);
494   }
495   else if (sscanf(cmd, ".newtype %s\n", name) == 1) {
496     break_on_ident(name, BP_ON_NEW_TYPE);
497   }
498   else if (strcmp(cmd, ".init") == 0)
499     break_on_init = 1;
500   else if (strcmp(cmd, ".bp") == 0)
501     show_bp();
502   else if (sscanf(cmd, ".enable %u", &bp) == 1)
503     bp_activate(bp, 1);
504   else if (sscanf(cmd, ".disable %u", &bp) == 1)
505     bp_activate(bp, 0);
506   else {
507     show_commands();
508   }
509 }
510
511 /* creates the debugger tables */
512 void firm_init_debugger(void)
513 {
514   char *env;
515
516   bp_node_numbers = new_set(cmp_node_bp, 8);
517   bp_idents       = new_set(cmp_ident_bp, 8);
518
519   env = getenv("FIRMDBG");
520
521   if (env)
522     firm_break(env);
523
524   if (break_on_init)
525     firm_debug_break();
526 }
527
528 #endif /* NDEBUG */
529
530 /**
531  * @page debugger   The Firm debugger extension.
532  *
533  * Firm contains a debugger extension. This allows to set debugger breakpoints
534  * an various events.
535  * The extension uses a text interface which can be access in the debugger.
536  *
537  * The following commands are currently supported:
538  *
539  * .init
540  *
541  * Break immediately after the debugger extension was initialized.
542  * Typically this command is used in the environment to stop the execution
543  * of a Firm compiler right after the initialization, like this:
544  *
545  * $export FIRMDBG=".init"
546  *
547  *
548  * .create nr
549  *
550  * Break if a new IR-node with node number nr was created.
551  * Typically used to find the place where wrong nodes are created.
552  *
553  * .replace nr
554  *
555  * Break before IR-node with node number nr is replaced by another node.
556  *
557  * .lower nr
558  *
559  * Break before IR-node with node number nr is lowered.
560  *
561  * .remirg name
562  *
563  * Break if the irg of entity name is deleted.
564  *
565  * .newent name
566  *
567  * Break if the entity name was created.
568  *
569  * .newtype name
570  *
571  * Break if the type name was created.
572  *
573  * .bp
574  *
575  * Show all Firm internal breakpoints.
576  *
577  * .enable nr
578  *
579  * Enables breakpoint nr.
580  *
581  * .disable nr
582  *
583  * Disables breakpoint nr.
584  *
585  * .help
586  *
587  * List all commands.
588  *
589  *
590  * The Firm debugger extension can be accessed using the function firm_break().
591  * The following example shows how to set a creation breakpoint in GDB when
592  * node 2101 is created.
593  *
594  * 1.) set FIRMDBG=".init"
595  * 2.) start gdb with your compiler
596  * 3.) after gdb breaks, issue
597  *
598  * p firm_debug(".create 2101")
599  *
600  * On the console the following text should be issued:
601  *
602  * Firm BP 1: creation of Node 2101
603  */