X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fdebug%2Fdebugger.c;h=aeed330cb0622e2c245c3f03d08481aacee424dd;hb=3b6c919808534f66388ec4212373fe5b40d20926;hp=9d454fe0248201755c7f9e572aade63ebc3125f3;hpb=863d31d7a5c8210432fef88b30fc3e8353131538;p=libfirm diff --git a/ir/debug/debugger.c b/ir/debug/debugger.c index 9d454fe02..aeed330cb 100644 --- a/ir/debug/debugger.c +++ b/ir/debug/debugger.c @@ -1,37 +1,31 @@ /* - * 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 - * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE. + * This file is part of libFirm. + * Copyright (C) 2012 University of Karlsruhe. + */ + +/** + * @file + * @brief Helper function for integrated debug support + * @author Michael Beck + * @date 2005 */ -#ifdef HAVE_CONFIG_H #include "config.h" -#endif #ifdef DEBUG_libfirm #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include - -#define strncasecmp strnicmp #endif -#ifdef HAVE_STDLIB_H -#include -#endif +#include "debugger.h" +#include #include #include - -#ifdef HAVE_STRING_H #include -#endif +#include +#include #include @@ -41,23 +35,28 @@ #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" +#include "util.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 */ @@ -71,23 +70,22 @@ typedef enum { /** * Reasons for node number breakpoints. */ -typedef enum _bp_reasons_t { - BP_ON_NEW_NODE, /**< break if node with number is created */ +typedef enum bp_reasons_t { + 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; /** A breakpoint. */ -typedef struct _breakpoint { +typedef struct breakpoint { bp_kind kind; /**< the kind of this break point */ unsigned bpnr; /**< break point number */ int active; /**< non-zero, if this break point is active */ bp_reasons_t reason; /**< reason for the breakpoint */ - struct _breakpoint *next; /**< link to the next one */ + struct breakpoint *next; /**< link to the next one */ } breakpoint; /** A number breakpoint. */ @@ -106,7 +104,7 @@ typedef struct { } 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; @@ -150,14 +148,14 @@ static int is_active = 0; 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) @@ -172,63 +170,48 @@ do { \ #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) { - 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 */ +} /** * 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. @@ -240,16 +223,18 @@ static void dbg_printf(const char *fmt, ...) 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; + key.bp.reason = BP_ON_NEW_THING; - elem = 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. @@ -261,16 +246,17 @@ static void dbg_new_node(void *ctx, ir_graph *irg, ir_node *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; - elem = 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. @@ -281,16 +267,17 @@ static void dbg_replace(void *ctx, ir_node *old, ir_node *nw) 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; - elem = 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. @@ -300,12 +287,13 @@ static void dbg_lower(void *ctx, ir_node *node) */ static void dbg_free_graph(void *ctx, ir_graph *irg) { + (void) ctx; { bp_nr_t key, *elem; key.nr = get_irg_graph_nr(irg); key.bp.reason = BP_ON_REMIRG; - elem = 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(); @@ -321,13 +309,13 @@ static void dbg_free_graph(void *ctx, ir_graph *irg) key.id = get_entity_ident(ent); key.bp.reason = BP_ON_REMIRG; - elem = 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. @@ -337,13 +325,14 @@ static void dbg_free_graph(void *ctx, ir_graph *irg) */ static void dbg_new_entity(void *ctx, ir_entity *ent) { + (void) ctx; { bp_ident_t key, *elem; key.id = get_entity_ident(ent); key.bp.reason = BP_ON_NEW_ENT; - elem = 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(); @@ -353,15 +342,15 @@ static void dbg_new_entity(void *ctx, ir_entity *ent) 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 = 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. @@ -371,31 +360,20 @@ static void dbg_new_entity(void *ctx, ir_entity *ent) */ static void dbg_new_type(void *ctx, ir_type *tp) { + (void) ctx; { 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 = 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(); } } - { - 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 */ +} /** * Return the reason string. @@ -403,46 +381,47 @@ static void dbg_new_type(void *ctx, ir_type *tp) 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"; - default: assert(0); + 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; } - return "unknown"; -} /* reason_str */ + panic("unsupported reason"); +} /** * Compare two number breakpoints. */ static int cmp_nr_bp(const void *elt, const void *key, size_t size) { - const bp_nr_t *e1 = elt; - const bp_nr_t *e2 = key; + const bp_nr_t *e1 = (const bp_nr_t*)elt; + const bp_nr_t *e2 = (const bp_nr_t*)key; + (void) size; return (e1->nr - e2->nr) | (e1->bp.reason - e2->bp.reason); -} /* cmp_nr_bp */ +} /** * Compare two ident breakpoints. */ static int cmp_ident_bp(const void *elt, const void *key, size_t size) { - const bp_ident_t *e1 = elt; - const bp_ident_t *e2 = key; + const bp_ident_t *e1 = (const bp_ident_t*)elt; + const bp_ident_t *e2 = (const bp_ident_t*)key; + (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]; @@ -452,32 +431,44 @@ static void update_hooks(breakpoint *bp) 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. @@ -492,7 +483,7 @@ static void break_on_nr(long nr, bp_reasons_t reason) key.bp.reason = reason; key.nr = nr; - elem = 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 */ @@ -504,12 +495,13 @@ static void break_on_nr(long nr, bp_reasons_t reason) update_hooks(&elem->bp); } -} /* break_on_nr */ +} /** * 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; @@ -518,7 +510,7 @@ static void break_on_ident(const char *name, bp_reasons_t reason) { key.bp.reason = reason; key.id = new_id_from_str(name); - elem = 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 */ @@ -530,7 +522,7 @@ static void break_on_ident(const char *name, bp_reasons_t reason) { update_hooks(&elem->bp); } -} /* break_on_ident */ +} /** * Sets/resets the active flag of breakpoint bp. @@ -551,39 +543,42 @@ static void bp_activate(unsigned bp, int active) } } dbg_printf("Error: Firm BP %u not exists.\n", bp); -} /* bp_activate */ +} /** * Show a list of supported commands */ -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" +static void show_commands(void) +{ + 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" + "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" + "initialnodenr n|rand set initial node number to n or random number\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; @@ -609,17 +604,18 @@ static void show_bp(void) { 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. * 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)); -} /* dbg_register */ +} /** * Sets the debug mask of module name to lvl @@ -633,7 +629,7 @@ static void set_dbg_level(const char *name, unsigned 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 @@ -650,12 +646,13 @@ static void set_dbg_outfile(const char *name, const char *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) { +static void show_firm_object(void *firm_thing) +{ FILE *f = stdout; if (firm_thing == NULL) { @@ -667,10 +664,10 @@ static void show_firm_object(void *firm_thing) { fprintf(f, "BAD: (%p)\n", firm_thing); break; case k_entity: - dump_entity_to_file(f, firm_thing, dump_verbosity_max); + dump_entity_to_file(f, (ir_entity*)firm_thing); break; case k_type: - dump_type_to_file(f, firm_thing, dump_verbosity_max); + dump_type_to_file(f, (ir_type*)firm_thing); break; case k_ir_graph: case k_ir_node: @@ -678,20 +675,19 @@ static void show_firm_object(void *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. */ -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; @@ -704,25 +700,29 @@ static ir_type *find_type_nr(long nr) { 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) { +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 */ +} /** The environment for the entity search functions. */ typedef struct find_env { @@ -736,61 +736,65 @@ typedef struct find_env { /** * 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; - find_env_t *env = ctx; +static void check_ent_nr(type_or_ent tore, void *ctx) +{ + find_env_t *env = (find_env_t*)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; - find_env_t *env = ctx; +static void check_ent_name(type_or_ent tore, void *ctx) +{ + find_env_t *env = (find_env_t*)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; env.res = NULL; type_walk(check_ent_nr, NULL, &env); return env.res; -} /* find_entity_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; 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) { +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) { @@ -798,7 +802,7 @@ static void show_by_name(type_or_ent *tore, void *env) { 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)); } @@ -809,16 +813,17 @@ static void show_by_name(type_or_ent *tore, void *env) { } } } -} /* show_by_name */ +} /** * 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) { @@ -826,7 +831,7 @@ static void show_by_ldname(type_or_ent *tore, void *env) { 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)); } @@ -837,45 +842,49 @@ static void show_by_ldname(type_or_ent *tore, void *env) { } } } -} /* show_by_ldname */ +} /** * 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); -} /* irg_name */ +} /** * 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); -} /* 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, @@ -883,24 +892,25 @@ enum tokens { }; 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", }; /** @@ -911,7 +921,7 @@ static struct lexer { unsigned cur_token; /**< current token. */ unsigned number; /**< current token attribute. */ const char *s; /**< current token attribute. */ - unsigned len; /**< current token attribute. */ + size_t len; /**< current token attribute. */ const char *curr_pos; const char *end_pos; @@ -921,23 +931,25 @@ static struct lexer { /** * 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); -} /* init_lexer */ +} /** * 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++; -} /* next_char */ +} -#define unput() if (lexer.curr_pos < lexer.end_pos) --lexer.curr_pos +#define unput() if (lexer.curr_pos < lexer.end_pos) --lexer.curr_pos #undef MIN #define MIN(a, b) (a) < (b) ? (a) : (b) @@ -945,45 +957,43 @@ static char next_char(void) { /** * The lexer. */ -static unsigned get_token(void) { +static unsigned get_token(void) +{ char c; - int i; + size_t i; /* skip white space */ do { c = next_char(); - } while (c != '\0' && isspace(c)); + } while (c != '\0' && isspace((unsigned char)c)); lexer.tok_start = lexer.curr_pos - 1; - if (c == '.') { + if (c == '.' || isalpha((unsigned char)c)) { /* command begins here */ - int len = 0; + int len = 0; + const char* tok_start; do { c = next_char(); ++len; - } while (isalpha(c)); + } while (isgraph((unsigned char)c)); unput(); - --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; + tok_start = lexer.tok_start; + if (*tok_start == '.') { + ++tok_start; + --len; + } + for (i = ARRAY_SIZE(reserved); i-- != 0;) { + if (strncasecmp(tok_start, reserved[i], len) == 0 && reserved[i][len] == '\0') + return first_token + 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 == '-') { + } else if (isdigit((unsigned char)c) || c == '-') { unsigned number = 0; unsigned sign = 0; @@ -1000,12 +1010,12 @@ static unsigned get_token(void) { for (;;) { c = next_char(); - if (! isxdigit(c)) + if (! isxdigit((unsigned char)c)) break; - if (isdigit(c)) + if (isdigit((unsigned char)c)) number = (number << 4) | (c - '0'); else - number = (number << 4) | (toupper(c) - 'A' + 10); + number = (number << 4) | (toupper((unsigned char)c) - 'A' + 10); } unput(); lexer.number = number; @@ -1013,7 +1023,7 @@ static unsigned get_token(void) { } } for (;;) { - if (! isdigit(c)) + if (! isdigit((unsigned char)c)) break; number = number * 10 + (c - '0'); c = next_char(); @@ -1025,18 +1035,12 @@ static unsigned get_token(void) { else if (c == '\0') return tok_eof; 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; + size_t len; init_lexer(cmd); @@ -1053,7 +1057,7 @@ 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: @@ -1088,7 +1092,7 @@ void firm_debug(const char *cmd) { 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); @@ -1098,20 +1102,6 @@ void firm_debug(const char *cmd) { 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(); @@ -1205,6 +1195,7 @@ void firm_debug(const char *cmd) { strncpy(fname, lexer.s, len); fname[len] = '\0'; set_dbg_outfile(name, fname); + break; case tok_irgname: token = get_token(); @@ -1214,6 +1205,20 @@ void firm_debug(const char *cmd) { strncpy(name, lexer.s, len); name[len] = '\0'; 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(); @@ -1225,6 +1230,16 @@ void firm_debug(const char *cmd) { 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; @@ -1245,9 +1260,8 @@ error: } leave: ; -} /* firm_debug */ +} -/* creates the debugger tables */ void firm_init_debugger(void) { char *env; @@ -1264,12 +1278,53 @@ 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. + */ +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); + 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 */ @@ -1283,9 +1338,11 @@ static int _firm_only_that_you_can_compile_with_NDEBUG_defined; * * @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 @@ -1293,92 +1350,92 @@ static int _firm_only_that_you_can_compile_with_NDEBUG_defined; * * $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. * @@ -1387,11 +1444,11 @@ static int _firm_only_that_you_can_compile_with_NDEBUG_defined; * 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: * @@ -1413,7 +1470,7 @@ static int _firm_only_that_you_can_compile_with_NDEBUG_defined; * 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" */