summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2015-03-23 17:19:01 +1100
committerChris Johns <chrisj@rtems.org>2015-03-23 17:19:01 +1100
commit29ad92c524be36364ad2e987a3bcf16f753dd88a (patch)
treef317589f7d50624047bb3a9eee66e2a939d2d5cf
parentrtemstoolkit: Add an array operator to return recs in a section. (diff)
downloadrtems-tools-29ad92c524be36364ad2e987a3bcf16f753dd88a.tar.bz2
trace-linker: Add options, names, enables, and triggers.
Move the options to a section so an option can be a single line. This gives the user the ability to localise specific configurations in a top level configuration file. Provide support for names, enables and triggers. Names is an array of names of the trace functions. The table is sorted and you can use an index to reference the trace function. There is a @FUNC_INDEX@ macro that is replaced with the trace function's index. Enables is a bitmap of default trace enabled states for all trace functions. Triggers is a bitmap of default triggers bit states for each trace function. Generators can use these bitmaps to control functionality. Currently the bitmaps are const but a generator option can be added to disable the const and allow the capture engine access to update the bitmaps.
-rw-r--r--linkers/rtems-tld.cpp411
-rw-r--r--linkers/test-trace.ini15
2 files changed, 366 insertions, 60 deletions
diff --git a/linkers/rtems-tld.cpp b/linkers/rtems-tld.cpp
index c2cc196..a3bd0cf 100644
--- a/linkers/rtems-tld.cpp
+++ b/linkers/rtems-tld.cpp
@@ -1,5 +1,5 @@
/*
- * 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
* purpose with or without fee is hereby granted, provided that the above
@@ -30,6 +30,7 @@
#include <cctype>
#include <functional>
#include <iostream>
+#include <iomanip>
#include <locale>
#include <sstream>
@@ -74,6 +75,28 @@ namespace rld
typedef std::string function_return;
/**
+ * 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.
*/
struct signature
@@ -190,31 +213,78 @@ namespace rld
/**
* Process any script based options.
*/
- void load_options (const rld::config::section& section);
+ 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 the functions for the trace.
+ * The functions for the trace.
*/
void load_functions (rld::config::config& config,
const rld::config::section& section);
/**
- * 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,
const rld::config::section& section);
/**
+ * Get option from the options section.
+ */
+ const std::string get_option (const std::string& name) const;
+
+ /**
* Generate the wrapper object file.
*/
void generate (rld::process::tempfile& c);
/**
+ * 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.
*/
void generate_traces (rld::process::tempfile& c);
/**
+ * 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.
*/
const rld::strings& get_traces () const;
@@ -227,7 +297,11 @@ namespace rld
private:
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. */
};
@@ -243,8 +317,9 @@ namespace rld
/**
* 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);
/**
* Generate the C file.
@@ -479,7 +554,7 @@ namespace rld
* # headers A list of sections containing headers or header records.
* # 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.
*
@@ -547,7 +622,11 @@ namespace rld
* configuration and may contain:
*
* # 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.
* # include The list of files to include.
@@ -561,71 +640,96 @@ namespace rld
const rld::config::section& section = config.get_section (tname);
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)
+ tracer::load_options (rld::config::config& config,
+ const rld::config::section& section)
{
- rld::strings ol;
- rld::config::parse_items (section, "options", ol, true);
+ 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 oli = ol.begin ();
- oli != ol.end ();
- ++oli)
+ for (rld::strings::const_iterator osi = opts.begin ();
+ osi != opts.end ();
+ ++osi)
{
- rld::strings opts;
- rld::split(opts, *oli, ',');
- for (rld::strings::const_iterator oi = opts.begin ();
- oi != opts.end ();
- ++oi)
+ 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);
+ }
+
+ void
tracer::load_functions (rld::config::config& config,
const rld::config::section& section)
{
@@ -640,6 +744,20 @@ namespace rld
}
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)
{
@@ -668,9 +786,29 @@ namespace rld
gen = gens[0];
}
+ 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;
+ }
+
void
tracer::generate (rld::process::tempfile& c)
{
@@ -688,11 +826,21 @@ namespace rld
c.write_line ("");
c.write_line ("/*");
+ c.write_line (" * Tracer: " + name);
+ c.write_line (" */");
+ c.write_lines (defines);
+
+ c.write_line ("");
+ c.write_line ("/*");
c.write_line (" * Generator: " + generator_.name);
c.write_line (" */");
c.write_lines (generator_.defines);
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);
generate_traces (c);
@@ -715,6 +863,82 @@ namespace rld
}
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 ("");
+ }
+
+ void
tracer::generate_traces (rld::process::tempfile& c)
{
for (functions::const_iterator fi = functions_.begin ();
@@ -748,6 +972,8 @@ namespace rld
c.write_line (" * Wrappers.");
c.write_line (" */");
+ size_t count = 0;
+
for (rld::strings::const_iterator ti = traces.begin ();
ti != traces.end ();
++ti)
@@ -777,12 +1003,16 @@ namespace rld
if (sig.has_ret ())
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);
}
@@ -823,6 +1053,7 @@ namespace rld
{
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);
}
@@ -843,7 +1074,62 @@ namespace rld
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 ("};");
}
const rld::strings&
@@ -879,8 +1165,9 @@ namespace rld
}
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 ();
@@ -888,12 +1175,15 @@ namespace rld
rld::path::path_join (sp, "rtems", sp);
rld::path::path_join (sp, "trace-linker", sp);
+ if (!path.empty ())
+ sp = path + ':' + sp;
+
if (rld::verbose ())
std::cout << "search path: " << sp << std::endl;
config.set_search_path (sp);
config.clear ();
- config.load (path);
+ config.load (name);
tracer_.load (config, trace);
}
@@ -1012,6 +1302,7 @@ static struct option rld_opts[] = {
{ "rtems", required_argument, NULL, 'r' },
{ "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 }
};
@@ -1034,7 +1325,8 @@ usage (int exit_code)
<< " -r path : RTEMS path (also --rtems)" << std::endl
<< " -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);
}
@@ -1086,6 +1378,7 @@ main (int argc, char* argv[])
std::string ld;
std::string ld_cmd;
std::string configuration;
+ std::string path;
std::string trace = "tracer";
std::string wrapper;
std::string rtems_path;
@@ -1095,7 +1388,7 @@ main (int argc, char* argv[])
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;
@@ -1149,6 +1442,12 @@ main (int argc, char* argv[])
configuration = optarg;
break;
+ case 'P':
+ if (!path.empty ())
+ path += ":";
+ path += optarg;
+ break;
+
case 'W':
wrapper = optarg;
break;
@@ -1224,7 +1523,7 @@ main (int argc, char* argv[])
*/
try
{
- linker.load_config (configuration, trace);
+ linker.load_config (configuration, trace, path);
rld::process::tempfile c (".c");
rld::process::tempfile o (".o");
diff --git a/linkers/test-trace.ini b/linkers/test-trace.ini
index a6205d2..64da320 100644
--- a/linkers/test-trace.ini
+++ b/linkers/test-trace.ini
@@ -13,14 +13,14 @@ name = RTEMS Trace Linker Test
;
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
; added to the trace lists.
;
@@ -31,6 +31,13 @@ functions = test-trace-funcs, rtems-api
include = rtems.ini, rtld-base.ini
;
+; Options can be defined here or on the command line.
+;
+[trace-options]
+all-funcs = true
+verbose = true
+
+;
; User application trace example.
;
[test-trace]