3 * File name: ir/debug/debugger.c
4 * Purpose: Helper function for integerated debug support
9 * Copyright: (c) 2001-2005 Universität Karlsruhe
10 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
19 #define WIN32_LEAN_AND_MEAN
41 /** Break into the debugger. The Win32 way. */
42 static void firm_debug_break(void) {
45 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64))
46 /** Break into the debugger. The ia32 way under GCC. */
47 static void firm_debug_break(void) {
48 __asm__ __volatile__("int3");
51 /** Break into the debugger. Poor Unix way. */
52 static void firm_debug_break(void) {
57 /** supported breakpoint kinds */
59 BP_NODE = 0 /**< break on node number. */
63 typedef struct _breakpoint {
64 bp_kind kind; /**< the kind of this break point */
65 unsigned bpnr; /**< break point number */
66 int active; /**< non-zero, if this break point is active */
67 struct _breakpoint *next; /**< link to the next one */
71 * Reasons for node number breakpoints.
73 typedef enum _bp_reasons_t {
74 BP_ON_CREATION = 1, /**< break if node with number is created */
75 BP_ON_REPLACE = 2, /**< break if node with number is replaced */
76 BP_ON_LOWER = 3, /**< break if node with number is lowered */
80 /** A node number breakpoint. */
82 breakpoint bp; /**< the breakpoint data */
83 long nr; /**< the node number */
84 bp_reasons_t reason; /**< reason for the breakpoint */
87 /** calculate the hash value for a node breakpoint */
88 #define HASH_NODE_BP(key) (((key).nr << 2) ^ (key).reason)
90 /** The set containing the breakpoints on node numbers. */
91 static set *bp_node_numbers;
93 /**< the list of all breakpoints */
94 static breakpoint *bp_list;
96 /** number of the current break point */
97 static unsigned bp_num = 0;
99 /** set if break on init command was issued. */
100 static int break_on_init = 0;
102 /** the hook entries for the Firm debugger module. */
103 static hook_entry_t debugger_hooks[hook_last];
105 /** number of active breakpoints to maintein hooks. */
106 static unsigned num_active_bp[BP_MAX_REASON];
108 /** hook the hook h with function fkt. */
109 #define HOOK(h, fkt) \
110 debugger_hooks[h].hook._##h = fkt; register_hook(h, &debugger_hooks[h])
112 /** unhook the hook h */
113 #define UNHOOK(h) unregister_hook(h, &debugger_hooks[h])
115 /** returns non-zero if a entry hook h is used */
116 #define IS_HOOKED(h) (debugger_hooks[h].next != NULL)
119 * A new node is created.
121 * @param ctx the hook context
122 * @param irg the IR graph on which the node is created
123 * @param node the new IR node that was created
125 static void dbg_new_node(void *ctx, ir_graph *irg, ir_node *node)
127 bp_node_t key, *elem;
129 key.nr = get_irn_node_nr(node);
130 key.reason = BP_ON_CREATION;
132 elem = set_find(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
133 if (elem && elem->bp.active) {
134 ir_printf("Firm BP %u reached, %+F created\n", elem->bp.bpnr, node);
140 * A node is replaced.
142 * @param ctx the hook context
143 * @param old the IR node the is replaced
144 * @param nw the new IR node that will replace old
146 static void dbg_replace(void *ctx, ir_node *old, ir_node *nw)
148 bp_node_t key, *elem;
150 key.nr = get_irn_node_nr(old);
151 key.reason = BP_ON_REPLACE;
153 elem = set_find(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
154 if (elem && elem->bp.active) {
155 ir_printf("Firm BP %u reached, %+F will be replaced by %+F\n", elem->bp.bpnr, old, nw);
161 * A new node is lowered.
163 * @param ctx the hook context
164 * @param node the new IR node that will be lowered
166 static void dbg_lower_node(void *ctx, ir_node *node)
168 bp_node_t key, *elem;
170 key.nr = get_irn_node_nr(node);
171 key.reason = BP_ON_LOWER;
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 lowered\n", elem->bp.bpnr, node);
182 * return the reason string.
184 static const char *reason_str(bp_reasons_t reason)
187 case BP_ON_CREATION: return "creation";
188 case BP_ON_REPLACE: return "replacing";
189 case BP_ON_LOWER: return "lowering";
195 #define HASH_NODE_BP(key) (((key).nr << 2) ^ (key).reason)
198 * Compare two node number breakpoints
200 static int cmp_node_bp(const void *elt, const void *key, size_t size)
202 const bp_node_t *e1 = elt;
203 const bp_node_t *e2 = key;
205 return (e1->nr - e2->nr) | (e1->reason - e2->reason);
211 static void update_hooks(breakpoint *bp)
213 if (bp->kind == BP_NODE) {
214 bp_node_t *elem = (bp_node_t *)bp;
217 ++num_active_bp[elem->reason];
219 --num_active_bp[elem->reason];
221 if (num_active_bp[elem->reason] > 0) {
222 /* register the hooks on demand */
223 switch (elem->reason) {
225 if (! IS_HOOKED(hook_new_node))
226 HOOK(hook_new_node, dbg_new_node);
230 if (! IS_HOOKED(hook_replace))
231 HOOK(hook_replace, dbg_replace);
234 if (! IS_HOOKED(hook_lower))
235 HOOK(hook_lower, dbg_lower_node);
240 switch (elem->reason) {
242 if (IS_HOOKED(hook_new_node))
243 UNHOOK(hook_new_node);
247 if (IS_HOOKED(hook_replace))
248 UNHOOK(hook_replace);
251 if (IS_HOOKED(hook_lower))
260 * Break if node nr is reached.
262 static void break_on_node(long nr, bp_reasons_t reason)
264 bp_node_t key, *elem;
266 key.bp.kind = BP_NODE;
272 elem = set_insert(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
274 if (elem->bp.bpnr == 0) {
275 /* new break point */
276 elem->bp.bpnr = ++bp_num;
277 elem->bp.next = bp_list;
280 printf("Firm BP %u: %s of Node %ld\n", elem->bp.bpnr, reason_str(reason), nr);
282 update_hooks(&elem->bp);
287 * Sets/resets the active flag of breakpoint bp.
289 static void bp_activate(unsigned bp, int active)
293 for (p = bp_list; p; p = p->next) {
295 if (p->active != active) {
300 printf("Firm BP %u is now %s\n", bp, active ? "enabled" : "disabled");
304 printf("Error: Firm BP %u not exists.\n", bp);
309 * Show a list of supported commands
311 static void show_commands(void) {
312 printf("Internal Firm debugger extension commands:\n"
313 ".init break after initialization\n"
314 ".create nr break if node nr was created\n"
315 ".replace nr break if node nr is replaced by another node\n"
316 ".lower nr break before node nr is lowered\n"
317 ".bp show all breakpoints\n"
318 ".enable nr enable breakpoint nr\n"
319 ".disable nr disable breakpoint nr\n"
320 ".help list all commands\n"
325 * Shows all Firm breakpoints.
327 static void show_bp(void) {
331 for (p = bp_list; p; p = p->next) {
332 printf("Firm BP %u: ", p->bpnr);
336 node_p = (bp_node_t *)p;
337 printf("%s of node %ld ", reason_str(node_p->reason), node_p->nr);
341 printf(p->active ? "enabled\n" : "disabled\n");
346 * High level function to use from debugger interface
348 * Supported commands:
349 * .create nr break if node nr was created
350 * .help list all commands
352 void firm_break(const char *cmd) {
356 while (isspace(*cmd)) ++cmd;
358 if (sscanf(cmd, ".create %ld\n", &nr) == 1) {
359 break_on_node(nr, BP_ON_CREATION);
361 else if (sscanf(cmd, ".replace %ld\n", &nr) == 1) {
362 break_on_node(nr, BP_ON_REPLACE);
364 else if (sscanf(cmd, ".lower %ld\n", &nr) == 1) {
365 break_on_node(nr, BP_ON_LOWER);
367 else if (strcmp(cmd, ".init") == 0)
369 else if (strcmp(cmd, ".bp") == 0)
371 else if (sscanf(cmd, ".enable %u", &bp) == 1)
373 else if (sscanf(cmd, ".disable %u", &bp) == 1)
380 /* creates the debugger tables */
381 void firm_init_debugger(void)
385 bp_node_numbers = new_set(cmp_node_bp, 8);
387 env = getenv("FIRMDBG");
399 * @page debugger The Firm debugger extension.
401 * Firm contains a debugger extension. This allows to set debugger breakpoints
403 * The extension uses a text interface which can be access in the debugger.
405 * The following commands are currently supported:
409 * Break immediately after the debugger extension was initialized.
410 * Typically this command is used in the environment to stop the execution
411 * of a Firm compiler right after the initialization, like this:
413 * $export FIRMDBG=".init"
418 * Break if a new IR-node with node number nr was created.
419 * Typically used to find the place where wrong nodes are created.
423 * Break before IR-node with node number nr is replaced by another node.
427 * Break before IR-node with node number nr is lowered.
431 * Show all Firm internal breakpoints.
435 * Enables breakpoint nr.
439 * Disables breakpoint nr.
446 * The Firm debugger extension can be accessed using the function firm_break().
447 * The following example shows how to set a creation breakpoint in GDB when
448 * node 2101 is created.
450 * 1.) set FIRMDBG=".init"
451 * 2.) start gdb with your compiler
452 * 3.) after gdb breaks, issue
454 * p firm_debug(".create 2101")
456 * On the console the following text should be issued:
458 * Firm BP 1: creation of Node 2101