/*
- * Copyright (C) 1995-2010 University of Karlsruhe. All right reserved.
- *
* This file is part of libFirm.
- *
- * This file may be distributed and/or modified under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation and appearing in the file LICENSE.GPL included in the
- * packaging of this file.
- *
- * Licensees holding valid libFirm Professional Edition licenses may use
- * this file in accordance with the libFirm Commercial License.
- * Agreement provided with the Software.
- *
- * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
- * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE.
+ * Copyright (C) 2012 University of Karlsruhe.
*/
/**
#include <signal.h>
#include <string.h>
#include <strings.h>
+#include <time.h>
#include <ctype.h>
* Reasons for node number breakpoints.
*/
typedef enum bp_reasons_t {
- BP_ON_NEW_NODE, /**< break if node with number is created */
+ BP_ON_NEW_THING, /**< break if node, entity or type with number is created */
BP_ON_REPLACE, /**< break if node with number is replaced */
BP_ON_LOWER, /**< break if node with number is lowered */
BP_ON_REMIRG, /**< break if an IRG is removed */
BP_ON_NEW_ENT, /**< break if a new entity is created */
- BP_ON_NEW_TYPE, /**< break if a new type is created */
BP_MAX_REASON
} bp_reasons_t;
} bp_ident_t;
/** Calculate the hash value for an ident breakpoint. */
-#define HASH_IDENT_BP(key) (HASH_PTR((key).id) ^ (key).bp.reason)
+#define HASH_IDENT_BP(key) (hash_ptr((key).id) ^ (key).bp.reason)
/** The set containing the breakpoints on node numbers. */
static set *bp_numbers;
int firm_debug_active(void)
{
return is_active;
-} /* firm_debug_active */
+}
/**
* Reset the debug text buffer.
static void reset_dbg_buf(void)
{
firm_dbg_msg_buf[0] = '\0';
-} /* reset_dbg_buf */
-
-static void add_to_dbg_buf(const char *buf)
-{
- strncat(firm_dbg_msg_buf, buf, sizeof(firm_dbg_msg_buf));
-} /* add_to_dbg_buf */
+}
const char *firm_debug_text(void)
{
firm_dbg_msg_buf[sizeof(firm_dbg_msg_buf) - 1] = '\0';
return firm_dbg_msg_buf;
-} /* firm_debug_text */
+}
/**
* debug output
*/
static void dbg_printf(const char *fmt, ...)
{
- char buf[1024];
-
- va_list args;
- va_start(args, fmt);
-
if (fmt[0] != '+')
reset_dbg_buf();
else
++fmt;
- ir_vsnprintf(buf, sizeof(buf), fmt, args);
+ va_list args;
+ va_start(args, fmt);
+ if (redir_output) {
+ size_t const cur = strlen(firm_dbg_msg_buf);
+ ir_vsnprintf(firm_dbg_msg_buf + cur, sizeof(firm_dbg_msg_buf) - cur, fmt, args);
+ } else {
+ ir_vprintf(fmt, args);
+ }
va_end(args);
-
- if (redir_output)
- add_to_dbg_buf(buf);
- else
- puts(buf);
-} /* dbg_printf */
+}
/**
* A new node is created.
(void) irg;
key.nr = get_irn_node_nr(node);
- key.bp.reason = BP_ON_NEW_NODE;
+ key.bp.reason = BP_ON_NEW_THING;
- elem = (bp_nr_t*)set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
+ elem = set_find(bp_nr_t, bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
if (elem && elem->bp.active) {
dbg_printf("Firm BP %u reached, %+F created\n", elem->bp.bpnr, node);
firm_debug_break();
}
-} /* dbg_new_node */
+}
/**
* A node is replaced.
key.nr = get_irn_node_nr(old);
key.bp.reason = BP_ON_REPLACE;
- elem = (bp_nr_t*)set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
+ elem = set_find(bp_nr_t, bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
if (elem && elem->bp.active) {
dbg_printf("Firm BP %u reached, %+F will be replaced by %+F\n", elem->bp.bpnr, old, nw);
firm_debug_break();
}
-} /* dbg_replace */
+}
/**
* A new node is lowered.
key.nr = get_irn_node_nr(node);
key.bp.reason = BP_ON_LOWER;
- elem = (bp_nr_t*)set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
+ elem = set_find(bp_nr_t, bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
if (elem && elem->bp.active) {
dbg_printf("Firm BP %u reached, %+F will be lowered\n", elem->bp.bpnr, node);
firm_debug_break();
}
-} /* dbg_lower */
+}
/**
* A graph will be deleted.
key.nr = get_irg_graph_nr(irg);
key.bp.reason = BP_ON_REMIRG;
- elem = (bp_nr_t*)set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
+ elem = set_find(bp_nr_t, bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
if (elem && elem->bp.active) {
ir_printf("Firm BP %u reached, %+F will be deleted\n", elem->bp.bpnr, irg);
firm_debug_break();
key.id = get_entity_ident(ent);
key.bp.reason = BP_ON_REMIRG;
- elem = (bp_ident_t*)set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
+ elem = set_find(bp_ident_t, bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
if (elem && elem->bp.active) {
dbg_printf("Firm BP %u reached, %+F will be deleted\n", elem->bp.bpnr, ent);
firm_debug_break();
}
}
-} /* dbg_free_graph */
+}
/**
* An entity was created.
key.id = get_entity_ident(ent);
key.bp.reason = BP_ON_NEW_ENT;
- elem = (bp_ident_t*)set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
+ elem = set_find(bp_ident_t, bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
if (elem && elem->bp.active) {
ir_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, ent);
firm_debug_break();
bp_nr_t key, *elem;
key.nr = get_entity_nr(ent);
- key.bp.reason = BP_ON_NEW_ENT;
+ key.bp.reason = BP_ON_NEW_THING;
- elem = (bp_nr_t*)set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
+ elem = set_find(bp_nr_t, bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
if (elem && elem->bp.active) {
dbg_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, ent);
firm_debug_break();
}
}
-} /* dbg_new_entity */
+}
/**
* A type was created.
bp_nr_t key, *elem;
key.nr = get_type_nr(tp);
- key.bp.reason = BP_ON_NEW_TYPE;
+ key.bp.reason = BP_ON_NEW_THING;
- elem = (bp_nr_t*)set_find(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
+ elem = set_find(bp_nr_t, bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
if (elem && elem->bp.active) {
ir_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, tp);
firm_debug_break();
}
}
-} /* dbg_new_type */
+}
/**
* Return the reason string.
static const char *reason_str(bp_reasons_t reason)
{
switch (reason) {
- case BP_ON_NEW_NODE: return "node creation";
- case BP_ON_REPLACE: return "node replace";
- case BP_ON_LOWER: return "node lowering";
- case BP_ON_REMIRG: return "removing IRG";
- case BP_ON_NEW_ENT: return "entity creation";
- case BP_ON_NEW_TYPE: return "type creation";
- case BP_MAX_REASON: break;
+ case BP_ON_NEW_THING: return "node, entity or type creation";
+ case BP_ON_REPLACE: return "node replace";
+ case BP_ON_LOWER: return "node lowering";
+ case BP_ON_REMIRG: return "removing IRG";
+ case BP_ON_NEW_ENT: return "entity creation";
+ case BP_MAX_REASON: break;
}
panic("unsupported reason");
-} /* reason_str */
+}
/**
* Compare two number breakpoints.
(void) size;
return (e1->nr - e2->nr) | (e1->bp.reason - e2->bp.reason);
-} /* cmp_nr_bp */
+}
/**
* Compare two ident breakpoints.
(void) size;
return (e1->id != e2->id) | (e1->bp.reason - e2->bp.reason);
-} /* cmp_ident_bp */
+}
/**
* Update the hooks.
*/
static void update_hooks(breakpoint *bp)
{
-#define CASE_ON(a, b) case a: if (! IS_HOOKED(hook_##b)) HOOK(hook_##b, dbg_##b); break
-#define CASE_OFF(a, b) case a: if (IS_HOOKED(hook_##b)) UNHOOK(hook_##b); break
+#define CASE_ON(a, hook, handler) case a: if (! IS_HOOKED(hook)) HOOK(hook, handler); break
+#define CASE_OFF(a, hook) case a: if (IS_HOOKED(hook)) UNHOOK(hook); break
if (bp->active)
++num_active_bp[bp->reason];
if (num_active_bp[bp->reason] > 0) {
/* register the hooks on demand */
switch (bp->reason) {
- CASE_ON(BP_ON_NEW_NODE, new_node);
- CASE_ON(BP_ON_REPLACE, replace);
- CASE_ON(BP_ON_LOWER, lower);
- CASE_ON(BP_ON_REMIRG, free_graph);
- CASE_ON(BP_ON_NEW_ENT, new_entity);
- CASE_ON(BP_ON_NEW_TYPE, new_type);
+ CASE_ON(BP_ON_REPLACE, hook_replace, dbg_replace);
+ CASE_ON(BP_ON_LOWER, hook_lower, dbg_lower);
+ CASE_ON(BP_ON_REMIRG, hook_free_graph, dbg_free_graph);
+ CASE_ON(BP_ON_NEW_ENT, hook_new_entity, dbg_new_entity);
+ case BP_ON_NEW_THING:
+ if (!IS_HOOKED(hook_new_node))
+ HOOK(hook_new_node, dbg_new_node);
+ if (!IS_HOOKED(hook_new_type))
+ HOOK(hook_new_type, dbg_new_type);
+ if (!IS_HOOKED(hook_new_entity))
+ HOOK(hook_new_entity, dbg_new_entity);
+ break;
default:
break;
}
else {
/* unregister the hook on demand */
switch (bp->reason) {
- CASE_OFF(BP_ON_NEW_NODE, new_node);
- CASE_OFF(BP_ON_REPLACE, replace);
- CASE_OFF(BP_ON_LOWER, lower);
- CASE_OFF(BP_ON_REMIRG, free_graph);
- CASE_OFF(BP_ON_NEW_ENT, new_entity);
- CASE_OFF(BP_ON_NEW_TYPE, new_type);
+ CASE_OFF(BP_ON_REPLACE, hook_replace);
+ CASE_OFF(BP_ON_LOWER, hook_lower);
+ CASE_OFF(BP_ON_REMIRG, hook_free_graph);
+ CASE_OFF(BP_ON_NEW_ENT, hook_new_entity);
+ case BP_ON_NEW_THING:
+ if (IS_HOOKED(hook_new_node))
+ UNHOOK(hook_new_node);
+ if (IS_HOOKED(hook_new_type))
+ UNHOOK(hook_new_type);
+ if (IS_HOOKED(hook_new_entity))
+ UNHOOK(hook_new_entity);
+ break;
default:
break;
}
}
#undef CASE_ON
#undef CASE_OFF
-} /* update_hooks */
+}
/**
* Break if nr is reached.
key.bp.reason = reason;
key.nr = nr;
- elem = (bp_nr_t*)set_insert(bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
+ elem = set_insert(bp_nr_t, bp_numbers, &key, sizeof(key), HASH_NR_BP(key));
if (elem->bp.bpnr == 0) {
/* new break point */
update_hooks(&elem->bp);
}
-} /* break_on_nr */
+}
/**
* Break if ident name is reached.
key.bp.reason = reason;
key.id = new_id_from_str(name);
- elem = (bp_ident_t*)set_insert(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
+ elem = set_insert(bp_ident_t, bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
if (elem->bp.bpnr == 0) {
/* new break point */
update_hooks(&elem->bp);
}
-} /* break_on_ident */
+}
/**
* Sets/resets the active flag of breakpoint bp.
}
}
dbg_printf("Error: Firm BP %u not exists.\n", bp);
-} /* bp_activate */
+}
/**
*/
static void show_commands(void)
{
- dbg_printf("Internal Firm debugger extension $Revision$ commands:\n"
+ dbg_printf("Internal Firm debugger extension commands:\n"
"init break after initialization\n"
"create nr break if node nr was created\n"
"replace nr break if node nr is replaced by another node\n"
"setoutfile name file redirects debug output of module name to file\n"
"irgname name prints address and graph number of a method given by its name\n"
"irgldname ldname prints address and graph number of a method given by its ldname\n"
+ "initialnodenr n|rand set initial node number to n or random number\n"
"help list all commands\n"
);
-} /* show_commands */
+}
/**
* Shows all Firm breakpoints.
dbg_printf(p->active ? "+enabled" : "+disabled");
}
dbg_printf(have_one ? "+\n" : "+ NONE\n");
-} /* show_bp */
+}
/**
* firm_dbg_register() expects that the name is stored persistent.
ident *id = new_id_from_str(name);
return firm_dbg_register(get_id_str(id));
-} /* dbg_register */
+}
/**
* Sets the debug mask of module name to lvl
dbg_printf("Setting debug mask of module %s to %u\n", name, lvl);
}
-} /* set_dbg_level */
+}
/**
* Redirects the debug output of module name to fname
firm_dbg_set_file(module, f);
dbg_printf("Redirecting debug output of module %s to file %s\n", name, fname);
-} /* set_dbg_outfile */
+}
/**
* Show info about a firm thing.
case k_ir_op:
case k_tarval:
case k_ir_loop:
- case k_ir_compound_graph_path:
- case k_ir_extblk:
case k_ir_prog:
fprintf(f, "NIY\n");
break;
default:
fprintf(f, "Cannot identify thing at (%p).\n", firm_thing);
}
-} /* show_firm_object */
+}
/**
* Find a firm type by its number.
if (get_type_nr(tp) == nr)
return tp;
return NULL;
-} /* find_type_nr */
+}
/**
* Find a firm type by its name.
if (strcmp(get_compound_name(tp), name) == 0)
return tp;
return NULL;
-} /* find_type_name */
+}
/** The environment for the entity search functions. */
typedef struct find_env {
env->res = tore.ent;
}
}
-} /* check_ent_nr */
+}
/**
* Type-walker: Find an entity with given name.
if (strcmp(get_entity_name(tore.ent), env->u.name) == 0) {
env->res = tore.ent;
}
-} /* check_ent_name */
+}
/**
* Find a firm entity by its number.
env.res = NULL;
type_walk(check_ent_nr, NULL, &env);
return env.res;
-} /* find_entity_nr */
+}
/**
* Find a firm entity by its name.
env.res = NULL;
type_walk(check_ent_name, NULL, &env);
return env.res;
-} /* find_entity_name */
+}
/**
* Search methods for a name.
}
}
}
-} /* show_by_name */
+}
/**
* Search methods for a ldname.
}
}
}
-} /* show_by_ldname */
+}
/**
* prints the address and graph number of all irgs with given name
ident *id = new_id_from_str(name);
type_walk(show_by_name, NULL, (void *)id);
-} /* irg_name */
+}
/**
* prints the address and graph number of all irgs with given ld_name
ident *id = new_id_from_str(name);
type_walk(show_by_ldname, NULL, (void *)id);
-} /* irg_ld_name */
+}
enum tokens {
- tok_create = 256,
- tok_replace,
+ first_token = 256,
+ tok_bp = first_token,
+ tok_create,
+ tok_disable,
+ tok_dumpfilter,
+ tok_enable,
+ tok_help,
+ tok_init,
+ tok_irgldname,
+ tok_irgname,
tok_lower,
- tok_remirg,
tok_newent,
- tok_newtype,
- tok_showtype,
- tok_showent,
- tok_init,
- tok_bp,
- tok_enable,
- tok_disable,
- tok_setmask,
+ tok_remirg,
+ tok_replace,
tok_setlvl,
+ tok_setmask,
tok_setoutfile,
- tok_irgname,
- tok_irgldname,
- tok_help,
+ tok_showent,
+ tok_showtype,
+ tok_initialnodenr,
tok_identifier,
tok_number,
tok_eof,
};
static const char *reserved[] = {
+ "bp",
"create",
- "replace",
+ "disable",
+ "dumpfilter",
+ "enable",
+ "help",
+ "init",
+ "irgldname",
+ "irgname",
"lower",
- "remirg",
"newent",
- "newtype",
- "showtype",
- "showent",
- "init",
- "bp",
- "enable",
- "disable",
- "setmask",
+ "remirg",
+ "replace",
"setlvl",
+ "setmask",
"setoutfile",
- "irgname",
- "irgldname",
- "help"
+ "showent",
+ "showtype",
+ "initialnodenr",
};
/**
lexer.has_token = 0;
lexer.curr_pos = input;
lexer.end_pos = input + strlen(input);
-} /* init_lexer */
+}
/**
if (lexer.curr_pos >= lexer.end_pos)
return '\0';
return *lexer.curr_pos++;
-} /* next_char */
+}
#define unput() if (lexer.curr_pos < lexer.end_pos) --lexer.curr_pos
}
for (i = ARRAY_SIZE(reserved); i-- != 0;) {
if (strncasecmp(tok_start, reserved[i], len) == 0 && reserved[i][len] == '\0')
- return 256 + i;
+ return first_token + i;
}
/* identifier */
else if (c == '\0')
return tok_eof;
return c;
-} /* get_token */
+}
void firm_debug(const char *cmd)
{
token = get_token();
if (token != tok_number)
goto error;
- break_on_nr(lexer.number, BP_ON_NEW_NODE);
+ break_on_nr(lexer.number, BP_ON_NEW_THING);
break;
case tok_replace:
token = get_token();
if (token == tok_number)
- break_on_nr(lexer.number, BP_ON_NEW_ENT);
+ break_on_nr(lexer.number, BP_ON_NEW_THING);
else if (token == tok_identifier) {
len = MIN(lexer.len, 1023);
strncpy(name, lexer.s, len);
goto error;
break;
- case tok_newtype:
- token = get_token();
-
- if (token == tok_number)
- break_on_nr(lexer.number, BP_ON_NEW_TYPE);
- else if (token == tok_identifier) {
- len = MIN(lexer.len, 1023);
- strncpy(name, lexer.s, len);
- name[len] = '\0';
- break_on_ident(name, BP_ON_NEW_TYPE);
- } else
- goto error;
- break;
-
case tok_showtype:
token = get_token();
irg_name(name);
break;
+ case tok_initialnodenr:
+ token = get_token();
+ if (token == tok_number) {
+ dbg_printf("Setting initial node number to %u\n", lexer.number);
+ irp->max_node_nr = lexer.number;
+ } else if (token == tok_identifier && !strcmp(lexer.s, "rand")) {
+ dbg_printf("Randomizing initial node number\n");
+ srand(time(0));
+ irp->max_node_nr += rand() % 6666;
+ } else
+ goto error;
+ break;
+
case tok_irgldname:
token = get_token();
if (token != tok_identifier)
irg_ld_name(name);
break;
+ case tok_dumpfilter:
+ token = get_token();
+ if (token != tok_identifier)
+ goto error;
+ len = MIN(lexer.len, 1023);
+ strncpy(name, lexer.s, len);
+ name[len] = '\0';
+ ir_set_dump_filter(name);
+ break;
+
case tok_help:
show_commands();
break;
}
leave:
;
-} /* firm_debug */
+}
void firm_init_debugger(void)
{
if (break_on_init)
firm_debug_break();
-} /* firm_init_debugger */
+}
+
+void firm_finish_debugger(void)
+{
+ del_set(bp_numbers);
+ del_set(bp_idents);
+}
/**
* A gdb helper function to print firm objects.
char *b = buf;
size_t l;
size_t len = sizeof(buf);
- const ir_edge_t *edge;
foreach_out_edge(node, edge) {
ir_node *n = get_edge_src_irn(edge);