/*
- * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
*
* This file is part of libFirm.
*
* PURPOSE.
*/
-/*
- * Project: libFIRM
- * File name: ir/debug/debugger.c
- * Purpose: Helper function for integerated debug support
- * Author: Michael Beck
- * Modified by:
- * Created: 2005
- * CVS-ID: $Id$
- * Copyright: (c) 2001-2007 Universität Karlsruhe
+/**
+ * @file
+ * @brief Helper function for integrated debug support
+ * @author Michael Beck
+ * @date 2005
+ * @version $Id$
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#ifdef DEBUG_libfirm
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-
-#define strncasecmp strnicmp
#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
+#include "debugger.h"
+#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
-
-#ifdef HAVE_STRING_H
#include <string.h>
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
#endif
#include <ctype.h>
#include "irgraph_t.h"
#include "entity_t.h"
#include "irprintf.h"
-#include "typewalk.h"
#include "irdump.h"
+#include "iredges_t.h"
#include "debug.h"
+#include "error.h"
#ifdef _WIN32
/* Break into the debugger. The Win32 way. */
-void firm_debug_break(void) {
+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. */
-void firm_debug_break(void) {
+void firm_debug_break(void)
+{
__asm__ __volatile__("int3");
}
#else
/* Break into the debugger. Poor Unix way. */
-void firm_debug_break(void) {
+void firm_debug_break(void)
+{
raise(SIGINT);
}
#endif /* _WIN32 */
do { \
debugger_hooks[h].hook._##h = fkt; \
register_hook(h, &debugger_hooks[h]); \
-} while(0)
+} while (0)
/** unhook the hook h */
#define UNHOOK(h) \
do { \
unregister_hook(h, &debugger_hooks[h]); \
debugger_hooks[h].hook._##h = NULL; \
-} while(0)
+} while (0)
/** returns non-zero if a entry hook h is used */
#define IS_HOOKED(h) (debugger_hooks[h].hook._##h != NULL)
#define FIRM_DBG_MINOR 0
/** for automatic detection of the debug extension */
-static const char *firm_debug_info_string =
+static const char __attribute__((used)) firm_debug_info_string[] =
API_VERSION(FIRM_DBG_MAJOR, FIRM_DBG_MINOR);
-/**
- * Returns non-zero, if the debug extension is active
- */
-int firm_debug_active(void) {
+int firm_debug_active(void)
+{
return is_active;
} /* firm_debug_active */
/**
* Reset the debug text buffer.
*/
-static void reset_dbg_buf(void) {
+static void reset_dbg_buf(void)
+{
firm_dbg_msg_buf[0] = '\0';
} /* reset_dbg_buf */
-/**
- * Add text to the debug text buffer.
- */
-static void add_to_dbg_buf(const char *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 */
-/**
- * Return the content of the debug text buffer.
- *
- * To be called from the debugger.
- */
-const char *firm_debug_text(void) {
+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 */
static void dbg_new_node(void *ctx, ir_graph *irg, ir_node *node)
{
bp_nr_t key, *elem;
+ (void) ctx;
+ (void) irg;
key.nr = get_irn_node_nr(node);
key.bp.reason = BP_ON_NEW_NODE;
static void dbg_replace(void *ctx, ir_node *old, ir_node *nw)
{
bp_nr_t key, *elem;
+ (void) ctx;
key.nr = get_irn_node_nr(old);
key.bp.reason = BP_ON_REPLACE;
static void dbg_lower(void *ctx, ir_node *node)
{
bp_nr_t key, *elem;
+ (void) ctx;
key.nr = get_irn_node_nr(node);
key.bp.reason = BP_ON_LOWER;
*/
static void dbg_free_graph(void *ctx, ir_graph *irg)
{
+ (void) ctx;
{
bp_nr_t key, *elem;
key.nr = get_irg_graph_nr(irg);
*/
static void dbg_new_entity(void *ctx, ir_entity *ent)
{
+ (void) ctx;
{
bp_ident_t key, *elem;
*/
static void dbg_new_type(void *ctx, ir_type *tp)
{
+ (void) ctx;
{
bp_nr_t key, *elem;
firm_debug_break();
}
}
- {
- bp_ident_t key, *elem;
-
- key.id = get_type_ident(tp);
- key.bp.reason = BP_ON_NEW_TYPE;
-
- elem = set_find(bp_idents, &key, sizeof(key), HASH_IDENT_BP(key));
- if (elem && elem->bp.active) {
- dbg_printf("Firm BP %u reached, %+F was created\n", elem->bp.bpnr, tp);
- firm_debug_break();
- }
- }
} /* dbg_new_type */
/**
case BP_ON_REMIRG: return "removing IRG";
case BP_ON_NEW_ENT: return "entity creation";
case BP_ON_NEW_TYPE: return "type creation";
- default: assert(0);
+ case BP_MAX_REASON: break;
}
- return "unknown";
+ panic("unsupported reason");
} /* reason_str */
/**
{
const bp_nr_t *e1 = elt;
const bp_nr_t *e2 = key;
+ (void) size;
return (e1->nr - e2->nr) | (e1->bp.reason - e2->bp.reason);
} /* cmp_nr_bp */
{
const bp_ident_t *e1 = elt;
const bp_ident_t *e2 = key;
+ (void) size;
return (e1->id != e2->id) | (e1->bp.reason - e2->bp.reason);
} /* cmp_ident_bp */
CASE_ON(BP_ON_NEW_ENT, new_entity);
CASE_ON(BP_ON_NEW_TYPE, new_type);
default:
- ;
+ break;
}
}
else {
CASE_OFF(BP_ON_NEW_ENT, new_entity);
CASE_OFF(BP_ON_NEW_TYPE, new_type);
default:
- ;
+ break;
}
}
#undef CASE_ON
/**
* Break if ident name is reached.
*/
-static void break_on_ident(const char *name, bp_reasons_t reason) {
+static void break_on_ident(const char *name, bp_reasons_t reason)
+{
bp_ident_t key, *elem;
key.bp.kind = BP_IDENT;
/**
* Show a list of supported commands
*/
-static void show_commands(void) {
+static void show_commands(void)
+{
dbg_printf("Internal Firm debugger extension $Revision$ 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"
- ".lower nr break before node nr is lowered\n"
- ".remirg nr|name break if the irg of nr or entity name is deleted\n"
- ".newent nr|name break if the entity nr or name was created\n"
- ".newtype nr|name break if the type nr or name was created\n"
- ".bp show all breakpoints\n"
- ".enable nr enable breakpoint nr\n"
- ".disable nr disable breakpoint nr\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"
+ "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"
+ "lower nr break before node nr is lowered\n"
+ "remirg nr|name break if the irg of nr or entity name is deleted\n"
+ "newent nr|name break if the entity nr or name was created\n"
+ "newtype nr|name break if the type nr or name was created\n"
+ "bp show all breakpoints\n"
+ "enable nr enable breakpoint nr\n"
+ "disable nr disable breakpoint nr\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.
*/
-static void show_bp(void) {
+static void show_bp(void)
+{
breakpoint *p;
bp_nr_t *node_p;
bp_ident_t *ident_p;
* firm_dbg_register() expects that the name is stored persistent.
* So we need this little helper function
*/
-static firm_dbg_module_t *dbg_register(const char *name) {
+static firm_dbg_module_t *dbg_register(const char *name)
+{
ident *id = new_id_from_str(name);
return firm_dbg_register(get_id_str(id));
/**
* Show info about a firm thing.
*/
-static void show_firm_object(void *firm_thing) {
+static void show_firm_object(void *firm_thing)
+{
FILE *f = stdout;
if (firm_thing == NULL) {
/**
* Find a firm type by its number.
*/
-static ir_type *find_type_nr(long nr) {
+static ir_type *find_type_nr(long nr)
+{
int i, n = get_irp_n_types();
ir_type *tp;
/**
* Find a firm type by its name.
*/
-static ir_type *find_type_name(const char *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)
+ if (!is_compound_type(tp))
+ continue;
+
+ if (strcmp(get_compound_name(tp), name) == 0)
return tp;
}
tp = get_glob_type();
- if (strcmp(get_type_name(tp), name) == 0)
+ if (strcmp(get_compound_name(tp), name) == 0)
return tp;
return NULL;
} /* find_type_name */
/**
* Type-walker: Find an entity with given number.
*/
-static void check_ent_nr(type_or_ent *tore, void *ctx) {
- ir_entity *ent = (ir_entity *)tore;
+static void check_ent_nr(type_or_ent tore, void *ctx)
+{
find_env_t *env = ctx;
- if (is_entity(ent))
- if (get_entity_nr(ent) == env->u.nr) {
- env->res = ent;
+ if (is_entity(tore.ent)) {
+ if (get_entity_nr(tore.ent) == env->u.nr) {
+ env->res = tore.ent;
}
+ }
} /* check_ent_nr */
/**
* Type-walker: Find an entity with given name.
*/
-static void check_ent_name(type_or_ent *tore, void *ctx) {
- ir_entity *ent = (ir_entity *)tore;
+static void check_ent_name(type_or_ent tore, void *ctx)
+{
find_env_t *env = ctx;
- if (is_entity(ent))
- if (strcmp(get_entity_name(ent), env->u.name) == 0) {
- env->res = ent;
+ if (is_entity(tore.ent))
+ 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.
*/
-static ir_entity *find_entity_nr(long nr) {
+static ir_entity *find_entity_nr(long nr)
+{
find_env_t env;
env.u.nr = nr;
/**
* Find a firm entity by its name.
*/
-static ir_entity *find_entity_name(const char *name) {
+static ir_entity *find_entity_name(const char *name)
+{
find_env_t env;
env.u.name = name;
/**
* Search methods for a name.
*/
-static void show_by_name(type_or_ent *tore, void *env) {
+static void show_by_name(type_or_ent tore, void *env)
+{
ident *id = (ident *)env;
- if (is_entity(tore)) {
- ir_entity *ent = (ir_entity *)tore;
+ if (is_entity(tore.ent)) {
+ ir_entity *ent = tore.ent;
if (is_method_entity(ent)) {
if (get_entity_ident(ent) == id) {
ir_graph *irg = get_entity_irg(ent);
if (owner != get_glob_type()) {
- printf("%s::%s", get_type_name(owner), get_id_str(id));
+ printf("%s::%s", get_compound_name(owner), get_id_str(id));
} else {
printf("%s", get_id_str(id));
}
/**
* Search methods for a ldname.
*/
-static void show_by_ldname(type_or_ent *tore, void *env) {
+static void show_by_ldname(type_or_ent tore, void *env)
+{
ident *id = (ident *)env;
- if (is_entity(tore)) {
- ir_entity *ent = (ir_entity *)tore;
+ if (is_entity(tore.ent)) {
+ ir_entity *ent = tore.ent;
if (is_method_entity(ent)) {
if (get_entity_ld_ident(ent) == id) {
ir_graph *irg = get_entity_irg(ent);
if (owner != get_glob_type()) {
- printf("%s::%s", get_type_name(owner), get_id_str(id));
+ printf("%s::%s", get_compound_name(owner), get_id_str(id));
} else {
printf("%s", get_id_str(id));
}
/**
* prints the address and graph number of all irgs with given name
*/
-static void irg_name(const char *name) {
+static void irg_name(const char *name)
+{
ident *id = new_id_from_str(name);
type_walk(show_by_name, NULL, (void *)id);
/**
* prints the address and graph number of all irgs with given ld_name
*/
-static void irg_ld_name(const char *name) {
+static void irg_ld_name(const char *name)
+{
ident *id = new_id_from_str(name);
type_walk(show_by_ldname, NULL, (void *)id);
/**
* Initialize the lexer.
*/
-static void init_lexer(const char *input) {
+static void init_lexer(const char *input)
+{
lexer.has_token = 0;
lexer.curr_pos = input;
lexer.end_pos = input + strlen(input);
/**
* Get the next char from the input.
*/
-static char next_char(void) {
+static char next_char(void)
+{
if (lexer.curr_pos >= lexer.end_pos)
return '\0';
return *lexer.curr_pos++;
/**
* The lexer.
*/
-static unsigned get_token(void) {
+static unsigned get_token(void)
+{
char c;
int i;
} while (c != '\0' && isspace(c));
lexer.tok_start = lexer.curr_pos - 1;
- if (c == '.') {
+ if (c == '.' || isalpha(c)) {
/* command begins here */
- int len = 0;
+ int len = 0;
+ const char* tok_start;
do {
c = next_char();
++len;
- } while (isalpha(c));
+ } while (isgraph(c));
unput();
- --len;
+ tok_start = lexer.tok_start;
+ if (*tok_start == '.') {
+ ++tok_start;
+ --len;
+ }
for (i = sizeof(reserved)/sizeof(reserved[0]) - 1; i >= 0; --i) {
- if (strncasecmp(lexer.tok_start + 1, reserved[i], len) == 0 && reserved[i][len] == '\0')
- break;
+ if (strncasecmp(tok_start, reserved[i], len) == 0 && reserved[i][len] == '\0')
+ return 256 + i;
}
- if (i >= 0)
- return 256 + i;
- return tok_error;
- } else if (isalpha(c)) {
- /* identifier */
- lexer.s = lexer.curr_pos - 1;
- do {
- c = next_char();
- } while (isgraph(c));
- unput();
+ /* identifier */
+ lexer.s = lexer.tok_start;
lexer.len = lexer.curr_pos - lexer.s;
return tok_identifier;
} else if (isdigit(c) || c == '-') {
return c;
} /* get_token */
-/**
- * High level function to use from debugger interface
- *
- * Supported commands:
- * .create nr break if node nr was created
- * .help list all commands
- */
-void firm_debug(const char *cmd) {
+void firm_debug(const char *cmd)
+{
char name[1024], fname[1024];
int len;
;
} /* firm_debug */
-/* creates the debugger tables */
void firm_init_debugger(void)
{
char *env;
firm_debug_break();
} /* firm_init_debugger */
+/**
+ * A gdb helper function to print firm objects.
+ */
+const char *gdb_node_helper(void *firm_object)
+{
+ static char buf[1024];
+ ir_snprintf(buf, sizeof(buf), "%+F", firm_object);
+ return buf;
+}
+
+const char *gdb_tarval_helper(void *tv_object)
+{
+ static char buf[1024];
+ ir_snprintf(buf, sizeof(buf), "%+T", tv_object);
+ return buf;
+}
+
+const char *gdb_out_edge_helper(const ir_node *node)
+{
+ static char buf[4*1024];
+ 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);
+
+ ir_snprintf(b, len, "%+F ", n);
+ l = strlen(b);
+ len -= l;
+ b += l;
+ }
+
+ return buf;
+}
+
#else
/* some picky compiler do not allow empty files */
-static int _firm_only_that_you_can_compile_with_NDEBUG_defined;
+static int __attribute__((unused)) _firm_only_that_you_can_compile_with_NDEBUG_defined;
#endif /* NDEBUG */
*
* @section sec_cmd Supported commands
*
+ * Historically all debugger commands start with a dot. This isn't needed in newer
+ * versions, but still supported, ie the commands ".init" and "init" are equal.
* The following commands are currently supported:
*
- * @b .init
+ * @b init
*
* Break immediately after the debugger extension was initialized.
* Typically this command is used in the environment to stop the execution
*
* $export FIRMDBG=".init"
*
- * @b .create nr
+ * @b create nr
*
* Break if a new IR-node with node number nr was created.
* Typically used to find the place where wrong nodes are created.
*
- * @b .replace nr
+ * @b replace nr
*
* Break before IR-node with node number nr is replaced by another node.
*
- * @b .lower nr
+ * @b lower nr
*
* Break before IR-node with node number nr is lowered.
*
- * @b .remirg nr
+ * @b remirg nr
*
* Break if the irg with graph number nr is deleted.
*
- * @b .remirg name
+ * @b remirg name
*
* Break if the irg of entity name is deleted.
*
- * @b .newent nr
+ * @b newent nr
*
* Break if the entity with number nr was created.
*
- * @b .newent name
+ * @b newent name
*
* Break if the entity name was created.
*
- * @b .newtype nr
+ * @b newtype nr
*
* Break if the type with number nr was created.
*
- * @b .newtype name
+ * @b newtype name
*
* Break if the type name was created.
*
- * @b .bp
+ * @b bp
*
* Show all Firm internal breakpoints.
*
- * @b .enable nr
+ * @b enable nr
*
* Enables breakpoint nr.
*
- * @b .disable nr
+ * @b disable nr
*
* Disables breakpoint nr.
*
- * @b .showent nr
+ * @b showent nr
*
* Show the content of entity nr.
*
- * @b .showent name
+ * @b showent name
*
* Show the content of entity name.
*
- * @b .showtype nr
+ * @b showtype nr
*
* Show the content of type nr.
*
- * @b .showtype name
+ * @b showtype name
*
* Show the content of type name.
*
- * @b .setmask name msk
+ * @b setmask name msk
*
* Sets the debug module name to mask msk.
*
- * @b .setlvl name lvl
+ * @b setlvl name lvl
*
* Sets the debug module name to level lvl.
*
- * @b .setoutfile name file
+ * @b setoutfile name file
*
* Redirects debug output of module name to file.
*
- * @b .irgname name
+ * @b irgname name
*
* Prints address and graph number of a method given by its name.
*
- * @b .irgldname name
+ * @b irgldname name
*
* Prints address and graph number of a method given by its linker name.
*
- * @b .help
+ * @b help
*
* List all commands.
*
* The following example shows how to set a creation breakpoint in GDB when
* node 2101 is created.
*
- * -# set FIRMDBG=".init"
+ * -# set FIRMDBG="init"
* -# start gdb with your compiler
* -# after gdb breaks, issue
*
- * call firm_debug(".create 2101")
+ * call firm_debug("create 2101")
*
* On the console the following text should be issued:
*
* Then, all Firm debugger extension commands can be accessed in the gdb
* console using the firm prefix, eg.:
*
- * firm ".create 2101"
+ * firm "create 2101"
*
- * firm ".help"
+ * firm "help"
*/