* Modified by:
* Created: 2005
* CVS-ID: $Id$
- * Copyright: (c) 2001-2005 Universität Karlsruhe
+ * Copyright: (c) 2001-2006 Universität Karlsruhe
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#ifndef NDEBUG
+#ifdef DEBUG_libfirm
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include "irgraph_t.h"
#include "entity_t.h"
#include "irprintf.h"
+#include "typewalk.h"
+#include "irdump.h"
#include "debug.h"
#ifdef _WIN32
-/** Break into the debugger. The Win32 way. */
-static void firm_debug_break(void) {
+/* Break into the debugger. The Win32 way. */
+void firm_debug_break(void) {
DebugBreak();
}
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64))
-/** Break into the debugger. The ia32/x86_64 way under GCC. */
-static void firm_debug_break(void) {
+/* Break into the debugger. The ia32/x86_64 way under GCC. */
+void firm_debug_break(void) {
__asm__ __volatile__("int3");
}
#else
-/** Break into the debugger. Poor Unix way. */
-static void firm_debug_break(void) {
+/* Break into the debugger. Poor Unix way. */
+void firm_debug_break(void) {
raise(SIGINT);
}
#endif /* _WIN32 */
/** supported breakpoint kinds */
typedef enum {
- BP_NR = 'n', /**< break on node number. */
+ BP_NR = 'n', /**< break on node number. */
BP_IDENT = 'i' /**< break on ident. */
} bp_kind;
long nr; /**< the node number */
} bp_nr_t;
-/** calculate the hash value for a node breakpoint */
+/** Calculate the hash value for a node breakpoint. */
#define HASH_NR_BP(key) (((key).nr << 2) ^ (key).bp.reason)
-/** A ident breakpoint. */
+/** An ident breakpoint. */
typedef struct {
breakpoint bp; /**< the breakpoint data */
ident *id; /**< the ident */
} bp_ident_t;
-/** calculate the hash value for an ident breakpoint */
+/** Calculate the hash value for an ident breakpoint. */
#define HASH_IDENT_BP(key) (HASH_PTR((key).id) ^ (key).bp.reason)
/** The set containing the breakpoints on node numbers. */
/** hook the hook h with function fkt. */
#define HOOK(h, fkt) \
- debugger_hooks[h].hook._##h = fkt; register_hook(h, &debugger_hooks[h])
+do { \
+ debugger_hooks[h].hook._##h = fkt; \
+ register_hook(h, &debugger_hooks[h]); \
+} while(0)
/** unhook the hook h */
-#define UNHOOK(h) unregister_hook(h, &debugger_hooks[h])
+#define UNHOOK(h) \
+do { \
+ unregister_hook(h, &debugger_hooks[h]); \
+ debugger_hooks[h].hook._##h = NULL; \
+} while(0)
/** returns non-zero if a entry hook h is used */
-#define IS_HOOKED(h) (debugger_hooks[h].next != NULL)
+#define IS_HOOKED(h) (debugger_hooks[h].hook._##h != NULL)
/* some macros needed to create the info string */
#define _DBG_VERSION(major, minor) #major "." #minor
*/
int firm_debug_active(void) {
return is_active;
-}
+} /* firm_debug_active */
/**
- * reset the debug text buffer
+ * Reset the debug text buffer.
*/
static void reset_dbg_buf(void) {
firm_dbg_msg_buf[0] = '\0';
-}
+} /* reset_dbg_buf */
/**
- * Add text to the debug text buffer
+ * Add text to the debug text buffer.
*/
static void add_to_dbg_buf(const char *buf) {
strncat(firm_dbg_msg_buf, buf, sizeof(firm_dbg_msg_buf));
-}
+} /* add_to_dbg_buf */
/**
* Return the content of the debug text buffer.
* To be called from the debugger.
*/
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
add_to_dbg_buf(buf);
else
puts(buf);
-}
+} /* dbg_printf */
/**
* A new node is created.
dbg_printf("Firm BP %u reached, %+F created\n", elem->bp.bpnr, node);
firm_debug_break();
}
-}
+} /* dbg_new_node */
/**
* A node is replaced.
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.
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.
firm_debug_break();
}
}
-}
+} /* dbg_free_graph */
/**
* An entity was created.
firm_debug_break();
}
}
-}
+} /* dbg_new_entity */
/**
* A type was created.
* @param ctx the hook context
* @param tp the newly created type
*/
-static void dbg_new_type(void *ctx, type *tp)
+static void dbg_new_type(void *ctx, ir_type *tp)
{
{
bp_nr_t key, *elem;
firm_debug_break();
}
}
-}
+} /* dbg_new_type */
/**
- * return the reason string.
+ * Return the reason string.
*/
static const char *reason_str(bp_reasons_t reason)
{
default: assert(0);
}
return "unknown";
-}
+} /* reason_str */
/**
- * Compare two number breakpoints
+ * Compare two number breakpoints.
*/
static int cmp_nr_bp(const void *elt, const void *key, size_t size)
{
const bp_nr_t *e2 = key;
return (e1->nr - e2->nr) | (e1->bp.reason - e2->bp.reason);
-}
+} /* cmp_nr_bp */
/**
- * Compare two ident breakpoints
+ * Compare two ident breakpoints.
*/
static int cmp_ident_bp(const void *elt, const void *key, size_t size)
{
const bp_ident_t *e2 = key;
return (e1->id != e2->id) | (e1->bp.reason - e2->bp.reason);
-}
+} /* cmp_ident_bp */
/**
- * update the hooks
+ * Update the hooks.
*/
static void update_hooks(breakpoint *bp)
{
}
#undef CASE_ON
#undef CASE_OFF
-}
+} /* update_hooks */
/**
* Break if nr is reached.
update_hooks(&elem->bp);
}
-}
+} /* break_on_nr */
/**
* Break if ident name is reached.
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 */
/**
".bp show all breakpoints\n"
".enable nr enable breakpoint nr\n"
".disable nr disable breakpoint nr\n"
- ".setmask name lvl sets the debug module name to level lvl\n"
+ ".showtype nr|name show content of the type nr or name\n"
+ ".showent nr|name show content of the entity nr or name\n"
+ ".setmask name msk sets the debug module name to mask msk\n"
+ ".setlvl name lvl sets the debug module name to level lvl\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"
".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
{
firm_dbg_module_t *module = dbg_register(name);
- firm_dbg_set_mask(module, lvl);
+ if (firm_dbg_get_mask(module) != lvl) {
+ firm_dbg_set_mask(module, lvl);
- dbg_printf("Setting debug mask of module %s to %u\n", name, 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.
+ */
+static void show_firm_object(void *firm_thing) {
+ FILE *f = stdout;
+
+ if (firm_thing == NULL) {
+ fprintf(f, "<NULL>\n");
+ return;
+ }
+ switch (get_kind(firm_thing)) {
+ case k_BAD:
+ fprintf(f, "BAD: (%p)\n", firm_thing);
+ break;
+ case k_entity:
+ dump_entity_to_file(f, firm_thing, dump_verbosity_max);
+ break;
+ case k_type:
+ dump_type_to_file(f, firm_thing, dump_verbosity_max);
+ break;
+ case k_ir_graph:
+ case k_ir_node:
+ case k_ir_mode:
+ 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.
+ */
+static ir_type *find_type_nr(long nr) {
+ int i, n = get_irp_n_types();
+ ir_type *tp;
+
+ for (i = 0; i < n; ++i) {
+ tp = get_irp_type(i);
+ if (get_type_nr(tp) == nr)
+ return tp;
+ }
+ tp = get_glob_type();
+ if (get_type_nr(tp) == nr)
+ return tp;
+ return NULL;
+} /* find_type_nr */
+
+/**
+ * Find a firm type by its name.
+ */
+static ir_type *find_type_name(const char *name) {
+ int i, n = get_irp_n_types();
+ ir_type *tp;
+
+ for (i = 0; i < n; ++i) {
+ tp = get_irp_type(i);
+ if (strcmp(get_type_name(tp), name) == 0)
+ return tp;
+ }
+ tp = get_glob_type();
+ if (strcmp(get_type_name(tp), name) == 0)
+ return tp;
+ return NULL;
+} /* find_type_name */
+
+/** The environment for the entity search functions. */
+typedef struct find_env {
+ union {
+ long nr; /**< the number that is searched for */
+ const char *name; /**< the name that is searched for */
+ } u;
+ entity *res; /**< the result */
+} find_env_t;
+
+/**
+ * Type-walker: Find an entity with given number.
+ */
+static void check_ent_nr(type_or_ent *tore, void *ctx) {
+ entity *ent = (entity *)tore;
+ find_env_t *env = ctx;
+
+ if (is_entity(ent))
+ if (get_entity_nr(ent) == env->u.nr) {
+ env->res = ent;
+ }
+} /* check_ent_nr */
+
+/**
+ * Type-walker: Find an entity with given name.
+ */
+static void check_ent_name(type_or_ent *tore, void *ctx) {
+ entity *ent = (entity *)tore;
+ find_env_t *env = ctx;
+
+ if (is_entity(ent))
+ if (strcmp(get_entity_name(ent), env->u.name) == 0) {
+ env->res = ent;
+ }
+} /* check_ent_name */
+
+/**
+ * Find a firm entity by its number.
+ */
+static entity *find_entity_nr(long nr) {
+ find_env_t env;
+
+ env.u.nr = nr;
+ env.res = NULL;
+ type_walk(check_ent_nr, NULL, &env);
+ return env.res;
+} /* find_entity_nr */
+
+/**
+ * Find a firm entity by its name.
+ */
+static entity *find_entity_name(const char *name) {
+ find_env_t env;
+
+ env.u.name = name;
+ env.res = NULL;
+ type_walk(check_ent_name, NULL, &env);
+ return env.res;
+} /* find_entity_name */
+
+/**
+ * Search methods for a name.
+ */
+static void show_by_name(type_or_ent *tore, void *env) {
+ ident *id = (ident *)env;
+
+ if (is_entity(tore)) {
+ entity *ent = (entity *)tore;
+
+ if (is_method_entity(ent)) {
+ if (get_entity_ident(ent) == id) {
+ ir_type *owner = get_entity_owner(ent);
+ ir_graph *irg = get_entity_irg(ent);
+
+ if (owner != get_glob_type()) {
+ printf("%s::%s", get_type_name(owner), get_id_str(id));
+ } else {
+ printf("%s", get_id_str(id));
+ }
+ if (irg)
+ printf("[%ld] (%p)\n", get_irg_graph_nr(irg), irg);
+ else
+ printf(" NULL\n");
+ }
+ }
+ }
+} /* show_by_name */
+
+/**
+ * Search methods for a ldname.
+ */
+static void show_by_ldname(type_or_ent *tore, void *env) {
+ ident *id = (ident *)env;
+
+ if (is_entity(tore)) {
+ entity *ent = (entity *)tore;
+
+ if (is_method_entity(ent)) {
+ if (get_entity_ld_ident(ent) == id) {
+ ir_type *owner = get_entity_owner(ent);
+ ir_graph *irg = get_entity_irg(ent);
+
+ if (owner != get_glob_type()) {
+ printf("%s::%s", get_type_name(owner), get_id_str(id));
+ } else {
+ printf("%s", get_id_str(id));
+ }
+ if (irg)
+ printf("[%ld] (%p)\n", get_irg_graph_nr(irg), irg);
+ else
+ printf(" NULL\n");
+ }
+ }
+ }
+} /* show_by_ldname */
+
+/**
+ * prints the address and graph number of all irgs with given name
+ */
+static void irg_name(const char *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
+ */
+static void irg_ld_name(const char *name) {
+ ident *id = new_id_from_str(name);
+
+ type_walk(show_by_ldname, NULL, (void *)id);
+} /* irg_ld_name */
/**
* High level function to use from debugger interface
else if (sscanf(cmd, ".newtype %s\n", name) == 1) {
break_on_ident(name, BP_ON_NEW_TYPE);
}
+ else if (sscanf(cmd, ".showtype %ld\n", &nr) == 1) {
+ show_firm_object(find_type_nr(nr));
+ }
+ else if (sscanf(cmd, ".showtype %s\n", name) == 1) {
+ show_firm_object(find_type_name(name));
+ }
+ else if (sscanf(cmd, ".showent %ld\n", &nr) == 1) {
+ show_firm_object(find_entity_nr(nr));
+ }
+ else if (sscanf(cmd, ".showent %s\n", name) == 1) {
+ show_firm_object(find_entity_name(name));
+ }
else if (strcmp(cmd, ".init") == 0)
break_on_init = 1;
else if (strcmp(cmd, ".bp") == 0)
bp_activate(bp, 0);
else if (sscanf(cmd, ".setmask %s %u\n", name, &lvl) == 2)
set_dbg_level(name, lvl);
+ else if (sscanf(cmd, ".setlvl %s %u\n", name, &lvl) == 2)
+ set_dbg_level(name, (1 << lvl) - 1);
else if (sscanf(cmd, ".setoutfile %s %s\n", name, fname) == 2)
set_dbg_outfile(name, fname);
+ else if (sscanf(cmd, ".irgname %s\n", name) == 1)
+ irg_name(name);
+ else if (sscanf(cmd, ".irgldname %s\n", name) == 1)
+ irg_ld_name(name);
else {
show_commands();
}
-}
+} /* firm_debug */
/* creates the debugger tables */
void firm_init_debugger(void)
char *env;
bp_numbers = new_set(cmp_nr_bp, 8);
- bp_idents = new_set(cmp_ident_bp, 8);
+ bp_idents = new_set(cmp_ident_bp, 8);
env = getenv("FIRMDBG");
if (break_on_init)
firm_debug_break();
-}
+} /* firm_init_debugger */
#else
* @section sec_cmd Supported commands
*
* The following commands are currently supported:
+ *
* @b .init
*
* Break immediately after the debugger extension was initialized.
*
* $export FIRMDBG=".init"
*
- *
* @b .create nr
*
* Break if a new IR-node with node number nr was created.
*
* Disables breakpoint nr.
*
- * @b .setmask name lvl
+ * @b .showent nr
+ *
+ * Show the content of entity nr.
+ *
+ * @b .showent name
+ *
+ * Show the content of entity name.
+ *
+ * @b .showtype nr
+ *
+ * Show the content of type nr.
+ *
+ * @b .showtype name
+ *
+ * Show the content of type name.
+ *
+ * @b .setmask name msk
+ *
+ * Sets the debug module name to mask msk.
+ *
+ * @b .setlvl name lvl
*
* Sets the debug module name to level lvl.
*
*
* Redirects debug output of module name to file.
*
+ * @b .irgname name
+ *
+ * Prints address and graph number of a method given by its name.
+ *
+ * @b .irgldname name
+ *
+ * Prints address and graph number of a method given by its linker name.
+ *
* @b .help
*
* List all commands.
* -# start gdb with your compiler
* -# after gdb breaks, issue
*
- * p firm_debug(".create 2101")
+ * call firm_debug(".create 2101")
*
* On the console the following text should be issued:
*
# define firm "cmd" Firm debugger extension
#
define firm
- p firm_debug($arg0)
+ call firm_debug($arg0)
end
* @endcode
*
- * Then, all Firm debugger extension commands can be access in the gdb
+ * Then, all Firm debugger extension commands can be accessed in the gdb
* console using the firm prefix, eg.:
*
* firm ".create 2101"
+ *
* firm ".help"
*/