3 * File name: ir/debug/debugger.c
4 * Purpose: Helper function for integerated debug support
9 * Copyright: (c) 2001-2006 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"
47 /* Break into the debugger. The Win32 way. */
48 void firm_debug_break(void) {
51 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64))
52 /* Break into the debugger. The ia32/x86_64 way under GCC. */
53 void firm_debug_break(void) {
54 __asm__ __volatile__("int3");
57 /* Break into the debugger. Poor Unix way. */
58 void firm_debug_break(void) {
63 /** supported breakpoint kinds */
65 BP_NR = 'n', /**< break on node number. */
66 BP_IDENT = 'i' /**< break on ident. */
70 * Reasons for node number breakpoints.
72 typedef enum _bp_reasons_t {
73 BP_ON_NEW_NODE, /**< break if node with number is created */
74 BP_ON_REPLACE, /**< break if node with number is replaced */
75 BP_ON_LOWER, /**< break if node with number is lowered */
76 BP_ON_REMIRG, /**< break if an IRG is removed */
77 BP_ON_NEW_ENT, /**< break if a new entity is created */
78 BP_ON_NEW_TYPE, /**< break if a new type is created */
83 typedef struct _breakpoint {
84 bp_kind kind; /**< the kind of this break point */
85 unsigned bpnr; /**< break point number */
86 int active; /**< non-zero, if this break point is active */
87 bp_reasons_t reason; /**< reason for the breakpoint */
88 struct _breakpoint *next; /**< link to the next one */
91 /** A number breakpoint. */
93 breakpoint bp; /**< the breakpoint data */
94 long nr; /**< the node number */
97 /** Calculate the hash value for a node breakpoint. */
98 #define HASH_NR_BP(key) (((key).nr << 2) ^ (key).bp.reason)
100 /** An ident breakpoint. */
102 breakpoint bp; /**< the breakpoint data */
103 ident *id; /**< the ident */
106 /** Calculate the hash value for an ident breakpoint. */
107 #define HASH_IDENT_BP(key) (HASH_PTR((key).id) ^ (key).bp.reason)
109 /** The set containing the breakpoints on node numbers. */
110 static set *bp_numbers;
112 /** The set containing the breakpoints on idents. */
113 static set *bp_idents;
115 /**< the list of all breakpoints */
116 static breakpoint *bp_list;
118 /** number of the current break point */
119 static unsigned bp_num = 0;
121 /** set if break on init command was issued. */
122 static int break_on_init = 0;
124 /** the hook entries for the Firm debugger module. */
125 static hook_entry_t debugger_hooks[hook_last];
127 /** number of active breakpoints to maintain hooks. */
128 static unsigned num_active_bp[BP_MAX_REASON];
131 * The debug message buffer
133 static char firm_dbg_msg_buf[2048];
136 * If set, the debug extension writes all output to the
137 * firm_dbg_msg_buf buffer
139 static int redir_output = 0;
142 * Is set to one, if the debug extension is active
144 static int is_active = 0;
146 /** hook the hook h with function fkt. */
147 #define HOOK(h, fkt) \
149 debugger_hooks[h].hook._##h = fkt; \
150 register_hook(h, &debugger_hooks[h]); \
153 /** unhook the hook h */
156 unregister_hook(h, &debugger_hooks[h]); \
157 debugger_hooks[h].hook._##h = NULL; \
160 /** returns non-zero if a entry hook h is used */
161 #define IS_HOOKED(h) (debugger_hooks[h].hook._##h != NULL)
163 /* some macros needed to create the info string */
164 #define _DBG_VERSION(major, minor) #major "." #minor
165 #define DBG_VERSION(major, minor) _DBG_VERSION(major, minor)
166 #define API_VERSION(major, minor) "API:" DBG_VERSION(major, minor)
168 /* the API version: change if needed */
169 #define FIRM_DBG_MAJOR 1
170 #define FIRM_DBG_MINOR 0
172 /** for automatic detection of the debug extension */
173 static const char *firm_debug_info_string =
174 API_VERSION(FIRM_DBG_MAJOR, FIRM_DBG_MINOR)
178 * Returns non-zero, if the debug extension is active
180 int firm_debug_active(void) {
182 } /* firm_debug_active */
185 * Reset the debug text buffer.
187 static void reset_dbg_buf(void) {
188 firm_dbg_msg_buf[0] = '\0';
189 } /* reset_dbg_buf */
192 * Add text to the debug text buffer.
194 static void add_to_dbg_buf(const char *buf) {
195 strncat(firm_dbg_msg_buf, buf, sizeof(firm_dbg_msg_buf));
196 } /* add_to_dbg_buf */
199 * Return the content of the debug text buffer.
201 * To be called from the debugger.
203 const char *firm_debug_text(void) {
204 firm_dbg_msg_buf[sizeof(firm_dbg_msg_buf) - 1] = '\0';
205 return firm_dbg_msg_buf;
206 } /* firm_debug_text */
211 static void dbg_printf(const char *fmt, ...)
223 ir_vsnprintf(buf, sizeof(buf), fmt, args);
233 * A new node is created.
235 * @param ctx the hook context
236 * @param irg the IR graph on which the node is created
237 * @param node the new IR node that was created
239 static void dbg_new_node(void *ctx, ir_graph *irg, ir_node *node)
243 key.nr = get_irn_node_nr(node);
244 key.bp.reason = BP_ON_NEW_NODE;
246 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
247 if (elem && elem->bp.active) {
248 dbg_printf("Firm BP %u reached, %+F created\n", elem->bp.bpnr, node);
254 * A node is replaced.
256 * @param ctx the hook context
257 * @param old the IR node the is replaced
258 * @param nw the new IR node that will replace old
260 static void dbg_replace(void *ctx, ir_node *old, ir_node *nw)
264 key.nr = get_irn_node_nr(old);
265 key.bp.reason = BP_ON_REPLACE;
267 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
268 if (elem && elem->bp.active) {
269 dbg_printf("Firm BP %u reached, %+F will be replaced by %+F\n", elem->bp.bpnr, old, nw);
275 * A new node is lowered.
277 * @param ctx the hook context
278 * @param node the new IR node that will be lowered
280 static void dbg_lower(void *ctx, ir_node *node)
284 key.nr = get_irn_node_nr(node);
285 key.bp.reason = BP_ON_LOWER;
287 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
288 if (elem && elem->bp.active) {
289 dbg_printf("Firm BP %u reached, %+F will be lowered\n", elem->bp.bpnr, node);
295 * A graph will be deleted.
297 * @param ctx the hook context
298 * @param irg the IR graph that will be deleted
300 static void dbg_free_graph(void *ctx, ir_graph *irg)
304 key.nr = get_irg_graph_nr(irg);
305 key.bp.reason = BP_ON_REMIRG;
307 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
308 if (elem && elem->bp.active) {
309 ir_printf("Firm BP %u reached, %+F will be deleted\n", elem->bp.bpnr, irg);
314 bp_ident_t key, *elem;
315 ir_entity *ent = get_irg_entity(irg);
320 key.id = get_entity_ident(ent);
321 key.bp.reason = BP_ON_REMIRG;
323 elem = set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
324 if (elem && elem->bp.active) {
325 dbg_printf("Firm BP %u reached, %+F will be deleted\n", elem->bp.bpnr, ent);
329 } /* dbg_free_graph */
332 * An entity was created.
334 * @param ctx the hook context
335 * @param ent the newly created entity
337 static void dbg_new_entity(void *ctx, ir_entity *ent)
340 bp_ident_t key, *elem;
342 key.id = get_entity_ident(ent);
343 key.bp.reason = BP_ON_NEW_ENT;
345 elem = set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
346 if (elem && elem->bp.active) {
347 ir_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, ent);
354 key.nr = get_entity_nr(ent);
355 key.bp.reason = BP_ON_NEW_ENT;
357 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
358 if (elem && elem->bp.active) {
359 dbg_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, ent);
363 } /* dbg_new_entity */
366 * A type was created.
368 * @param ctx the hook context
369 * @param tp the newly created type
371 static void dbg_new_type(void *ctx, ir_type *tp)
376 key.nr = get_type_nr(tp);
377 key.bp.reason = BP_ON_NEW_TYPE;
379 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
380 if (elem && elem->bp.active) {
381 ir_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, tp);
386 bp_ident_t key, *elem;
388 key.id = get_type_ident(tp);
389 key.bp.reason = BP_ON_NEW_TYPE;
391 elem = set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
392 if (elem && elem->bp.active) {
393 dbg_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, tp);
400 * Return the reason string.
402 static const char *reason_str(bp_reasons_t reason)
405 case BP_ON_NEW_NODE: return "node creation";
406 case BP_ON_REPLACE: return "node replace";
407 case BP_ON_LOWER: return "node lowering";
408 case BP_ON_REMIRG: return "removing IRG";
409 case BP_ON_NEW_ENT: return "entity creation";
410 case BP_ON_NEW_TYPE: return "type creation";
417 * Compare two number breakpoints.
419 static int cmp_nr_bp(const void *elt, const void *key, size_t size)
421 const bp_nr_t *e1 = elt;
422 const bp_nr_t *e2 = key;
424 return (e1->nr - e2->nr) | (e1->bp.reason - e2->bp.reason);
428 * Compare two ident breakpoints.
430 static int cmp_ident_bp(const void *elt, const void *key, size_t size)
432 const bp_ident_t *e1 = elt;
433 const bp_ident_t *e2 = key;
435 return (e1->id != e2->id) | (e1->bp.reason - e2->bp.reason);
441 static void update_hooks(breakpoint *bp)
443 #define CASE_ON(a, b) case a: if (! IS_HOOKED(hook_##b)) HOOK(hook_##b, dbg_##b); break
444 #define CASE_OFF(a, b) case a: if (IS_HOOKED(hook_##b)) UNHOOK(hook_##b); break
447 ++num_active_bp[bp->reason];
449 --num_active_bp[bp->reason];
451 if (num_active_bp[bp->reason] > 0) {
452 /* register the hooks on demand */
453 switch (bp->reason) {
454 CASE_ON(BP_ON_NEW_NODE, new_node);
455 CASE_ON(BP_ON_REPLACE, replace);
456 CASE_ON(BP_ON_LOWER, lower);
457 CASE_ON(BP_ON_REMIRG, free_graph);
458 CASE_ON(BP_ON_NEW_ENT, new_entity);
459 CASE_ON(BP_ON_NEW_TYPE, new_type);
465 /* unregister the hook on demand */
466 switch (bp->reason) {
467 CASE_OFF(BP_ON_NEW_NODE, new_node);
468 CASE_OFF(BP_ON_REPLACE, replace);
469 CASE_OFF(BP_ON_LOWER, lower);
470 CASE_OFF(BP_ON_REMIRG, free_graph);
471 CASE_OFF(BP_ON_NEW_ENT, new_entity);
472 CASE_OFF(BP_ON_NEW_TYPE, new_type);
482 * Break if nr is reached.
484 static void break_on_nr(long nr, bp_reasons_t reason)
491 key.bp.reason = reason;
494 elem = set_insert(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
496 if (elem->bp.bpnr == 0) {
497 /* new break point */
498 elem->bp.bpnr = ++bp_num;
499 elem->bp.next = bp_list;
502 dbg_printf("Firm BP %u: %s of Nr %ld\n", elem->bp.bpnr, reason_str(reason), nr);
504 update_hooks(&elem->bp);
509 * Break if ident name is reached.
511 static void break_on_ident(const char *name, bp_reasons_t reason) {
512 bp_ident_t key, *elem;
514 key.bp.kind = BP_IDENT;
517 key.bp.reason = reason;
518 key.id = new_id_from_str(name);
520 elem = set_insert(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
522 if (elem->bp.bpnr == 0) {
523 /* new break point */
524 elem->bp.bpnr = ++bp_num;
525 elem->bp.next = bp_list;
528 dbg_printf("Firm BP %u: %s of ident \"%s\"\n", elem->bp.bpnr, reason_str(reason), name);
530 update_hooks(&elem->bp);
532 } /* break_on_ident */
535 * Sets/resets the active flag of breakpoint bp.
537 static void bp_activate(unsigned bp, int active)
541 for (p = bp_list; p; p = p->next) {
543 if (p->active != active) {
548 dbg_printf("Firm BP %u is now %s\n", bp, active ? "enabled" : "disabled");
552 dbg_printf("Error: Firm BP %u not exists.\n", bp);
557 * Show a list of supported commands
559 static void show_commands(void) {
560 dbg_printf("Internal Firm debugger extension $Revision$ commands:\n"
561 ".init break after initialization\n"
562 ".create nr break if node nr was created\n"
563 ".replace nr break if node nr is replaced by another node\n"
564 ".lower nr break before node nr is lowered\n"
565 ".remirg nr|name break if the irg of nr or entity name is deleted\n"
566 ".newent nr|name break if the entity nr or name was created\n"
567 ".newtype nr|name break if the type nr or name was created\n"
568 ".bp show all breakpoints\n"
569 ".enable nr enable breakpoint nr\n"
570 ".disable nr disable breakpoint nr\n"
571 ".showtype nr|name show content of the type nr or name\n"
572 ".showent nr|name show content of the entity nr or name\n"
573 ".setmask name msk sets the debug module name to mask msk\n"
574 ".setlvl name lvl sets the debug module name to level lvl\n"
575 ".setoutfile name file redirects debug output of module name to file\n"
576 ".irgname name prints address and graph number of a method given by its name\n"
577 ".irgldname ldname prints address and graph number of a method given by its ldname\n"
578 ".help list all commands\n"
580 } /* show_commands */
583 * Shows all Firm breakpoints.
585 static void show_bp(void) {
591 dbg_printf("Firm Breakpoints:");
592 for (p = bp_list; p; p = p->next) {
594 dbg_printf("+\n BP %u: ", p->bpnr);
598 node_p = (bp_nr_t *)p;
599 dbg_printf("%s of Nr %ld ", reason_str(p->reason), node_p->nr);
603 ident_p = (bp_ident_t *)p;
604 dbg_printf("+%s of ident \"%s\" ", reason_str(p->reason), get_id_str(ident_p->id));
608 dbg_printf(p->active ? "+enabled" : "+disabled");
610 dbg_printf(have_one ? "+\n" : "+ NONE\n");
614 * firm_dbg_register() expects that the name is stored persistent.
615 * So we need this little helper function
617 static firm_dbg_module_t *dbg_register(const char *name) {
618 ident *id = new_id_from_str(name);
620 return firm_dbg_register(get_id_str(id));
624 * Sets the debug mask of module name to lvl
626 static void set_dbg_level(const char *name, unsigned lvl)
628 firm_dbg_module_t *module = dbg_register(name);
630 if (firm_dbg_get_mask(module) != lvl) {
631 firm_dbg_set_mask(module, lvl);
633 dbg_printf("Setting debug mask of module %s to %u\n", name, lvl);
635 } /* set_dbg_level */
638 * Redirects the debug output of module name to fname
640 static void set_dbg_outfile(const char *name, const char *fname)
642 firm_dbg_module_t *module = dbg_register(name);
643 FILE *f = fopen(fname, "w");
650 firm_dbg_set_file(module, f);
651 dbg_printf("Redirecting debug output of module %s to file %s\n", name, fname);
652 } /* set_dbg_outfile */
655 * Show info about a firm thing.
657 static void show_firm_object(void *firm_thing) {
660 if (firm_thing == NULL) {
661 fprintf(f, "<NULL>\n");
664 switch (get_kind(firm_thing)) {
666 fprintf(f, "BAD: (%p)\n", firm_thing);
669 dump_entity_to_file(f, firm_thing, dump_verbosity_max);
672 dump_type_to_file(f, firm_thing, dump_verbosity_max);
680 case k_ir_compound_graph_path:
686 fprintf(f, "Cannot identify thing at (%p).\n", firm_thing);
688 } /* show_firm_object */
691 * Find a firm type by its number.
693 static ir_type *find_type_nr(long nr) {
694 int i, n = get_irp_n_types();
697 for (i = 0; i < n; ++i) {
698 tp = get_irp_type(i);
699 if (get_type_nr(tp) == nr)
702 tp = get_glob_type();
703 if (get_type_nr(tp) == nr)
709 * Find a firm type by its name.
711 static ir_type *find_type_name(const char *name) {
712 int i, n = get_irp_n_types();
715 for (i = 0; i < n; ++i) {
716 tp = get_irp_type(i);
717 if (strcmp(get_type_name(tp), name) == 0)
720 tp = get_glob_type();
721 if (strcmp(get_type_name(tp), name) == 0)
724 } /* find_type_name */
726 /** The environment for the entity search functions. */
727 typedef struct find_env {
729 long nr; /**< the number that is searched for */
730 const char *name; /**< the name that is searched for */
732 ir_entity *res; /**< the result */
736 * Type-walker: Find an entity with given number.
738 static void check_ent_nr(type_or_ent *tore, void *ctx) {
739 ir_entity *ent = (ir_entity *)tore;
740 find_env_t *env = ctx;
743 if (get_entity_nr(ent) == env->u.nr) {
749 * Type-walker: Find an entity with given name.
751 static void check_ent_name(type_or_ent *tore, void *ctx) {
752 ir_entity *ent = (ir_entity *)tore;
753 find_env_t *env = ctx;
756 if (strcmp(get_entity_name(ent), env->u.name) == 0) {
759 } /* check_ent_name */
762 * Find a firm entity by its number.
764 static ir_entity *find_entity_nr(long nr) {
769 type_walk(check_ent_nr, NULL, &env);
771 } /* find_entity_nr */
774 * Find a firm entity by its name.
776 static ir_entity *find_entity_name(const char *name) {
781 type_walk(check_ent_name, NULL, &env);
783 } /* find_entity_name */
786 * Search methods for a name.
788 static void show_by_name(type_or_ent *tore, void *env) {
789 ident *id = (ident *)env;
791 if (is_entity(tore)) {
792 ir_entity *ent = (ir_entity *)tore;
794 if (is_method_entity(ent)) {
795 if (get_entity_ident(ent) == id) {
796 ir_type *owner = get_entity_owner(ent);
797 ir_graph *irg = get_entity_irg(ent);
799 if (owner != get_glob_type()) {
800 printf("%s::%s", get_type_name(owner), get_id_str(id));
802 printf("%s", get_id_str(id));
805 printf("[%ld] (%p)\n", get_irg_graph_nr(irg), irg);
814 * Search methods for a ldname.
816 static void show_by_ldname(type_or_ent *tore, void *env) {
817 ident *id = (ident *)env;
819 if (is_entity(tore)) {
820 ir_entity *ent = (ir_entity *)tore;
822 if (is_method_entity(ent)) {
823 if (get_entity_ld_ident(ent) == id) {
824 ir_type *owner = get_entity_owner(ent);
825 ir_graph *irg = get_entity_irg(ent);
827 if (owner != get_glob_type()) {
828 printf("%s::%s", get_type_name(owner), get_id_str(id));
830 printf("%s", get_id_str(id));
833 printf("[%ld] (%p)\n", get_irg_graph_nr(irg), irg);
839 } /* show_by_ldname */
842 * prints the address and graph number of all irgs with given name
844 static void irg_name(const char *name) {
845 ident *id = new_id_from_str(name);
847 type_walk(show_by_name, NULL, (void *)id);
851 * prints the address and graph number of all irgs with given ld_name
853 static void irg_ld_name(const char *name) {
854 ident *id = new_id_from_str(name);
856 type_walk(show_by_ldname, NULL, (void *)id);
860 * High level function to use from debugger interface
862 * Supported commands:
863 * .create nr break if node nr was created
864 * .help list all commands
866 void firm_debug(const char *cmd) {
869 char name[1024], fname[1024];
872 while (isspace(*cmd)) ++cmd;
874 if (sscanf(cmd, ".create %ld\n", &nr) == 1) {
875 break_on_nr(nr, BP_ON_NEW_NODE);
877 else if (sscanf(cmd, ".replace %ld\n", &nr) == 1) {
878 break_on_nr(nr, BP_ON_REPLACE);
880 else if (sscanf(cmd, ".lower %ld\n", &nr) == 1) {
881 break_on_nr(nr, BP_ON_LOWER);
883 else if (sscanf(cmd, ".remirg %ld\n", &nr) == 1) {
884 break_on_nr(nr, BP_ON_REMIRG);
886 else if (sscanf(cmd, ".remirg %s\n", name) == 1) {
887 break_on_ident(name, BP_ON_REMIRG);
889 else if (sscanf(cmd, ".newent %ld\n", &nr) == 1) {
890 break_on_nr(nr, BP_ON_NEW_ENT);
892 else if (sscanf(cmd, ".newent %s\n", name) == 1) {
893 break_on_ident(name, BP_ON_NEW_ENT);
895 else if (sscanf(cmd, ".newtype %ld\n", &nr) == 1) {
896 break_on_nr(nr, BP_ON_NEW_TYPE);
898 else if (sscanf(cmd, ".newtype %s\n", name) == 1) {
899 break_on_ident(name, BP_ON_NEW_TYPE);
901 else if (sscanf(cmd, ".showtype %ld\n", &nr) == 1) {
902 show_firm_object(find_type_nr(nr));
904 else if (sscanf(cmd, ".showtype %s\n", name) == 1) {
905 show_firm_object(find_type_name(name));
907 else if (sscanf(cmd, ".showent %ld\n", &nr) == 1) {
908 show_firm_object(find_entity_nr(nr));
910 else if (sscanf(cmd, ".showent %s\n", name) == 1) {
911 show_firm_object(find_entity_name(name));
913 else if (strcmp(cmd, ".init") == 0)
915 else if (strcmp(cmd, ".bp") == 0)
917 else if (sscanf(cmd, ".enable %u", &bp) == 1)
919 else if (sscanf(cmd, ".disable %u", &bp) == 1)
921 else if (sscanf(cmd, ".setmask %s %u\n", name, &lvl) == 2)
922 set_dbg_level(name, lvl);
923 else if (sscanf(cmd, ".setlvl %s %u\n", name, &lvl) == 2)
924 set_dbg_level(name, (1 << lvl) - 1);
925 else if (sscanf(cmd, ".setoutfile %s %s\n", name, fname) == 2)
926 set_dbg_outfile(name, fname);
927 else if (sscanf(cmd, ".irgname %s\n", name) == 1)
929 else if (sscanf(cmd, ".irgldname %s\n", name) == 1)
936 /* creates the debugger tables */
937 void firm_init_debugger(void)
941 bp_numbers = new_set(cmp_nr_bp, 8);
942 bp_idents = new_set(cmp_ident_bp, 8);
944 env = getenv("FIRMDBG");
953 } /* firm_init_debugger */
957 /* some picky compiler do not allow empty files */
958 static int _firm_only_that_you_can_compile_with_NDEBUG_defined;
963 * @page debugger The Firm debugger extension
965 * Firm contains a debugger extension. This allows to set debugger breakpoints
967 * The extension uses a text interface which can be accessed from most debuggers.
969 * @section sec_cmd Supported commands
971 * The following commands are currently supported:
975 * Break immediately after the debugger extension was initialized.
976 * Typically this command is used in the environment to stop the execution
977 * of a Firm compiler right after the initialization, like this:
979 * $export FIRMDBG=".init"
983 * Break if a new IR-node with node number nr was created.
984 * Typically used to find the place where wrong nodes are created.
988 * Break before IR-node with node number nr is replaced by another node.
992 * Break before IR-node with node number nr is lowered.
996 * Break if the irg with graph number nr is deleted.
1000 * Break if the irg of entity name is deleted.
1004 * Break if the entity with number nr was created.
1008 * Break if the entity name was created.
1012 * Break if the type with number nr was created.
1016 * Break if the type name was created.
1020 * Show all Firm internal breakpoints.
1024 * Enables breakpoint nr.
1028 * Disables breakpoint nr.
1032 * Show the content of entity nr.
1036 * Show the content of entity name.
1040 * Show the content of type nr.
1044 * Show the content of type name.
1046 * @b .setmask name msk
1048 * Sets the debug module name to mask msk.
1050 * @b .setlvl name lvl
1052 * Sets the debug module name to level lvl.
1054 * @b .setoutfile name file
1056 * Redirects debug output of module name to file.
1060 * Prints address and graph number of a method given by its name.
1062 * @b .irgldname name
1064 * Prints address and graph number of a method given by its linker name.
1068 * List all commands.
1071 * The Firm debugger extension can be accessed using the function firm_debug().
1072 * The following example shows how to set a creation breakpoint in GDB when
1073 * node 2101 is created.
1075 * -# set FIRMDBG=".init"
1076 * -# start gdb with your compiler
1077 * -# after gdb breaks, issue
1079 * call firm_debug(".create 2101")
1081 * On the console the following text should be issued:
1083 * Firm BP 1: creation of Node 2101
1086 * @section gdb_macro GDB macro
1088 * Add the following to your .gdbinit file:
1091 # define firm "cmd" Firm debugger extension
1094 call firm_debug($arg0)
1098 * Then, all Firm debugger extension commands can be accessed in the gdb
1099 * console using the firm prefix, eg.:
1101 * firm ".create 2101"