Index: linkers/rtems-tld.cpp
===================================================================
--- linkers/rtems-tld.cpp	(revision 8531776882b69aef9db276cbf9a18fd614bda9e5)
+++ linkers/rtems-tld.cpp	(revision 29ad92c524be36364ad2e987a3bcf16f753dd88a)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2014, Chris Johns <chrisj@rtems.org>
+ * Copyright (c) 2014-2015, Chris Johns <chrisj@rtems.org>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
@@ -31,4 +31,5 @@
 #include <functional>
 #include <iostream>
+#include <iomanip>
 #include <locale>
 #include <sstream>
@@ -75,4 +76,26 @@
 
     /**
+     * An option is a name and value pair. We consider options as global.
+     */
+    struct option
+    {
+      std::string name;      /**< The name of this option. */
+      std::string value;     /**< The option's value.. */
+
+      /**
+       * Load the option.
+       */
+      option (const std::string& name, const std::string& value)
+        : name (name),
+          value (value) {
+      }
+    };
+
+    /**
+     * A container of options.
+     */
+    typedef std::vector < option > options;
+
+    /**
      * A function's signature.
      */
@@ -191,8 +214,15 @@
        * Process any script based options.
        */
-      void load_options (const rld::config::section& section);
-
-      /**
-       * The the functions for the trace.
+      void load_options (rld::config::config&        config,
+                         const rld::config::section& section);
+
+      /**
+       * The defines for the trace.
+       */
+      void load_defines (rld::config::config&        config,
+                         const rld::config::section& section);
+
+      /**
+       * The functions for the trace.
        */
       void load_functions (rld::config::config&        config,
@@ -200,5 +230,17 @@
 
       /**
-       * The the traces for the tracer.
+       * The enables for the tracer.
+       */
+      void load_enables (rld::config::config&        config,
+                         const rld::config::section& section);
+
+      /**
+       * The triggers for the tracer.
+       */
+      void load_triggers (rld::config::config&        config,
+                          const rld::config::section& section);
+
+      /**
+       * The traces for the tracer.
        */
       void load_traces (rld::config::config&        config,
@@ -206,4 +248,9 @@
 
       /**
+       * Get option from the options section.
+       */
+      const std::string get_option (const std::string& name) const;
+
+      /**
        * Generate the wrapper object file.
        */
@@ -211,4 +258,19 @@
 
       /**
+       * Generate the trace names as a string table.
+       */
+      void generate_names (rld::process::tempfile& c);
+
+      /**
+       * Generate the enabled trace bitmap.
+       */
+      void generate_enables (rld::process::tempfile& c);
+
+      /**
+       * Generate the triggered trace bitmap.
+       */
+      void generate_triggers (rld::process::tempfile& c);
+
+      /**
        * Generate the trace functions.
        */
@@ -216,4 +278,12 @@
 
       /**
+       * Generate a bitmap.
+       */
+      void generate_bitmap (rld::process::tempfile& c,
+                            const rld::strings&     names,
+                            const std::string&      label,
+                            const bool              global_set);
+
+      /**
        * Get the traces.
        */
@@ -228,5 +298,9 @@
 
       std::string  name;          /**< The name of the trace. */
+      rld::strings defines;       /**< Define statements. */
+      rld::strings enables;       /**< The default enabled functions. */
+      rld::strings triggers;      /**< The default trigger functions. */
       rld::strings traces;        /**< The functions to trace. */
+      options      options_;      /**< The options. */
       functions    functions_;    /**< The functions that can be traced. */
       generator    generator_;    /**< The tracer's generator. */
@@ -244,6 +318,7 @@
        * Load the user's configuration.
        */
-      void load_config (const std::string& path,
-                        const std::string& trace);
+      void load_config (const std::string& name,
+                        const std::string& trace,
+                        const std::string& path);
 
       /**
@@ -480,5 +555,5 @@
        * # header      A list of include string that are single or double quoted.
        * # defines     A list of sections containing defines or define record.
-       * # defines     A list of define string that are single or double quoted.
+       * # define      A list of define string that are single or double quoted.
        * # code-blocks A list of section names of code blocks.
        * # includes    A list of files to include.
@@ -548,5 +623,9 @@
        *
        *  # name      The name of trace being linked.
-       *  # options   A list of options as per the long command line args.
+       *  # options   A list of option sections.
+       *  # defines   A list of sections containing defines or define record.
+       *  # define    A list of define string that are single or double quoted.
+       *  # enables   The list of sections containing enabled functions to trace.
+       *  # triggers  The list of sections containing enabled functions to trigger trace on.
        *  # traces    The list of sections containing function lists to trace.
        *  # functions The list of sections containing function details.
@@ -562,66 +641,91 @@
 
       name = section.get_record_item ("name");
-      load_options (section);
+      load_options (config, section);
       config.includes (section);
+      load_defines (config, section);
       load_functions (config, section);
+      load_enables (config, section);
+      load_triggers (config, section);
       load_traces (config, section);
     }
 
     void
-    tracer::load_options (const rld::config::section& section)
-    {
-      rld::strings ol;
-      rld::config::parse_items (section, "options", ol, true);
-
-      for (rld::strings::const_iterator oli = ol.begin ();
-           oli != ol.end ();
-           ++oli)
-      {
-        rld::strings opts;
-        rld::split(opts, *oli, ',');
-        for (rld::strings::const_iterator oi = opts.begin ();
-             oi != opts.end ();
-             ++oi)
+    tracer::load_options (rld::config::config&        config,
+                          const rld::config::section& section)
+    {
+      rld::strings opts;
+      rld::config::parse_items (section, "options", opts, false, true, true);
+
+      if (rld::verbose ())
+        std::cout << "options: " << section.name << ": " << opts.size () << std::endl;
+
+      options_.clear ();
+
+      for (rld::strings::const_iterator osi = opts.begin ();
+           osi != opts.end ();
+           ++osi)
+      {
+        const rld::config::section& osec = config.get_section (*osi);
+
+        if (rld::verbose ())
+          std::cout << " options: " << osec.name
+                    << ": recs:" << osec.recs.size () << std::endl;
+
+        for (rld::config::records::const_iterator ori = osec.recs.begin ();
+             ori != osec.recs.end ();
+             ++ori)
         {
-          const std::string& opt = *oi;
-          if (opt == "dump-on-error")
+          const rld::config::record& opt = *ori;
+
+          if (!opt.single ())
+              throw rld::error ("mode than one option specified", "option: " + opt.name);
+
+          options_.push_back (option (opt.name, opt[0]));
+
+          if (opt.name == "dump-on-error")
+          {
             dump_on_error = true;
-          else if (opt == "verbose")
-            rld::verbose_inc ();
-          else if (opt == "prefix")
+          }
+          else if (opt.name == "verbose")
           {
-            rld::strings prefix;
-            rld::split (prefix, opt, '=');
-            if (prefix.size () != 2)
-              throw rld::error ("invalid option", "option: " + opt);
-            rld::cc::set_exec_prefix (prefix[1]);
+            int level = ::strtoul(opt[0].c_str (), 0, 0);
+            if (level == 0)
+              level = 1;
+            for (int l = 0; l < level; ++l)
+              rld::verbose_inc ();
           }
-          else if (opt == "cc")
+          else if (opt.name == "prefix")
           {
-            rld::strings cc;
-            rld::split (cc, opt, '=');
-            if (cc.size () != 2)
-              throw rld::error ("invalid option", "option: " + opt);
-            rld::cc::set_cc (cc[1]);
+            rld::cc::set_exec_prefix (opt[0]);
           }
-          else if (opt == "ld")
+          else if (opt.name == "cc")
           {
-            rld::strings ld;
-            rld::split (ld, opt, '=');
-            if (ld.size () != 2)
-              throw rld::error ("invalid option", "option: " + opt);
-            rld::cc::set_ld (ld[1]);
+            rld::cc::set_cc (opt[0]);
           }
-          else if (opt == "cflags")
+          else if (opt.name == "ld")
           {
-            rld::strings cflags;
-            rld::split (cflags, opt, '=');
-            if (cflags.size () < 2)
-              throw rld::error ("invalid option", "option: " + opt);
-            cflags.erase (cflags.begin ());
-            rld::cc::append_flags (rld::join (cflags, "="), rld::cc::ft_cflags);
+            rld::cc::set_ld (opt[0]);
+          }
+          else if (opt.name == "cflags")
+          {
+            rld::cc::append_flags (opt[0], rld::cc::ft_cflags);
+          }
+          else if (opt.name == "rtems-path")
+          {
+            rld::rtems::set_path(opt[0]);
+          }
+          else if (opt.name == "rtems-bsp")
+          {
+            rld::rtems::set_arch_bsp(opt[0]);
           }
         }
       }
+    }
+
+    void
+    tracer::load_defines (rld::config::config&        config,
+                          const rld::config::section& section)
+    {
+      parse (config, section, "defines", "define", defines);
     }
 
@@ -641,4 +745,18 @@
 
     void
+    tracer::load_enables (rld::config::config&        config,
+                          const rld::config::section& section)
+    {
+      parse (config, section, "enables", "enable", enables);
+    }
+
+    void
+    tracer::load_triggers (rld::config::config&        config,
+                           const rld::config::section& section)
+    {
+      parse (config, section, "triggers", "trigger", triggers);
+    }
+
+    void
     tracer::load_traces (rld::config::config&        config,
                          const rld::config::section& section)
@@ -669,5 +787,25 @@
       }
 
+      sort (traces.begin (), traces.end ());
+
       generator_ = generator (config, gen);
+    }
+
+    const std::string
+    tracer::get_option (const std::string& name) const
+    {
+      std::string value;
+      for (options::const_iterator oi = options_.begin ();
+           oi != options_.end ();
+           ++oi)
+      {
+        const option& opt = *oi;
+        if (opt.name == name)
+        {
+          value = opt.value;
+          break;
+        }
+      }
+      return value;
     }
 
@@ -686,4 +824,10 @@
         c.write_line (" *  Automatically generated.");
         c.write_line (" */");
+
+        c.write_line ("");
+        c.write_line ("/*");
+        c.write_line (" * Tracer: " + name);
+        c.write_line (" */");
+        c.write_lines (defines);
 
         c.write_line ("");
@@ -694,4 +838,8 @@
         c.write_lines (generator_.headers);
         c.write_line ("");
+        generate_names (c);
+        generate_enables (c);
+        generate_triggers (c);
+        c.write_line ("");
         c.write_lines (generator_.code);
 
@@ -713,4 +861,80 @@
         c.output (" ", std::cout, true);
       }
+    }
+
+    void
+    tracer::generate_names (rld::process::tempfile& c)
+    {
+      const std::string opt = get_option ("gen-names");
+
+      if (opt == "disable")
+        return;
+
+      c.write_line ("");
+      c.write_line ("/*");
+      c.write_line (" * Names.");
+      c.write_line (" */");
+
+      std::stringstream sss;
+      sss << "const char const* __rld_trace_names[" << traces.size() << "] = " << std::endl
+          << "{";
+      c.write_line (sss.str ());
+
+      int count = 0;
+
+      for (rld::strings::const_iterator ti = traces.begin ();
+           ti != traces.end ();
+           ++ti)
+      {
+        const std::string& trace = *ti;
+        sss.str (std::string ());
+        sss << "  /* " << std::setw (3) << count << " */ \"" << trace << "\",";
+        c.write_line (sss.str ());
+        ++count;
+      }
+
+      c.write_line ("};");
+    }
+
+    void
+    tracer::generate_enables (rld::process::tempfile& c)
+    {
+      const std::string opt = get_option ("gen-enables");
+      bool              global_state = false;
+
+      if (opt == "disable")
+        return;
+
+      if (opt == "global-on")
+        global_state = true;
+
+      c.write_line ("");
+      c.write_line ("/*");
+      c.write_line (" * Enables.");
+      c.write_line (" */");
+
+      generate_bitmap (c, enables, "enables", global_state);
+    }
+
+    void
+    tracer::generate_triggers (rld::process::tempfile& c)
+    {
+      const std::string opt = get_option ("gen-triggers");
+      bool              global_state = false;
+
+      if (opt == "disable")
+        return;
+
+      if (opt == "global-on")
+        global_state = true;
+
+      c.write_line ("");
+      c.write_line ("/*");
+      c.write_line (" * Triggers.");
+      c.write_line (" */");
+
+      generate_bitmap (c, triggers, "triggers", global_state);
+
+      c.write_line ("");
     }
 
@@ -749,4 +973,6 @@
       c.write_line (" */");
 
+      size_t count = 0;
+
       for (rld::strings::const_iterator ti = traces.begin ();
            ti != traces.end ();
@@ -778,10 +1004,14 @@
               c.write_line(" " + sig.ret + " ret;");
 
+            std::stringstream lss;
+            lss << count;
+
             std::string l;
 
             if (!generator_.entry_trace.empty ())
             {
-              std::string l = ' ' + generator_.entry_trace;
+              std::string       l = ' ' + generator_.entry_trace;
               l = rld::find_replace (l, "@FUNC_NAME@", '"' + sig.name + '"');
+              l = rld::find_replace (l, "@FUNC_INDEX@", lss.str ());
               l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
               c.write_line(l);
@@ -824,4 +1054,5 @@
               std::string l = ' ' + generator_.exit_trace;
               l = rld::find_replace (l, "@FUNC_NAME@", '"' + sig.name + '"');
+              l = rld::find_replace (l, "@FUNC_INDEX@", lss.str ());
               l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
               c.write_line(l);
@@ -844,5 +1075,60 @@
         if (!found)
           throw rld::error ("not found", "trace function: " + trace);
-      }
+
+        ++count;
+      }
+    }
+
+    void
+    tracer::generate_bitmap (rld::process::tempfile& c,
+                             const rld::strings&     names,
+                             const std::string&      label,
+                             const bool              global_set)
+    {
+      uint32_t bitmap_size = ((traces.size () - 1) / (4 * 8)) + 1;
+
+      std::stringstream ss;
+
+      ss << "const uint32_t __rtld_trace_" << label << "[" << bitmap_size << "] = " << std::endl
+         << "{" << std::endl;
+
+      size_t   count = 0;
+      size_t   bit = 0;
+      uint32_t bitmask = 0;
+
+      for (rld::strings::const_iterator ti = traces.begin ();
+           ti != traces.end ();
+           ++ti)
+      {
+        const std::string& trace = *ti;
+        bool               set = global_set;
+        if (!global_set)
+        {
+          for (rld::strings::const_iterator ni = names.begin ();
+               ni != names.end ();
+               ++ni)
+          {
+            const std::string& name = *ni;
+            if (trace == name)
+              set = true;
+          }
+        }
+        if (set)
+          bitmask |= 1 << bit;
+        ++bit;
+        ++count;
+        if ((bit >= 32) || (count >= traces.size ()))
+        {
+          ss << " 0x" << std::hex << std::setfill ('0') << std::setw (8) << bitmask << ',';
+          if ((count % 4) == 0)
+            ss << std::endl;
+          bit = 0;
+          bitmask = 0;
+        }
+      }
+
+      c.write_line (ss.str ());
+
+      c.write_line ("};");
     }
 
@@ -880,6 +1166,7 @@
 
     void
-    linker::load_config (const std::string& path,
-                         const std::string& trace)
+    linker::load_config (const std::string& name,
+                         const std::string& trace,
+                         const std::string& path)
     {
       std::string sp = get_prefix ();
@@ -889,4 +1176,7 @@
       rld::path::path_join (sp, "trace-linker", sp);
 
+      if (!path.empty ())
+        sp = path + ':' + sp;
+
       if (rld::verbose ())
         std::cout << "search path: " << sp << std::endl;
@@ -894,5 +1184,5 @@
       config.set_search_path (sp);
       config.clear ();
-      config.load (path);
+      config.load (name);
       tracer_.load (config, trace);
     }
@@ -1013,4 +1303,5 @@
   { "rtems-bsp",   required_argument,      NULL,           'B' },
   { "config",      required_argument,      NULL,           'C' },
+  { "path",        required_argument,      NULL,           'P' },
   { "wrapper",     required_argument,      NULL,           'W' },
   { NULL,          0,                      NULL,            0 }
@@ -1035,5 +1326,6 @@
             << " -B bsp      : RTEMS arch/bsp (also --rtems-bsp)" << std::endl
             << " -W wrapper  : wrapper file name without ext (also --wrapper)" << std::endl
-            << " -C ini      : user configuration INI file (also --config)" << std::endl;
+            << " -C ini      : user configuration INI file (also --config)" << std::endl
+            << " -P path     : user configuration file search path (also --path)" << std::endl;
   ::exit (exit_code);
 }
@@ -1087,4 +1379,5 @@
     std::string        ld_cmd;
     std::string        configuration;
+    std::string        path;
     std::string        trace = "tracer";
     std::string        wrapper;
@@ -1096,5 +1389,5 @@
     while (true)
     {
-      int opt = ::getopt_long (argc, argv, "hvwkVc:l:E:f:C:r:B:W:", rld_opts, NULL);
+      int opt = ::getopt_long (argc, argv, "hvwkVc:l:E:f:C:P:r:B:W:", rld_opts, NULL);
       if (opt < 0)
         break;
@@ -1148,4 +1441,10 @@
         case 'C':
           configuration = optarg;
+          break;
+
+        case 'P':
+          if (!path.empty ())
+            path += ":";
+          path += optarg;
           break;
 
@@ -1225,5 +1524,5 @@
     try
     {
-      linker.load_config (configuration, trace);
+      linker.load_config (configuration, trace, path);
 
       rld::process::tempfile c (".c");
Index: linkers/test-trace.ini
===================================================================
--- linkers/test-trace.ini	(revision 8531776882b69aef9db276cbf9a18fd614bda9e5)
+++ linkers/test-trace.ini	(revision 29ad92c524be36364ad2e987a3bcf16f753dd88a)
@@ -14,11 +14,11 @@
 bsp = sparc/sis
 ;
-; Options can be defined here or on the command line.
-;
-options = all-funcs, verbose
-;
 ; Functions to trace.
 ;
 traces = test-trace, test-trace-funcs, rtems-api-task
+;
+; Specify the options.
+;
+options = test-options
 ;
 ; Define the function sets. These are the function's that can be
@@ -30,4 +30,11 @@
 ;
 include = rtems.ini, rtld-base.ini
+
+;
+; Options can be defined here or on the command line.
+;
+[trace-options]
+all-funcs = true
+verbose = true
 
 ;
