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