3 * File name: ir/debug/debugger.c
4 * Purpose: Helper function for integerated debug support
9 * Copyright: (c) 2001-2007 Universität Karlsruhe
10 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
19 #define WIN32_LEAN_AND_MEAN
22 #define strncasecmp strnicmp
41 #include "irgraph_t.h"
49 /* Break into the debugger. The Win32 way. */
50 void firm_debug_break(void) {
53 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64))
54 /* Break into the debugger. The ia32/x86_64 way under GCC. */
55 void firm_debug_break(void) {
56 __asm__ __volatile__("int3");
59 /* Break into the debugger. Poor Unix way. */
60 void firm_debug_break(void) {
65 /** supported breakpoint kinds */
67 BP_NR = 'n', /**< break on node number. */
68 BP_IDENT = 'i' /**< break on ident. */
72 * Reasons for node number breakpoints.
74 typedef enum _bp_reasons_t {
75 BP_ON_NEW_NODE, /**< break if node with number is created */
76 BP_ON_REPLACE, /**< break if node with number is replaced */
77 BP_ON_LOWER, /**< break if node with number is lowered */
78 BP_ON_REMIRG, /**< break if an IRG is removed */
79 BP_ON_NEW_ENT, /**< break if a new entity is created */
80 BP_ON_NEW_TYPE, /**< break if a new type is created */
85 typedef struct _breakpoint {
86 bp_kind kind; /**< the kind of this break point */
87 unsigned bpnr; /**< break point number */
88 int active; /**< non-zero, if this break point is active */
89 bp_reasons_t reason; /**< reason for the breakpoint */
90 struct _breakpoint *next; /**< link to the next one */
93 /** A number breakpoint. */
95 breakpoint bp; /**< the breakpoint data */
96 long nr; /**< the node number */
99 /** Calculate the hash value for a node breakpoint. */
100 #define HASH_NR_BP(key) (((key).nr << 2) ^ (key).bp.reason)
102 /** An ident breakpoint. */
104 breakpoint bp; /**< the breakpoint data */
105 ident *id; /**< the ident */
108 /** Calculate the hash value for an ident breakpoint. */
109 #define HASH_IDENT_BP(key) (HASH_PTR((key).id) ^ (key).bp.reason)
111 /** The set containing the breakpoints on node numbers. */
112 static set *bp_numbers;
114 /** The set containing the breakpoints on idents. */
115 static set *bp_idents;
117 /**< the list of all breakpoints */
118 static breakpoint *bp_list;
120 /** number of the current break point */
121 static unsigned bp_num = 0;
123 /** set if break on init command was issued. */
124 static int break_on_init = 0;
126 /** the hook entries for the Firm debugger module. */
127 static hook_entry_t debugger_hooks[hook_last];
129 /** number of active breakpoints to maintain hooks. */
130 static unsigned num_active_bp[BP_MAX_REASON];
133 * The debug message buffer
135 static char firm_dbg_msg_buf[2048];
138 * If set, the debug extension writes all output to the
139 * firm_dbg_msg_buf buffer
141 static int redir_output = 0;
144 * Is set to one, if the debug extension is active
146 static int is_active = 0;
148 /** hook the hook h with function fkt. */
149 #define HOOK(h, fkt) \
151 debugger_hooks[h].hook._##h = fkt; \
152 register_hook(h, &debugger_hooks[h]); \
155 /** unhook the hook h */
158 unregister_hook(h, &debugger_hooks[h]); \
159 debugger_hooks[h].hook._##h = NULL; \
162 /** returns non-zero if a entry hook h is used */
163 #define IS_HOOKED(h) (debugger_hooks[h].hook._##h != NULL)
165 /* some macros needed to create the info string */
166 #define _DBG_VERSION(major, minor) #major "." #minor
167 #define DBG_VERSION(major, minor) _DBG_VERSION(major, minor)
168 #define API_VERSION(major, minor) "API:" DBG_VERSION(major, minor)
170 /* the API version: change if needed */
171 #define FIRM_DBG_MAJOR 1
172 #define FIRM_DBG_MINOR 0
174 /** for automatic detection of the debug extension */
175 static const char *firm_debug_info_string =
176 API_VERSION(FIRM_DBG_MAJOR, FIRM_DBG_MINOR);
179 * Returns non-zero, if the debug extension is active
181 int firm_debug_active(void) {
183 } /* firm_debug_active */
186 * Reset the debug text buffer.
188 static void reset_dbg_buf(void) {
189 firm_dbg_msg_buf[0] = '\0';
190 } /* reset_dbg_buf */
193 * Add text to the debug text buffer.
195 static void add_to_dbg_buf(const char *buf) {
196 strncat(firm_dbg_msg_buf, buf, sizeof(firm_dbg_msg_buf));
197 } /* add_to_dbg_buf */
200 * Return the content of the debug text buffer.
202 * To be called from the debugger.
204 const char *firm_debug_text(void) {
205 firm_dbg_msg_buf[sizeof(firm_dbg_msg_buf) - 1] = '\0';
206 return firm_dbg_msg_buf;
207 } /* firm_debug_text */
212 static void dbg_printf(const char *fmt, ...)
224 ir_vsnprintf(buf, sizeof(buf), fmt, args);
234 * A new node is created.
236 * @param ctx the hook context
237 * @param irg the IR graph on which the node is created
238 * @param node the new IR node that was created
240 static void dbg_new_node(void *ctx, ir_graph *irg, ir_node *node)
244 key.nr = get_irn_node_nr(node);
245 key.bp.reason = BP_ON_NEW_NODE;
247 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
248 if (elem && elem->bp.active) {
249 dbg_printf("Firm BP %u reached, %+F created\n", elem->bp.bpnr, node);
255 * A node is replaced.
257 * @param ctx the hook context
258 * @param old the IR node the is replaced
259 * @param nw the new IR node that will replace old
261 static void dbg_replace(void *ctx, ir_node *old, ir_node *nw)
265 key.nr = get_irn_node_nr(old);
266 key.bp.reason = BP_ON_REPLACE;
268 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
269 if (elem && elem->bp.active) {
270 dbg_printf("Firm BP %u reached, %+F will be replaced by %+F\n", elem->bp.bpnr, old, nw);
276 * A new node is lowered.
278 * @param ctx the hook context
279 * @param node the new IR node that will be lowered
281 static void dbg_lower(void *ctx, ir_node *node)
285 key.nr = get_irn_node_nr(node);
286 key.bp.reason = BP_ON_LOWER;
288 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
289 if (elem && elem->bp.active) {
290 dbg_printf("Firm BP %u reached, %+F will be lowered\n", elem->bp.bpnr, node);
296 * A graph will be deleted.
298 * @param ctx the hook context
299 * @param irg the IR graph that will be deleted
301 static void dbg_free_graph(void *ctx, ir_graph *irg)
305 key.nr = get_irg_graph_nr(irg);
306 key.bp.reason = BP_ON_REMIRG;
308 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
309 if (elem && elem->bp.active) {
310 ir_printf("Firm BP %u reached, %+F will be deleted\n", elem->bp.bpnr, irg);
315 bp_ident_t key, *elem;
316 ir_entity *ent = get_irg_entity(irg);
321 key.id = get_entity_ident(ent);
322 key.bp.reason = BP_ON_REMIRG;
324 elem = set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
325 if (elem && elem->bp.active) {
326 dbg_printf("Firm BP %u reached, %+F will be deleted\n", elem->bp.bpnr, ent);
330 } /* dbg_free_graph */
333 * An entity was created.
335 * @param ctx the hook context
336 * @param ent the newly created entity
338 static void dbg_new_entity(void *ctx, ir_entity *ent)
341 bp_ident_t key, *elem;
343 key.id = get_entity_ident(ent);
344 key.bp.reason = BP_ON_NEW_ENT;
346 elem = set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
347 if (elem && elem->bp.active) {
348 ir_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, ent);
355 key.nr = get_entity_nr(ent);
356 key.bp.reason = BP_ON_NEW_ENT;
358 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
359 if (elem && elem->bp.active) {
360 dbg_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, ent);
364 } /* dbg_new_entity */
367 * A type was created.
369 * @param ctx the hook context
370 * @param tp the newly created type
372 static void dbg_new_type(void *ctx, ir_type *tp)
377 key.nr = get_type_nr(tp);
378 key.bp.reason = BP_ON_NEW_TYPE;
380 elem = set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
381 if (elem && elem->bp.active) {
382 ir_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, tp);
387 bp_ident_t key, *elem;
389 key.id = get_type_ident(tp);
390 key.bp.reason = BP_ON_NEW_TYPE;
392 elem = set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
393 if (elem && elem->bp.active) {
394 dbg_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, tp);
401 * Return the reason string.
403 static const char *reason_str(bp_reasons_t reason)
406 case BP_ON_NEW_NODE: return "node creation";
407 case BP_ON_REPLACE: return "node replace";
408 case BP_ON_LOWER: return "node lowering";
409 case BP_ON_REMIRG: return "removing IRG";
410 case BP_ON_NEW_ENT: return "entity creation";
411 case BP_ON_NEW_TYPE: return "type creation";
418 * Compare two number breakpoints.
420 static int cmp_nr_bp(const void *elt, const void *key, size_t size)
422 const bp_nr_t *e1 = elt;
423 const bp_nr_t *e2 = key;
425 return (e1->nr - e2->nr) | (e1->bp.reason - e2->bp.reason);
429 * Compare two ident breakpoints.
431 static int cmp_ident_bp(const void *elt, const void *key, size_t size)
433 const bp_ident_t *e1 = elt;
434 const bp_ident_t *e2 = key;
436 return (e1->id != e2->id) | (e1->bp.reason - e2->bp.reason);
442 static void update_hooks(breakpoint *bp)
444 #define CASE_ON(a, b) case a: if (! IS_HOOKED(hook_##b)) HOOK(hook_##b, dbg_##b); break
445 #define CASE_OFF(a, b) case a: if (IS_HOOKED(hook_##b)) UNHOOK(hook_##b); break
448 ++num_active_bp[bp->reason];
450 --num_active_bp[bp->reason];
452 if (num_active_bp[bp->reason] > 0) {
453 /* register the hooks on demand */
454 switch (bp->reason) {
455 CASE_ON(BP_ON_NEW_NODE, new_node);
456 CASE_ON(BP_ON_REPLACE, replace);
457 CASE_ON(BP_ON_LOWER, lower);
458 CASE_ON(BP_ON_REMIRG, free_graph);
459 CASE_ON(BP_ON_NEW_ENT, new_entity);
460 CASE_ON(BP_ON_NEW_TYPE, new_type);
466 /* unregister the hook on demand */
467 switch (bp->reason) {
468 CASE_OFF(BP_ON_NEW_NODE, new_node);
469 CASE_OFF(BP_ON_REPLACE, replace);
470 CASE_OFF(BP_ON_LOWER, lower);
471 CASE_OFF(BP_ON_REMIRG, free_graph);
472 CASE_OFF(BP_ON_NEW_ENT, new_entity);
473 CASE_OFF(BP_ON_NEW_TYPE, new_type);
483 * Break if nr is reached.
485 static void break_on_nr(long nr, bp_reasons_t reason)
492 key.bp.reason = reason;
495 elem = set_insert(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
497 if (elem->bp.bpnr == 0) {
498 /* new break point */
499 elem->bp.bpnr = ++bp_num;
500 elem->bp.next = bp_list;
503 dbg_printf("Firm BP %u: %s of Nr %ld\n", elem->bp.bpnr, reason_str(reason), nr);
505 update_hooks(&elem->bp);
510 * Break if ident name is reached.
512 static void break_on_ident(const char *name, bp_reasons_t reason) {
513 bp_ident_t key, *elem;
515 key.bp.kind = BP_IDENT;
518 key.bp.reason = reason;
519 key.id = new_id_from_str(name);
521 elem = set_insert(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
523 if (elem->bp.bpnr == 0) {
524 /* new break point */
525 elem->bp.bpnr = ++bp_num;
526 elem->bp.next = bp_list;
529 dbg_printf("Firm BP %u: %s of ident \"%s\"\n", elem->bp.bpnr, reason_str(reason), name);
531 update_hooks(&elem->bp);
533 } /* break_on_ident */
536 * Sets/resets the active flag of breakpoint bp.
538 static void bp_activate(unsigned bp, int active)
542 for (p = bp_list; p; p = p->next) {
544 if (p->active != active) {
549 dbg_printf("Firm BP %u is now %s\n", bp, active ? "enabled" : "disabled");
553 dbg_printf("Error: Firm BP %u not exists.\n", bp);
558 * Show a list of supported commands
560 static void show_commands(void) {
561 dbg_printf("Internal Firm debugger extension $Revision$ commands:\n"
562 ".init break after initialization\n"
563 ".create nr break if node nr was created\n"
564 ".replace nr break if node nr is replaced by another node\n"
565 ".lower nr break before node nr is lowered\n"
566 ".remirg nr|name break if the irg of nr or entity name is deleted\n"
567 ".newent nr|name break if the entity nr or name was created\n"
568 ".newtype nr|name break if the type nr or name was created\n"
569 ".bp show all breakpoints\n"
570 ".enable nr enable breakpoint nr\n"
571 ".disable nr disable breakpoint nr\n"
572 ".showtype nr|name show content of the type nr or name\n"
573 ".showent nr|name show content of the entity nr or name\n"
574 ".setmask name msk sets the debug module name to mask msk\n"
575 ".setlvl name lvl sets the debug module name to level lvl\n"
576 ".setoutfile name file redirects debug output of module name to file\n"
577 ".irgname name prints address and graph number of a method given by its name\n"
578 ".irgldname ldname prints address and graph number of a method given by its ldname\n"
579 ".help list all commands\n"
581 } /* show_commands */
584 * Shows all Firm breakpoints.
586 static void show_bp(void) {
592 dbg_printf("Firm Breakpoints:");
593 for (p = bp_list; p; p = p->next) {
595 dbg_printf("+\n BP %u: ", p->bpnr);
599 node_p = (bp_nr_t *)p;
600 dbg_printf("%s of Nr %ld ", reason_str(p->reason), node_p->nr);
604 ident_p = (bp_ident_t *)p;
605 dbg_printf("+%s of ident \"%s\" ", reason_str(p->reason), get_id_str(ident_p->id));
609 dbg_printf(p->active ? "+enabled" : "+disabled");
611 dbg_printf(have_one ? "+\n" : "+ NONE\n");
615 * firm_dbg_register() expects that the name is stored persistent.
616 * So we need this little helper function
618 static firm_dbg_module_t *dbg_register(const char *name) {
619 ident *id = new_id_from_str(name);
621 return firm_dbg_register(get_id_str(id));
625 * Sets the debug mask of module name to lvl
627 static void set_dbg_level(const char *name, unsigned lvl)
629 firm_dbg_module_t *module = dbg_register(name);
631 if (firm_dbg_get_mask(module) != lvl) {
632 firm_dbg_set_mask(module, lvl);
634 dbg_printf("Setting debug mask of module %s to %u\n", name, lvl);
636 } /* set_dbg_level */
639 * Redirects the debug output of module name to fname
641 static void set_dbg_outfile(const char *name, const char *fname)
643 firm_dbg_module_t *module = dbg_register(name);
644 FILE *f = fopen(fname, "w");
651 firm_dbg_set_file(module, f);
652 dbg_printf("Redirecting debug output of module %s to file %s\n", name, fname);
653 } /* set_dbg_outfile */
656 * Show info about a firm thing.
658 static void show_firm_object(void *firm_thing) {
661 if (firm_thing == NULL) {
662 fprintf(f, "<NULL>\n");
665 switch (get_kind(firm_thing)) {
667 fprintf(f, "BAD: (%p)\n", firm_thing);
670 dump_entity_to_file(f, firm_thing, dump_verbosity_max);
673 dump_type_to_file(f, firm_thing, dump_verbosity_max);
681 case k_ir_compound_graph_path:
687 fprintf(f, "Cannot identify thing at (%p).\n", firm_thing);
689 } /* show_firm_object */
692 * Find a firm type by its number.
694 static ir_type *find_type_nr(long nr) {
695 int i, n = get_irp_n_types();
698 for (i = 0; i < n; ++i) {
699 tp = get_irp_type(i);
700 if (get_type_nr(tp) == nr)
703 tp = get_glob_type();
704 if (get_type_nr(tp) == nr)
710 * Find a firm type by its name.
712 static ir_type *find_type_name(const char *name) {
713 int i, n = get_irp_n_types();
716 for (i = 0; i < n; ++i) {
717 tp = get_irp_type(i);
718 if (strcmp(get_type_name(tp), name) == 0)
721 tp = get_glob_type();
722 if (strcmp(get_type_name(tp), name) == 0)
725 } /* find_type_name */
727 /** The environment for the entity search functions. */
728 typedef struct find_env {
730 long nr; /**< the number that is searched for */
731 const char *name; /**< the name that is searched for */
733 ir_entity *res; /**< the result */
737 * Type-walker: Find an entity with given number.
739 static void check_ent_nr(type_or_ent *tore, void *ctx) {
740 ir_entity *ent = (ir_entity *)tore;
741 find_env_t *env = ctx;
744 if (get_entity_nr(ent) == env->u.nr) {
750 * Type-walker: Find an entity with given name.
752 static void check_ent_name(type_or_ent *tore, void *ctx) {
753 ir_entity *ent = (ir_entity *)tore;
754 find_env_t *env = ctx;
757 if (strcmp(get_entity_name(ent), env->u.name) == 0) {
760 } /* check_ent_name */
763 * Find a firm entity by its number.
765 static ir_entity *find_entity_nr(long nr) {
770 type_walk(check_ent_nr, NULL, &env);
772 } /* find_entity_nr */
775 * Find a firm entity by its name.
777 static ir_entity *find_entity_name(const char *name) {
782 type_walk(check_ent_name, NULL, &env);
784 } /* find_entity_name */
787 * Search methods for a name.
789 static void show_by_name(type_or_ent *tore, void *env) {
790 ident *id = (ident *)env;
792 if (is_entity(tore)) {
793 ir_entity *ent = (ir_entity *)tore;
795 if (is_method_entity(ent)) {
796 if (get_entity_ident(ent) == id) {
797 ir_type *owner = get_entity_owner(ent);
798 ir_graph *irg = get_entity_irg(ent);
800 if (owner != get_glob_type()) {
801 printf("%s::%s", get_type_name(owner), get_id_str(id));
803 printf("%s", get_id_str(id));
806 printf("[%ld] (%p)\n", get_irg_graph_nr(irg), irg);
815 * Search methods for a ldname.
817 static void show_by_ldname(type_or_ent *tore, void *env) {
818 ident *id = (ident *)env;
820 if (is_entity(tore)) {
821 ir_entity *ent = (ir_entity *)tore;
823 if (is_method_entity(ent)) {
824 if (get_entity_ld_ident(ent) == id) {
825 ir_type *owner = get_entity_owner(ent);
826 ir_graph *irg = get_entity_irg(ent);
828 if (owner != get_glob_type()) {
829 printf("%s::%s", get_type_name(owner), get_id_str(id));
831 printf("%s", get_id_str(id));
834 printf("[%ld] (%p)\n", get_irg_graph_nr(irg), irg);
840 } /* show_by_ldname */
843 * prints the address and graph number of all irgs with given name
845 static void irg_name(const char *name) {
846 ident *id = new_id_from_str(name);
848 type_walk(show_by_name, NULL, (void *)id);
852 * prints the address and graph number of all irgs with given ld_name
854 static void irg_ld_name(const char *name) {
855 ident *id = new_id_from_str(name);
857 type_walk(show_by_ldname, NULL, (void *)id);
885 static const char *reserved[] = {
909 static struct lexer {
910 int has_token; /**< set if a token is cached. */
911 unsigned cur_token; /**< current token. */
912 unsigned number; /**< current token attribute. */
913 const char *s; /**< current token attribute. */
914 unsigned len; /**< current token attribute. */
916 const char *curr_pos;
918 const char *tok_start;
922 * Initialize the lexer.
924 static void init_lexer(const char *input) {
926 lexer.curr_pos = input;
927 lexer.end_pos = input + strlen(input);
932 * Get the next char from the input.
934 static char next_char(void) {
935 if (lexer.curr_pos >= lexer.end_pos)
937 return *lexer.curr_pos++;
940 #define unput() if (lexer.curr_pos < lexer.end_pos) --lexer.curr_pos
943 #define MIN(a, b) (a) < (b) ? (a) : (b)
948 static unsigned get_token(void) {
952 /* skip white space */
955 } while (c != '\0' && isspace(c));
957 lexer.tok_start = lexer.curr_pos - 1;
959 /* command begins here */
965 } while (isalpha(c));
969 for (i = sizeof(reserved)/sizeof(reserved[0]) - 1; i >= 0; --i) {
970 if (strncasecmp(lexer.tok_start + 1, reserved[i], len) == 0 && reserved[i][len] == '\0')
976 } else if (isalpha(c)) {
978 lexer.s = lexer.curr_pos - 1;
982 } while (isgraph(c));
984 lexer.len = lexer.curr_pos - lexer.s;
985 return tok_identifier;
986 } else if (isdigit(c) || c == '-') {
990 /* we support negative numbers as well, so one can easily set all bits with -1 */
999 if (c == 'x' || c == 'X') {
1006 number = (number << 4) | (c - '0');
1008 number = (number << 4) | (toupper(c) - 'A' + 10);
1011 lexer.number = number;
1018 number = number * 10 + (c - '0');
1022 lexer.number = sign ? 0 - number : number;
1031 * High level function to use from debugger interface
1033 * Supported commands:
1034 * .create nr break if node nr was created
1035 * .help list all commands
1037 void firm_debug(const char *cmd) {
1038 char name[1024], fname[1024];
1046 token = get_token();
1053 token = get_token();
1054 if (token != tok_number)
1056 break_on_nr(lexer.number, BP_ON_NEW_NODE);
1060 token = get_token();
1061 if (token != tok_number)
1063 break_on_nr(lexer.number, BP_ON_REPLACE);
1067 token = get_token();
1068 if (token != tok_number)
1070 break_on_nr(lexer.number, BP_ON_LOWER);
1074 token = get_token();
1076 if (token == tok_number)
1077 break_on_nr(lexer.number, BP_ON_REMIRG);
1078 else if (token == tok_identifier) {
1079 len = MIN(lexer.len, 1023);
1080 strncpy(name, lexer.s, len);
1082 break_on_ident(name, BP_ON_REMIRG);
1088 token = get_token();
1090 if (token == tok_number)
1091 break_on_nr(lexer.number, BP_ON_NEW_ENT);
1092 else if (token == tok_identifier) {
1093 len = MIN(lexer.len, 1023);
1094 strncpy(name, lexer.s, len);
1096 break_on_ident(name, BP_ON_NEW_ENT);
1102 token = get_token();
1104 if (token == tok_number)
1105 break_on_nr(lexer.number, BP_ON_NEW_TYPE);
1106 else if (token == tok_identifier) {
1107 len = MIN(lexer.len, 1023);
1108 strncpy(name, lexer.s, len);
1110 break_on_ident(name, BP_ON_NEW_TYPE);
1116 token = get_token();
1118 if (token == tok_number)
1119 show_firm_object(find_type_nr(lexer.number));
1120 else if (token == tok_identifier) {
1121 len = MIN(lexer.len, 1023);
1122 strncpy(name, lexer.s, len);
1124 show_firm_object(find_type_name(name));
1130 token = get_token();
1132 if (token == tok_number)
1133 show_firm_object(find_entity_nr(lexer.number));
1134 else if (token == tok_identifier) {
1135 len = MIN(lexer.len, 1023);
1136 strncpy(name, lexer.s, len);
1138 show_firm_object(find_entity_name(name));
1152 token = get_token();
1153 if (token != tok_number)
1155 bp_activate(lexer.number, 1);
1159 token = get_token();
1160 if (token != tok_number)
1162 bp_activate(lexer.number, 0);
1166 token = get_token();
1167 if (token != tok_identifier)
1169 len = MIN(lexer.len, 1023);
1170 strncpy(name, lexer.s, len);
1173 token = get_token();
1174 if (token != tok_number)
1176 set_dbg_level(name, lexer.number);
1180 token = get_token();
1181 if (token != tok_identifier)
1183 len = MIN(lexer.len, 1023);
1184 strncpy(name, lexer.s, len);
1187 token = get_token();
1188 if (token != tok_number)
1190 set_dbg_level(name, (1 << lexer.number) - 1);
1193 case tok_setoutfile:
1194 token = get_token();
1195 if (token != tok_identifier)
1197 len = MIN(lexer.len, 1023);
1198 strncpy(name, lexer.s, len);
1201 token = get_token();
1202 if (token != tok_identifier)
1204 len = MIN(lexer.len, 1023);
1205 strncpy(fname, lexer.s, len);
1207 set_dbg_outfile(name, fname);
1210 token = get_token();
1211 if (token != tok_identifier)
1213 len = MIN(lexer.len, 1023);
1214 strncpy(name, lexer.s, len);
1219 token = get_token();
1220 if (token != tok_identifier)
1222 len = MIN(lexer.len, 1023);
1223 strncpy(name, lexer.s, len);
1235 printf("Error: before %s\n", lexer.tok_start);
1240 token = get_token();
1241 if (token == tok_eof)
1250 /* creates the debugger tables */
1251 void firm_init_debugger(void)
1255 bp_numbers = new_set(cmp_nr_bp, 8);
1256 bp_idents = new_set(cmp_ident_bp, 8);
1258 env = getenv("FIRMDBG");
1267 } /* firm_init_debugger */
1271 /* some picky compiler do not allow empty files */
1272 static int _firm_only_that_you_can_compile_with_NDEBUG_defined;
1277 * @page debugger The Firm debugger extension
1279 * Firm contains a debugger extension. This allows to set debugger breakpoints
1280 * an various events.
1281 * The extension uses a text interface which can be accessed from most debuggers.
1282 * More than one command can be given separated by ';'.
1284 * @section sec_cmd Supported commands
1286 * The following commands are currently supported:
1290 * Break immediately after the debugger extension was initialized.
1291 * Typically this command is used in the environment to stop the execution
1292 * of a Firm compiler right after the initialization, like this:
1294 * $export FIRMDBG=".init"
1298 * Break if a new IR-node with node number nr was created.
1299 * Typically used to find the place where wrong nodes are created.
1303 * Break before IR-node with node number nr is replaced by another node.
1307 * Break before IR-node with node number nr is lowered.
1311 * Break if the irg with graph number nr is deleted.
1315 * Break if the irg of entity name is deleted.
1319 * Break if the entity with number nr was created.
1323 * Break if the entity name was created.
1327 * Break if the type with number nr was created.
1331 * Break if the type name was created.
1335 * Show all Firm internal breakpoints.
1339 * Enables breakpoint nr.
1343 * Disables breakpoint nr.
1347 * Show the content of entity nr.
1351 * Show the content of entity name.
1355 * Show the content of type nr.
1359 * Show the content of type name.
1361 * @b .setmask name msk
1363 * Sets the debug module name to mask msk.
1365 * @b .setlvl name lvl
1367 * Sets the debug module name to level lvl.
1369 * @b .setoutfile name file
1371 * Redirects debug output of module name to file.
1375 * Prints address and graph number of a method given by its name.
1377 * @b .irgldname name
1379 * Prints address and graph number of a method given by its linker name.
1383 * List all commands.
1386 * The Firm debugger extension can be accessed using the function firm_debug().
1387 * The following example shows how to set a creation breakpoint in GDB when
1388 * node 2101 is created.
1390 * -# set FIRMDBG=".init"
1391 * -# start gdb with your compiler
1392 * -# after gdb breaks, issue
1394 * call firm_debug(".create 2101")
1396 * On the console the following text should be issued:
1398 * Firm BP 1: creation of Node 2101
1401 * @section gdb_macro GDB macro
1403 * Add the following to your .gdbinit file:
1406 # define firm "cmd" Firm debugger extension
1409 call firm_debug($arg0)
1413 * Then, all Firm debugger extension commands can be accessed in the gdb
1414 * console using the firm prefix, eg.:
1416 * firm ".create 2101"