- add an extra filed for the bit offset\n- renamed access functions\n- renamed entity...
[libfirm] / ir / debug / debugger.c
index 4732879..00cfe05 100644 (file)
@@ -6,14 +6,14 @@
  * 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;
 
@@ -92,16 +94,16 @@ typedef struct {
   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. */
@@ -143,13 +145,20 @@ static int is_active = 0;
 
 /** 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
@@ -170,21 +179,21 @@ static const char *firm_debug_info_string =
  */
 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.
@@ -192,8 +201,9 @@ static void add_to_dbg_buf(const char *buf) {
  * 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
@@ -217,7 +227,7 @@ static void dbg_printf(const char *fmt, ...)
     add_to_dbg_buf(buf);
   else
     puts(buf);
-}
+}  /* dbg_printf */
 
 /**
  * A new node is created.
@@ -238,7 +248,7 @@ static void dbg_new_node(void *ctx, ir_graph *irg, ir_node *node)
     dbg_printf("Firm BP %u reached, %+F created\n", elem->bp.bpnr, node);
     firm_debug_break();
   }
-}
+}  /* dbg_new_node */
 
 /**
  * A node is replaced.
@@ -259,7 +269,7 @@ static void dbg_replace(void *ctx, ir_node *old, ir_node *nw)
     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.
@@ -279,7 +289,7 @@ static void dbg_lower(void *ctx, ir_node *node)
     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.
@@ -316,7 +326,7 @@ static void dbg_free_graph(void *ctx, ir_graph *irg)
       firm_debug_break();
     }
   }
-}
+}  /* dbg_free_graph */
 
 /**
  * An entity was created.
@@ -350,7 +360,7 @@ static void dbg_new_entity(void *ctx, entity *ent)
       firm_debug_break();
     }
   }
-}
+}  /* dbg_new_entity */
 
 /**
  * A type was created.
@@ -358,7 +368,7 @@ static void dbg_new_entity(void *ctx, entity *ent)
  * @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;
@@ -384,10 +394,10 @@ static void dbg_new_type(void *ctx, type *tp)
       firm_debug_break();
     }
   }
-}
+}  /* dbg_new_type */
 
 /**
- * return the reason string.
+ * Return the reason string.
  */
 static const char *reason_str(bp_reasons_t reason)
 {
@@ -401,10 +411,10 @@ 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)
 {
@@ -412,10 +422,10 @@ 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)
 {
@@ -423,10 +433,10 @@ 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)
 {
@@ -466,7 +476,7 @@ static void update_hooks(breakpoint *bp)
   }
 #undef CASE_ON
 #undef CASE_OFF
-}
+}  /* update_hooks */
 
 /**
  * Break if nr is reached.
@@ -493,7 +503,7 @@ static void break_on_nr(long nr, bp_reasons_t reason)
 
     update_hooks(&elem->bp);
   }
-}
+}  /* break_on_nr */
 
 /**
  * Break if ident name is reached.
@@ -519,7 +529,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.
@@ -540,7 +550,7 @@ static void bp_activate(unsigned bp, int active)
     }
   }
   dbg_printf("Error: Firm BP %u not exists.\n", bp);
-}
+}  /* bp_activate */
 
 
 /**
@@ -558,11 +568,16 @@ static void show_commands(void) {
     ".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.
@@ -593,7 +608,7 @@ 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.
@@ -603,7 +618,7 @@ 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
@@ -612,10 +627,12 @@ static void set_dbg_level(const char *name, unsigned 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
@@ -632,7 +649,212 @@ 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) {
+  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
@@ -676,6 +898,18 @@ void firm_debug(const char *cmd) {
   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)
@@ -686,12 +920,18 @@ void firm_debug(const char *cmd) {
     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)
@@ -699,7 +939,7 @@ 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");
 
@@ -710,7 +950,7 @@ void firm_init_debugger(void)
 
   if (break_on_init)
     firm_debug_break();
-}
+}  /* firm_init_debugger */
 
 #else
 
@@ -729,6 +969,7 @@ static int _firm_only_that_you_can_compile_with_NDEBUG_defined;
  * @section sec_cmd Supported commands
  *
  * The following commands are currently supported:
+ *
  * @b .init
  *
  * Break immediately after the debugger extension was initialized.
@@ -737,7 +978,6 @@ static int _firm_only_that_you_can_compile_with_NDEBUG_defined;
  *
  * $export FIRMDBG=".init"
  *
- *
  * @b .create nr
  *
  * Break if a new IR-node with node number nr was created.
@@ -787,7 +1027,27 @@ static int _firm_only_that_you_can_compile_with_NDEBUG_defined;
  *
  * 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.
  *
@@ -795,6 +1055,14 @@ static int _firm_only_that_you_can_compile_with_NDEBUG_defined;
  *
  * 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.
@@ -808,7 +1076,7 @@ static int _firm_only_that_you_can_compile_with_NDEBUG_defined;
  * -# 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:
  *
@@ -823,21 +1091,14 @@ static int _firm_only_that_you_can_compile_with_NDEBUG_defined;
  # 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"
  */
-
-#ifdef __GNUC__
-static void _firm_only_that_you_can_compile_with_NDEBUG_defined(void) __attribute__((unused));
-#endif
-
-static void _firm_only_that_you_can_compile_with_NDEBUG_defined(void)
-{
-}