e8d68ce4fc66c6c5644b5067c9a8e1c008d35046
[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 #include "set.h"
31 #include "irhooks.h"
32 #include "irprintf.h"
33
34 #ifdef _WIN32
35 /* Win32 support */
36
37 /** Break into the debugger */
38 static void firm_debug_break(void) {
39   DebugBreak();
40 }
41
42 #else
43
44 /** Break into the debugger */
45 static void firm_debug_break(void) {
46   raise(SIGINT);
47 }
48
49 #endif /* _WIN32 */
50
51 /** supported breakpoint kinds */
52 typedef enum {
53   BP_CREATION = 0    /**< break on creation. */
54 } bp_kind;
55
56 /** A breakpoint. */
57 typedef struct _breakpoint {
58   bp_kind   kind;           /**< the kind of this break point */
59   unsigned  bpnr;           /**< break point number */
60   int       active;         /**< non-zero, if this break point is active */
61   struct _breakpoint *next; /**< link to the next one */
62 } breakpoint;
63
64 /** A creation breakpoint. */
65 typedef struct {
66   breakpoint  bp; /**< the breakpoint data */
67   long        nr; /**< the node number */
68 } bp_create_t;
69
70 /** The set containing the creation breakpoints. */
71 static set *bp_creations;
72
73 /**< the list of all breakpoints */
74 static breakpoint *bp_list;
75
76 /** number of the current break point */
77 static unsigned bp_num = 0;
78
79 /** set if break on init command was issued. */
80 static int break_on_init = 0;
81
82 /**
83  * Compare two creation breakpoints
84  */
85 static int cmp_create_bp(const void *elt, const void *key, size_t size)
86 {
87   const bp_create_t *e1 = elt;
88   const bp_create_t *e2 = key;
89
90   return e1->nr - e2->nr;
91 }
92
93 /**
94  * Break if node nr is created.
95  */
96 static void break_on_creation(long nr)
97 {
98   bp_create_t key, *elem;
99
100   key.bp.kind   = BP_CREATION;
101   key.bp.bpnr   = 0;
102   key.bp.active = 1;
103   key.nr        = nr;
104
105   elem = set_insert(bp_creations, &key, sizeof(key), nr);
106
107   if (elem->bp.bpnr == 0) {
108     /* new break point */
109     elem->bp.bpnr = ++bp_num;
110     elem->bp.next = bp_list;
111     bp_list = &elem->bp;
112
113     printf("Firm BP %u: creation of Node %ld\n", elem->bp.bpnr, nr);
114   }
115 }
116
117 /**
118  * Sets/resets the active flag of breakpoint bp.
119  */
120 static void bp_activate(unsigned bp, int active)
121 {
122   breakpoint *p;
123
124   for (p = bp_list; p; p = p->next) {
125     if (p->bpnr == bp) {
126       p->bpnr = active;
127
128       printf("Firm BP %u is now %s\n", bp, active ? "enabled" : "disabled");
129       return;
130     }
131   }
132   printf("Error: Firm BP %u not exists.\n", bp);
133 }
134
135
136 /**
137  * Show a list of supported commands
138  */
139 static void show_commands(void) {
140   printf("Internal Firm debugger extension commands:\n"
141     ".init         break after initialization\n"
142     ".create nr    break if node nr was created\n"
143     ".bp           show all breakpoints\n"
144     ".enable nr    enable breakpoint nr\n"
145     ".disable nr   disable breakpoint nr\n"
146     ".help         list all commands\n"
147   );
148 }
149
150 /**
151  * Shows all Firm breakpoints.
152  */
153 static void show_bp(void) {
154   breakpoint *p;
155
156   for (p = bp_list; p; p = p->next) {
157     printf("Firm BP %u ", p->bpnr);
158
159     switch (p->kind) {
160     case BP_CREATION:
161       printf("creation of node %ld ", ((bp_create_t *)p)->nr);
162       break;
163     }
164
165     printf(p->active ? "enabled\n" : "disabled\n");
166   }
167 }
168
169 /**
170  * High level function to use from debugger interface
171  *
172  * Supported commands:
173  *  .create nr    break if node nr was created
174  *  .help         list all commands
175  */
176 void firm_break(const char *cmd) {
177   long nr;
178   unsigned bp;
179
180   while (isspace(*cmd)) ++cmd;
181
182   if (sscanf(cmd, ".create %ld\n", &nr) == 1) {
183     break_on_creation(nr);
184   }
185   else if (strcmp(cmd, ".init") == 0)
186     break_on_init = 1;
187   else if (strcmp(cmd, ".bp") == 0)
188     show_bp();
189   else if (sscanf(cmd, ".enable %u", &bp) == 1)
190     bp_activate(bp, 1);
191   else if (sscanf(cmd, ".disable %u", &bp) == 1)
192     bp_activate(bp, 0);
193   else {
194     show_commands();
195   }
196 }
197
198 /** the hook entries for the Firm debugger module */
199 static hook_entry_t debugger_hooks[hook_last];
200
201 /**
202  * A new node is created.
203  *
204  * @param ctx   the hook context
205  * @param irg   the IR graph on which the node is created
206  * @param node  the new IR node that was created
207  */
208 static void dbg_new_node(void *ctx, ir_graph *irg, ir_node *node)
209 {
210   bp_create_t key, *elem;
211
212   key.nr   = get_irn_node_nr(node);
213
214   elem = set_find(bp_creations, &key, sizeof(key), key.nr);
215   if (elem && elem->bp.active) {
216     ir_printf("Firm BP %u reached, %+F created\n", elem->bp.bpnr, node);
217     firm_debug_break();
218   }
219 }
220
221 #define HOOK(h, fkt) \
222   debugger_hooks[h].hook._##h = fkt; register_hook(h, &debugger_hooks[h])
223
224 /* creates the debugger tables */
225 void firm_init_debugger(void)
226 {
227   char *env;
228
229   bp_creations = new_set(cmp_create_bp, 8);
230
231   /* register the hooks */
232   HOOK(hook_new_node,                         dbg_new_node);
233
234   env = getenv("FIRMDBG");
235
236   if (env)
237     firm_break(env);
238
239   if (break_on_init)
240     firm_debug_break();
241 }
242
243 #endif /* NDEBUG */
244
245 /**
246  * @page debugger   The Firm debugger extension.
247  *
248  * Firm contains a debugger extension. This allows to set debugger breakpoints
249  * an various events.
250  * The extension uses a text interface which can be access in the debugger.
251  *
252  * The following commands are currently supported:
253  *
254  * .init
255  *
256  * Break immediately after the debugger extension was initialized.
257  * Typically this command is used in the environment to stop the execution
258  * of a Firm compiler right after the initialization, like this:
259  *
260  * $export FIRMDBG=".init"
261  *
262  *
263  * .create nr
264  *
265  * Break if a new IR-node with node number nr was created.
266  * Typically used to find the place where wrong nodes are created.
267  *
268  * .bp
269  *
270  * Show all Firm internal breakpoints.
271  *
272  * .enable nr
273  *
274  * Enables breakpoint nr.
275  *
276  * .disable nr
277  *
278  * Disables breakpoint nr.
279  *
280  * .help
281  *
282  * List all commands.
283  *
284  *
285  * The Firm debugger extension is access using the function firm_break().
286  * The following example shows how to set a creating breakpoint in GDB when
287  * node 2101 is created.
288  *
289  * 1.) set FRIMDBG=".init"
290  * 2.) start gdb with your compiler
291  * 3.) after gdb breaks, issue
292  *
293  * p firm_debug(".create 2101")
294  *
295  * On the console the following text should be issued:
296  *
297  * Firm BP 1: creation of Node 2101
298  */