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
39 #include "irgraph_t.h"
45 /** Break into the debugger. The Win32 way. */
46 static void firm_debug_break(void) {
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");
55 /** Break into the debugger. Poor Unix way. */
56 static void firm_debug_break(void) {
61 /** supported breakpoint kinds */
63 BP_NODE = 'n', /**< break on node number. */
64 BP_IDENT = 'i' /**< break on ident. */
68 * Reasons for node number breakpoints.
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 */
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 */
89 /** A node number breakpoint. */
91 breakpoint bp; /**< the breakpoint data */
92 long nr; /**< the node number */
95 /** calculate the hash value for a node breakpoint */
96 #define HASH_NODE_BP(key) (((key).nr << 2) ^ (key).bp.reason)
98 /** A ident breakpoint. */
100 breakpoint bp; /**< the breakpoint data */
101 ident *id; /**< the ident */
104 /** calculate the hash value for an ident breakpoint */
105 #define HASH_IDENT_BP(key) (HASH_PTR((key).id) ^ (key).bp.reason)
107 /** The set containing the breakpoints on node numbers. */
108 static set *bp_node_numbers;
110 /** The set containing the breakpoints on idents. */
111 static set *bp_idents;
113 /**< the list of all breakpoints */
114 static breakpoint *bp_list;
116 /** number of the current break point */
117 static unsigned bp_num = 0;
119 /** set if break on init command was issued. */
120 static int break_on_init = 0;
122 /** the hook entries for the Firm debugger module. */
123 static hook_entry_t debugger_hooks[hook_last];
125 /** number of active breakpoints to maintain hooks. */
126 static unsigned num_active_bp[BP_MAX_REASON];
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])
132 /** unhook the hook h */
133 #define UNHOOK(h) unregister_hook(h, &debugger_hooks[h])
135 /** returns non-zero if a entry hook h is used */
136 #define IS_HOOKED(h) (debugger_hooks[h].next != NULL)
139 * A new node is created.
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
145 static void dbg_new_node(void *ctx, ir_graph *irg, ir_node *node)
147 bp_node_t key, *elem;
149 key.nr = get_irn_node_nr(node);
150 key.bp.reason = BP_ON_NEW_NODE;
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);
160 * A node is replaced.
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
166 static void dbg_replace(void *ctx, ir_node *old, ir_node *nw)
168 bp_node_t key, *elem;
170 key.nr = get_irn_node_nr(old);
171 key.bp.reason = BP_ON_REPLACE;
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);
181 * A new node is lowered.
183 * @param ctx the hook context
184 * @param node the new IR node that will be lowered
186 static void dbg_lower(void *ctx, ir_node *node)
188 bp_node_t key, *elem;
190 key.nr = get_irn_node_nr(node);
191 key.bp.reason = BP_ON_LOWER;
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);
201 * A graph will be deleted.
203 * @param ctx the hook context
204 * @param irg the IR graph that will be deleted
206 static void dbg_free_graph(void *ctx, ir_graph *irg)
208 bp_ident_t key, *elem;
209 entity *ent = get_irg_entity(irg);
214 key.id = get_entity_ident(ent);
215 key.bp.reason = BP_ON_REMIRG;
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);
225 * An entity was created.
227 * @param ctx the hook context
228 * @param ent the newly created entity
230 static void dbg_new_entity(void *ctx, entity *ent)
232 bp_ident_t key, *elem;
234 key.id = get_entity_ident(ent);
235 key.bp.reason = BP_ON_NEW_ENT;
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);
245 * A type was created.
247 * @param ctx the hook context
248 * @param tp the newly created type
250 static void dbg_new_type(void *ctx, type *tp)
252 bp_ident_t key, *elem;
254 key.id = get_type_ident(tp);
255 key.bp.reason = BP_ON_NEW_TYPE;
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);
265 * return the reason string.
267 static const char *reason_str(bp_reasons_t 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";
282 * Compare two node number breakpoints
284 static int cmp_node_bp(const void *elt, const void *key, size_t size)
286 const bp_node_t *e1 = elt;
287 const bp_node_t *e2 = key;
289 return (e1->nr - e2->nr) | (e1->bp.reason - e2->bp.reason);
293 * Compare two ident breakpoints
295 static int cmp_ident_bp(const void *elt, const void *key, size_t size)
297 const bp_ident_t *e1 = elt;
298 const bp_ident_t *e2 = key;
300 return (e1->id != e2->id) | (e1->bp.reason - e2->bp.reason);
306 static void update_hooks(breakpoint *bp)
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
312 ++num_active_bp[bp->reason];
314 --num_active_bp[bp->reason];
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);
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);
347 * Break if node nr is reached.
349 static void break_on_node(long nr, bp_reasons_t reason)
351 bp_node_t key, *elem;
353 key.bp.kind = BP_NODE;
356 key.bp.reason = reason;
359 elem = set_insert(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
361 if (elem->bp.bpnr == 0) {
362 /* new break point */
363 elem->bp.bpnr = ++bp_num;
364 elem->bp.next = bp_list;
367 printf("Firm BP %u: %s of Node %ld\n", elem->bp.bpnr, reason_str(reason), nr);
369 update_hooks(&elem->bp);
374 * Break if ident name is reached.
376 static void break_on_ident(const char *name, bp_reasons_t reason) {
377 bp_ident_t key, *elem;
379 key.bp.kind = BP_IDENT;
382 key.bp.reason = reason;
383 key.id = new_id_from_str(name);
385 elem = set_insert(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
387 if (elem->bp.bpnr == 0) {
388 /* new break point */
389 elem->bp.bpnr = ++bp_num;
390 elem->bp.next = bp_list;
393 printf("Firm BP %u: %s of ident \"%s\"\n", elem->bp.bpnr, reason_str(reason), name);
395 update_hooks(&elem->bp);
400 * Sets/resets the active flag of breakpoint bp.
402 static void bp_activate(unsigned bp, int active)
406 for (p = bp_list; p; p = p->next) {
408 if (p->active != active) {
413 printf("Firm BP %u is now %s\n", bp, active ? "enabled" : "disabled");
417 printf("Error: Firm BP %u not exists.\n", bp);
422 * Show a list of supported commands
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 ".setoutfile name file redirects debug output of module name to file\n"
438 ".help list all commands\n"
443 * Shows all Firm breakpoints.
445 static void show_bp(void) {
450 for (p = bp_list; p; p = p->next) {
451 printf("Firm BP %u: ", p->bpnr);
455 node_p = (bp_node_t *)p;
456 printf("%s of node %ld ", reason_str(p->reason), node_p->nr);
460 ident_p = (bp_ident_t *)p;
461 printf("%s of ident \"%s\" ", reason_str(p->reason), get_id_str(ident_p->id));
465 printf(p->active ? "enabled\n" : "disabled\n");
470 * firm_dbg_register() expects that the name is stored persistent.
471 * So we need this little helper function
473 static firm_dbg_module_t *dbg_register(const char *name) {
474 ident *id = new_id_from_str(name);
476 return firm_dbg_register(get_id_str(id));
480 * Sets the debug mask of module name to lvl
482 static void set_dbg_level(const char *name, unsigned lvl)
484 firm_dbg_module_t *module = dbg_register(name);
486 firm_dbg_set_mask(module, lvl);
488 printf("Setting debug mask of module %s to %u\n", name, lvl);
492 * Redirects the debug output of module name to fname
494 static void set_dbg_outfile(const char *name, const char *fname)
496 firm_dbg_module_t *module = dbg_register(name);
497 FILE *f = fopen(fname, "w");
504 firm_dbg_set_file(module, f);
505 printf("Redirecting debug output of module %s to file %s\n", name, fname);
509 * High level function to use from debugger interface
511 * Supported commands:
512 * .create nr break if node nr was created
513 * .help list all commands
515 void firm_debug(const char *cmd) {
518 char name[1024], fname[1024];
521 while (isspace(*cmd)) ++cmd;
523 if (sscanf(cmd, ".create %ld\n", &nr) == 1) {
524 break_on_node(nr, BP_ON_NEW_NODE);
526 else if (sscanf(cmd, ".replace %ld\n", &nr) == 1) {
527 break_on_node(nr, BP_ON_REPLACE);
529 else if (sscanf(cmd, ".lower %ld\n", &nr) == 1) {
530 break_on_node(nr, BP_ON_LOWER);
532 else if (sscanf(cmd, ".remirg %s\n", name) == 1) {
533 break_on_ident(name, BP_ON_REMIRG);
535 else if (sscanf(cmd, ".newent %s\n", name) == 1) {
536 break_on_ident(name, BP_ON_NEW_ENT);
538 else if (sscanf(cmd, ".newtype %s\n", name) == 1) {
539 break_on_ident(name, BP_ON_NEW_TYPE);
541 else if (strcmp(cmd, ".init") == 0)
543 else if (strcmp(cmd, ".bp") == 0)
545 else if (sscanf(cmd, ".enable %u", &bp) == 1)
547 else if (sscanf(cmd, ".disable %u", &bp) == 1)
549 else if (sscanf(cmd, ".setmask %s %u\n", name, &lvl) == 2)
550 set_dbg_level(name, lvl);
551 else if (sscanf(cmd, ".setoutfile %s %s\n", name, fname) == 2)
552 set_dbg_outfile(name, fname);
558 /* creates the debugger tables */
559 void firm_init_debugger(void)
563 bp_node_numbers = new_set(cmp_node_bp, 8);
564 bp_idents = new_set(cmp_ident_bp, 8);
566 env = getenv("FIRMDBG");
578 * @page debugger The Firm debugger extension
580 * Firm contains a debugger extension. This allows to set debugger breakpoints
582 * The extension uses a text interface which can be accessed from most debuggers.
584 * @section sec_cmd Supported commands
586 * The following commands are currently supported:
590 * Break immediately after the debugger extension was initialized.
591 * Typically this command is used in the environment to stop the execution
592 * of a Firm compiler right after the initialization, like this:
594 * $export FIRMDBG=".init"
599 * Break if a new IR-node with node number nr was created.
600 * Typically used to find the place where wrong nodes are created.
604 * Break before IR-node with node number nr is replaced by another node.
608 * Break before IR-node with node number nr is lowered.
612 * Break if the irg of entity name is deleted.
616 * Break if the entity name was created.
620 * Break if the type name was created.
624 * Show all Firm internal breakpoints.
628 * Enables breakpoint nr.
632 * Disables breakpoint nr.
634 * @b .setmask name lvl
636 * Sets the debug module name to level lvl.
638 * @b .setoutfile name file
640 * Redirects debug output of module name to file\.
647 * The Firm debugger extension can be accessed using the function firm_debug().
648 * The following example shows how to set a creation breakpoint in GDB when
649 * node 2101 is created.
651 * -# set FIRMDBG=".init"
652 * -# start gdb with your compiler
653 * -# after gdb breaks, issue
655 * p firm_debug(".create 2101")
657 * On the console the following text should be issued:
659 * Firm BP 1: creation of Node 2101
662 * @section gdb_macro GDB macro
664 * Add the following to your .gdbinit file:
667 # define firm "cmd" Firm debugger extension
674 * Then, all Firm debugger extension commands can be access in the gdb
675 * console using the firm prefix, eg.:
677 * firm ".create 2101"