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"
44 /** Break into the debugger. The Win32 way. */
45 static void firm_debug_break(void) {
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");
54 /** Break into the debugger. Poor Unix way. */
55 static void firm_debug_break(void) {
60 /** supported breakpoint kinds */
62 BP_NODE = 'n', /**< break on node number. */
63 BP_IDENT = 'i' /**< break on ident. */
67 * Reasons for node number breakpoints.
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 */
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 */
88 /** A node number breakpoint. */
90 breakpoint bp; /**< the breakpoint data */
91 long nr; /**< the node number */
94 /** calculate the hash value for a node breakpoint */
95 #define HASH_NODE_BP(key) (((key).nr << 2) ^ (key).bp.reason)
97 /** A ident breakpoint. */
99 breakpoint bp; /**< the breakpoint data */
100 ident *id; /**< the ident */
103 /** calculate the hash value for an ident breakpoint */
104 #define HASH_IDENT_BP(key) (HASH_PTR((key).id) ^ (key).bp.reason)
106 /** The set containing the breakpoints on node numbers. */
107 static set *bp_node_numbers;
109 /** The set containing the breakpoints on idents. */
110 static set *bp_idents;
112 /**< the list of all breakpoints */
113 static breakpoint *bp_list;
115 /** number of the current break point */
116 static unsigned bp_num = 0;
118 /** set if break on init command was issued. */
119 static int break_on_init = 0;
121 /** the hook entries for the Firm debugger module. */
122 static hook_entry_t debugger_hooks[hook_last];
124 /** number of active breakpoints to maintain hooks. */
125 static unsigned num_active_bp[BP_MAX_REASON];
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])
131 /** unhook the hook h */
132 #define UNHOOK(h) unregister_hook(h, &debugger_hooks[h])
134 /** returns non-zero if a entry hook h is used */
135 #define IS_HOOKED(h) (debugger_hooks[h].next != NULL)
138 * A new node is created.
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
144 static void dbg_new_node(void *ctx, ir_graph *irg, ir_node *node)
146 bp_node_t key, *elem;
148 key.nr = get_irn_node_nr(node);
149 key.bp.reason = BP_ON_NEW_NODE;
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);
159 * A node is replaced.
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
165 static void dbg_replace(void *ctx, ir_node *old, ir_node *nw)
167 bp_node_t key, *elem;
169 key.nr = get_irn_node_nr(old);
170 key.bp.reason = BP_ON_REPLACE;
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);
180 * A new node is lowered.
182 * @param ctx the hook context
183 * @param node the new IR node that will be lowered
185 static void dbg_lower(void *ctx, ir_node *node)
187 bp_node_t key, *elem;
189 key.nr = get_irn_node_nr(node);
190 key.bp.reason = BP_ON_LOWER;
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);
200 * A graph will be deleted.
202 * @param ctx the hook context
203 * @param irg the IR graph that will be deleted
205 static void dbg_free_graph(void *ctx, ir_graph *irg)
207 bp_ident_t key, *elem;
208 entity *ent = get_irg_entity(irg);
213 key.id = get_entity_ident(ent);
214 key.bp.reason = BP_ON_REMIRG;
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);
224 * An entity was created.
226 * @param ctx the hook context
227 * @param ent the newly created entity
229 static void dbg_new_entity(void *ctx, entity *ent)
231 bp_ident_t key, *elem;
233 key.id = get_entity_ident(ent);
234 key.bp.reason = BP_ON_NEW_ENT;
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);
244 * A type was created.
246 * @param ctx the hook context
247 * @param tp the newly created type
249 static void dbg_new_type(void *ctx, type *tp)
251 bp_ident_t key, *elem;
253 key.id = get_type_ident(tp);
254 key.bp.reason = BP_ON_NEW_TYPE;
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);
264 * return the reason string.
266 static const char *reason_str(bp_reasons_t 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";
281 * Compare two node number breakpoints
283 static int cmp_node_bp(const void *elt, const void *key, size_t size)
285 const bp_node_t *e1 = elt;
286 const bp_node_t *e2 = key;
288 return (e1->nr - e2->nr) | (e1->bp.reason - e2->bp.reason);
292 * Compare two ident breakpoints
294 static int cmp_ident_bp(const void *elt, const void *key, size_t size)
296 const bp_ident_t *e1 = elt;
297 const bp_ident_t *e2 = key;
299 return (e1->id != e2->id) | (e1->bp.reason - e2->bp.reason);
305 static void update_hooks(breakpoint *bp)
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
311 ++num_active_bp[bp->reason];
313 --num_active_bp[bp->reason];
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);
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);
346 * Break if node nr is reached.
348 static void break_on_node(long nr, bp_reasons_t reason)
350 bp_node_t key, *elem;
352 key.bp.kind = BP_NODE;
355 key.bp.reason = reason;
358 elem = set_insert(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
360 if (elem->bp.bpnr == 0) {
361 /* new break point */
362 elem->bp.bpnr = ++bp_num;
363 elem->bp.next = bp_list;
366 printf("Firm BP %u: %s of Node %ld\n", elem->bp.bpnr, reason_str(reason), nr);
368 update_hooks(&elem->bp);
373 * Break if ident name is reached.
375 static void break_on_ident(const char *name, bp_reasons_t reason) {
376 bp_ident_t key, *elem;
378 key.bp.kind = BP_IDENT;
381 key.bp.reason = reason;
382 key.id = new_id_from_str(name);
384 elem = set_insert(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
386 if (elem->bp.bpnr == 0) {
387 /* new break point */
388 elem->bp.bpnr = ++bp_num;
389 elem->bp.next = bp_list;
392 printf("Firm BP %u: %s of ident \"%s\"\n", elem->bp.bpnr, reason_str(reason), name);
394 update_hooks(&elem->bp);
399 * Sets/resets the active flag of breakpoint bp.
401 static void bp_activate(unsigned bp, int active)
405 for (p = bp_list; p; p = p->next) {
407 if (p->active != active) {
412 printf("Firm BP %u is now %s\n", bp, active ? "enabled" : "disabled");
416 printf("Error: Firm BP %u not exists.\n", bp);
421 * Show a list of supported commands
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"
440 * Shows all Firm breakpoints.
442 static void show_bp(void) {
447 for (p = bp_list; p; p = p->next) {
448 printf("Firm BP %u: ", p->bpnr);
452 node_p = (bp_node_t *)p;
453 printf("%s of node %ld ", reason_str(p->reason), node_p->nr);
457 ident_p = (bp_ident_t *)p;
458 printf("%s of ident \"%s\" ", reason_str(p->reason), get_id_str(ident_p->id));
462 printf(p->active ? "enabled\n" : "disabled\n");
467 * High level function to use from debugger interface
469 * Supported commands:
470 * .create nr break if node nr was created
471 * .help list all commands
473 void firm_break(const char *cmd) {
478 while (isspace(*cmd)) ++cmd;
480 if (sscanf(cmd, ".create %ld\n", &nr) == 1) {
481 break_on_node(nr, BP_ON_NEW_NODE);
483 else if (sscanf(cmd, ".replace %ld\n", &nr) == 1) {
484 break_on_node(nr, BP_ON_REPLACE);
486 else if (sscanf(cmd, ".lower %ld\n", &nr) == 1) {
487 break_on_node(nr, BP_ON_LOWER);
489 else if (sscanf(cmd, ".remirg %s\n", name) == 1) {
490 break_on_ident(name, BP_ON_REMIRG);
492 else if (sscanf(cmd, ".newent %s\n", name) == 1) {
493 break_on_ident(name, BP_ON_NEW_ENT);
495 else if (sscanf(cmd, ".newtype %s\n", name) == 1) {
496 break_on_ident(name, BP_ON_NEW_TYPE);
498 else if (strcmp(cmd, ".init") == 0)
500 else if (strcmp(cmd, ".bp") == 0)
502 else if (sscanf(cmd, ".enable %u", &bp) == 1)
504 else if (sscanf(cmd, ".disable %u", &bp) == 1)
511 /* creates the debugger tables */
512 void firm_init_debugger(void)
516 bp_node_numbers = new_set(cmp_node_bp, 8);
517 bp_idents = new_set(cmp_ident_bp, 8);
519 env = getenv("FIRMDBG");
531 * @page debugger The Firm debugger extension.
533 * Firm contains a debugger extension. This allows to set debugger breakpoints
535 * The extension uses a text interface which can be access in the debugger.
537 * The following commands are currently supported:
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:
545 * $export FIRMDBG=".init"
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.
555 * Break before IR-node with node number nr is replaced by another node.
559 * Break before IR-node with node number nr is lowered.
563 * Break if the irg of entity name is deleted.
567 * Break if the entity name was created.
571 * Break if the type name was created.
575 * Show all Firm internal breakpoints.
579 * Enables breakpoint nr.
583 * Disables breakpoint nr.
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.
594 * 1.) set FIRMDBG=".init"
595 * 2.) start gdb with your compiler
596 * 3.) after gdb breaks, issue
598 * p firm_debug(".create 2101")
600 * On the console the following text should be issued:
602 * Firm BP 1: creation of Node 2101