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_LOWER = 2 /**< break if node with number is lowered */
78 /** A node number breakpoint. */
80 breakpoint bp; /**< the breakpoint data */
81 long nr; /**< the node number */
82 bp_reasons_t reason; /**< reason for the breakpoint */
85 /** The set containing the breakpoints on node numbers. */
86 static set *bp_node_numbers;
88 /**< the list of all breakpoints */
89 static breakpoint *bp_list;
91 /** number of the current break point */
92 static unsigned bp_num = 0;
94 /** set if break on init command was issued. */
95 static int break_on_init = 0;
98 * return the reason string.
100 static const char *reason_str(bp_reasons_t reason)
103 case BP_ON_CREATION: return "creation";
104 case BP_ON_LOWER: return "lowering";
110 #define HASH_NODE_BP(key) (((key).nr << 2) ^ (key).reason)
113 * Compare two node number breakpoints
115 static int cmp_node_bp(const void *elt, const void *key, size_t size)
117 const bp_node_t *e1 = elt;
118 const bp_node_t *e2 = key;
120 return (e1->nr - e2->nr) | (e1->reason - e2->reason);
124 * Break if node nr is reached.
126 static void break_on_node(long nr, bp_reasons_t reason)
128 bp_node_t key, *elem;
130 key.bp.kind = BP_NODE;
136 elem = set_insert(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
138 if (elem->bp.bpnr == 0) {
139 /* new break point */
140 elem->bp.bpnr = ++bp_num;
141 elem->bp.next = bp_list;
144 printf("Firm BP %u: %s of Node %ld\n", elem->bp.bpnr, reason_str(reason), nr);
149 * Sets/resets the active flag of breakpoint bp.
151 static void bp_activate(unsigned bp, int active)
155 for (p = bp_list; p; p = p->next) {
159 printf("Firm BP %u is now %s\n", bp, active ? "enabled" : "disabled");
163 printf("Error: Firm BP %u not exists.\n", bp);
168 * Show a list of supported commands
170 static void show_commands(void) {
171 printf("Internal Firm debugger extension commands:\n"
172 ".init break after initialization\n"
173 ".create nr break if node nr was created\n"
174 ".lower nr break before node nr is lowered\n"
175 ".bp show all breakpoints\n"
176 ".enable nr enable breakpoint nr\n"
177 ".disable nr disable breakpoint nr\n"
178 ".help list all commands\n"
183 * Shows all Firm breakpoints.
185 static void show_bp(void) {
189 for (p = bp_list; p; p = p->next) {
190 printf("Firm BP %u: ", p->bpnr);
194 node_p = (bp_node_t *)p;
195 printf("%s of node %ld ", reason_str(node_p->reason), node_p->nr);
199 printf(p->active ? "enabled\n" : "disabled\n");
204 * High level function to use from debugger interface
206 * Supported commands:
207 * .create nr break if node nr was created
208 * .help list all commands
210 void firm_break(const char *cmd) {
214 while (isspace(*cmd)) ++cmd;
216 if (sscanf(cmd, ".create %ld\n", &nr) == 1) {
217 break_on_node(nr, BP_ON_CREATION);
219 else if (sscanf(cmd, ".lower %ld\n", &nr) == 1) {
220 break_on_node(nr, BP_ON_LOWER);
222 else if (strcmp(cmd, ".init") == 0)
224 else if (strcmp(cmd, ".bp") == 0)
226 else if (sscanf(cmd, ".enable %u", &bp) == 1)
228 else if (sscanf(cmd, ".disable %u", &bp) == 1)
235 /** the hook entries for the Firm debugger module */
236 static hook_entry_t debugger_hooks[hook_last];
239 * A new node is created.
241 * @param ctx the hook context
242 * @param irg the IR graph on which the node is created
243 * @param node the new IR node that was created
245 static void dbg_new_node(void *ctx, ir_graph *irg, ir_node *node)
247 bp_node_t key, *elem;
249 key.nr = get_irn_node_nr(node);
250 key.reason = BP_ON_CREATION;
252 elem = set_find(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
253 if (elem && elem->bp.active) {
254 ir_printf("Firm BP %u reached, %+F created\n", elem->bp.bpnr, node);
260 * A new node is lowered.
262 * @param ctx the hook context
263 * @param node the new IR node that will be lowered
265 static void dbg_lower_node(void *ctx, ir_node *node)
267 bp_node_t key, *elem;
269 key.nr = get_irn_node_nr(node);
270 key.reason = BP_ON_LOWER;
272 elem = set_find(bp_node_numbers, &key, sizeof(key), HASH_NODE_BP(key));
273 if (elem && elem->bp.active) {
274 ir_printf("Firm BP %u reached, %+F will be lowered\n", elem->bp.bpnr, node);
279 #define HOOK(h, fkt) \
280 debugger_hooks[h].hook._##h = fkt; register_hook(h, &debugger_hooks[h])
282 /* creates the debugger tables */
283 void firm_init_debugger(void)
287 bp_node_numbers = new_set(cmp_node_bp, 8);
289 /* register the hooks */
290 HOOK(hook_new_node, dbg_new_node);
291 HOOK(hook_lower, dbg_lower_node);
293 env = getenv("FIRMDBG");
305 * @page debugger The Firm debugger extension.
307 * Firm contains a debugger extension. This allows to set debugger breakpoints
309 * The extension uses a text interface which can be access in the debugger.
311 * The following commands are currently supported:
315 * Break immediately after the debugger extension was initialized.
316 * Typically this command is used in the environment to stop the execution
317 * of a Firm compiler right after the initialization, like this:
319 * $export FIRMDBG=".init"
324 * Break if a new IR-node with node number nr was created.
325 * Typically used to find the place where wrong nodes are created.
329 * Break before IR-node with node number nr is lowered.
333 * Show all Firm internal breakpoints.
337 * Enables breakpoint nr.
341 * Disables breakpoint nr.
348 * The Firm debugger extension is access using the function firm_break().
349 * The following example shows how to set a creating breakpoint in GDB when
350 * node 2101 is created.
352 * 1.) set FRIMDBG=".init"
353 * 2.) start gdb with your compiler
354 * 3.) after gdb breaks, issue
356 * p firm_debug(".create 2101")
358 * On the console the following text should be issued:
360 * Firm BP 1: creation of Node 2101