summaryrefslogtreecommitdiff
path: root/linkers/rtems-tld.cpp
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2014-08-04 09:19:55 +1000
committerChris Johns <chrisj@rtems.org>2014-08-04 09:19:55 +1000
commitb6d7f5ff2ea1db4d60e190f22a1c13a80b8819a0 (patch)
tree642bae7409295a9967b8ecd99862b5bc90f9c293 /linkers/rtems-tld.cpp
parentea299027e85c686b8f36b2564ada99803708b373 (diff)
rtems-tld: Add trace configuration support.
Extend the configuration support to provide the needed configuration required to generate the C stub support.
Diffstat (limited to 'linkers/rtems-tld.cpp')
-rw-r--r--linkers/rtems-tld.cpp485
1 files changed, 318 insertions, 167 deletions
diff --git a/linkers/rtems-tld.cpp b/linkers/rtems-tld.cpp
index edc6e55..4f17fba 100644
--- a/linkers/rtems-tld.cpp
+++ b/linkers/rtems-tld.cpp
@@ -52,226 +52,376 @@
namespace rld
{
-
/**
- * Trim from start.
+ * RTEMS Trace Linker.
*/
- inline std::string &ltrim (std::string &s)
+ namespace trace
{
- s.erase (s.begin (),
- std::find_if (s.begin (), s.end (),
- std::not1 (std::ptr_fun < int, int > (std::isspace))));
- return s;
- }
+ /**
+ * A container of arguments.
+ */
+ typedef std::vector < std::string > function_args;
- /**
- * Trim from end.
- */
- inline std::string &rtrim (std::string &s)
- {
- s.erase (std::find_if (s.rbegin (), s.rend (),
- std::not1 (std::ptr_fun < int, int > (std::isspace))).base(),
- s.end());
- return s;
- }
+ /**
+ * The return value.
+ */
+ typedef std::string function_return;
- /**
- * Trim from both ends.
- */
- inline std::string &trim (std::string &s)
- {
- return ltrim (rtrim (s));
- }
-}
+ /**
+ * A function's signature.
+ */
+ struct function_sig
+ {
+ std::string name; /**< The function's name. */
+ function_args args; /**< The function's list of arguments. */
+ function_return ret; /**< The fuctions return value. */
-/**
- * RTEMS Trace Linker.
- */
-namespace trace
-{
- /**
- * A container of arguments.
- */
- typedef std::vector < std::string > function_args;
+ /**
+ * The default constructor.
+ */
+ function_sig ();
- /**
- * The return value.
- */
- typedef std::string function_return;
+ /**
+ * Construct the signature loading it from the configuration.
+ */
+ function_sig (const rld::config::record& record);
- /**
- * A function's signature.
- */
- struct function_sig
- {
- std::string name; /**< The function's name. */
- function_args args; /**< The function's list of arguments. */
- function_return ret; /**< The fuctions return value. */
- };
+ /**
+ * Copy constructor.
+ */
+ function_sig (const function_sig& orig);
- /**
- * A container of function signatures.
- */
- typedef std::map < std::string, function_sig > function_sigs;
+ /**
+ * Return the function's declaration.
+ */
+ const std::string decl () const;
+ };
- /**
- * Trace Linker.
- */
- class linker
- {
- public:
- linker ();
+ /**
+ * A container of function signatures.
+ */
+ typedef std::map < std::string, function_sig > function_sigs;
/**
- * Load the user's configuration.
+ * Wrappers hold the data used when wrapping the code. It knows how to wrap
+ * a specific trace function. Wrapping a function requires specific defines
+ * and header files.
*/
- void load_config (const std::string& path);
+ struct wrapper
+ {
+ std::string name; /**< The name of this wrapper. */
+ rld::strings headers; /**< Include statements. */
+ rld::strings defines; /**< Define statements. */
+ function_sigs sigs; /**< The functions this wrapper wraps. */
+
+ /**
+ * Load the wrapper.
+ */
+ wrapper (const std::string& name,
+ rld::config::config& config);
+
+ /**
+ * Dump the wrapper.
+ */
+ void dump (std::ostream& out) const;
+ };
/**
- * Dump the linker status.
+ * A container of wrappers. The order is the order we wrap.
*/
- void dump (std::ostream& out);
+ typedef std::vector < wrapper > wrappers;
- private:
+ /**
+ * Tracer.
+ */
+ class tracer
+ {
+ public:
+ tracer ();
- rld::config::config config; /**< User configuration. */
- function_sigs sigs; /**< Function signatures. */
- };
+ /**
+ * Load the user's configuration.
+ */
+ void load (rld::config::config& config,
+ const std::string& section);
- linker::linker ()
- {
- }
+ /**
+ * Dump the wrapper.
+ */
+ void dump (std::ostream& out) const;
- void
- linker::load_config (const std::string& path)
- {
- config.clear ();
- config.load (path);
+ private:
- /*
- * The configuration must contain a "trace" section. This is the top level
- * configuration and must the following fields:
- *
- * # < add here >
- *
- * The 'trace" section may optionally contain a number of 'include' records
- * and these configuration files are included.
+ std::string name; /**< The name of the trace. */
+ std::string bsp; /**< The BSP we are linking to. */
+ rld::strings trace; /**< The functions to trace. */
+ wrappers wrappers; /**< Wrappers wrap trace functions. */
+ };
+
+ /**
+ * Trace Linker.
*/
+ class linker
+ {
+ public:
+ linker ();
- const rld::config::section& tsec = config.get_section ("trace");
- bool have_includes = false;
+ /**
+ * Load the user's configuration.
+ */
+ void load_config (const std::string& path,
+ const std::string& trace);
- try
+ /**
+ * Generate the C file.
+ */
+ void generate_c ();
+
+ /**
+ * Dump the linker.
+ */
+ void dump (std::ostream& out) const;
+
+ private:
+
+ rld::config::config config; /**< User configuration. */
+ tracer tracer; /**< The tracer */
+ };
+
+ function_sig::function_sig ()
{
- const rld::config::record& irec = tsec.get_record ("include");
+ }
- have_includes = true;
+ function_sig::function_sig (const rld::config::record& record)
+ {
+ /*
+ * There can only be one function signature in the configuration.
+ */
+ if (!record.single ())
+ throw rld::error ("duplicate", "function signature: " + record.name);
+
+ name = record.name;
+
+ /*
+ * Function signatures are defined as the return value then the arguments
+ * delimited by a comma and white space. No checking is made of the
+ * return value or arguments.
+ */
+ rld::strings si;
+ rld::config::parse_items (record, si);
+
+ if (si.size () == 0)
+ throw rld::error ("no return value", "function signature: " + record.name);
+ if (si.size () == 1)
+ throw rld::error ("no arguments", "function signature: " + record.name);
+
+ ret = si[0];
+ args.resize (si.size () - 1);
+ std::copy (si.begin () + 1, si.end (), args.begin ());
+ }
+
+ function_sig::function_sig (const function_sig& orig)
+ : name (orig.name),
+ args (orig.args),
+ ret (orig.ret)
+ {
+ }
+
+ const std::string
+ function_sig::decl () const
+ {
+ std::string ds = ret + ' ' + name + '(';
+ int arg = 0;
+ for (function_args::const_iterator ai = args.begin ();
+ ai != args.end ();
+ ++ai)
+ {
+ if (ai != args.begin ())
+ ds += ", ";
+ ds += (*ai) + " a" + rld::to_string (++arg);
+ }
+ ds += ')';
+
+ return ds;
+ }
+ wrapper::wrapper (const std::string& name,
+ rld::config::config& config)
+ : name (name)
+ {
/*
- * Include records are a path which we can just load.
+ * A wrapper section optionally contain one or more records of:
+ *
+ * # header A list of include string that are single or double quoted.
+ * # define A list of define string that are single or double quoted.
+ * # signature A list of section names of function signatures.
*
- * @todo Add a search path. See 'rld::files' for details. We can default
- * the search path to the install $prefix of this tool and we can
- * then provide a default set of function signatures for RTEMS
- * APIs.
+ * @note The quoting and list spliting is a little weak because a delimiter
+ * in a quote should not be seen as a delimiter.
*/
+ const rld::config::section& section = config.get_section (name);
- for (rld::config::items::const_iterator ii = irec.items.begin ();
- ii != irec.items.end ();
- ++ii)
+ rld::strings sig_list;
+
+ rld::config::parse_items (section, "header", headers);
+ rld::config::parse_items (section, "define", defines);
+ rld::config::parse_items (section, "signature", sig_list);
+
+ for (rld::strings::const_iterator sli = sig_list.begin ();
+ sli != sig_list.end ();
+ ++sli)
{
- config.load ((*ii).text);
+ const rld::config::section& sig_sec = config.get_section (*sli);
+ for (rld::config::records::const_iterator ri = sig_sec.recs.begin ();
+ ri != sig_sec.recs.end ();
+ ++ri)
+ {
+ function_sig func (*ri);
+ sigs[func.name] = func;
+ }
}
}
- catch (rld::error re)
+
+ void
+ wrapper::dump (std::ostream& out) const
+ {
+ out << " Wrapper: " << name << std::endl
+ << " Headers: " << headers.size () << std::endl;
+ for (rld::strings::const_iterator hi = headers.begin ();
+ hi != headers.end ();
+ ++hi)
+ {
+ out << " " << (*hi) << std::endl;
+ }
+ out << " Defines: " << defines.size () << std::endl;
+ for (rld::strings::const_iterator di = defines.begin ();
+ di != defines.end ();
+ ++di)
+ {
+ out << " " << (*di) << std::endl;
+ }
+ out << " Function Signatures: " << sigs.size () << std::endl;
+ for (function_sigs::const_iterator si = sigs.begin ();
+ si != sigs.end ();
+ ++si)
+ {
+ const function_sig& sig = (*si).second;
+ out << " " << sig.name << ": " << sig.decl () << ';' << std::endl;
+ }
+ }
+
+ tracer::tracer ()
+ {
+ }
+
+ void
+ tracer::load (rld::config::config& config,
+ const std::string& section)
{
/*
- * No include records, must be all inlined. If we have includes it must
- * be another error so throw it.
+ * The configuration must contain a "trace" section. This is the top level
+ * configuration and must the following fields:
+ *
+ * # name The name of trace being linked.
+ * # trace The list of sections containing functions to trace.
+ * # wrapper The list of sections containing wrapping details.
+ *
+ * The following record are optional:
+ *
+ * # bdp The BSP the executable is for. Can be supplied on the command
+ * line.
+ * # include Include the INI file.
+ *
+ * The following will throw an error is the section or records are not
+ * found.
*/
- if (have_includes)
- throw;
- }
+ rld::strings ss;
- /*
- * Get the function signatures from the configuration and load them into
- * the sig map.
- */
+ const rld::config::section& tsec = config.get_section (section);
+ const rld::config::record& nrec = tsec.get_record ("name");
+ const rld::config::record& brec = tsec.get_record ("bsp");
+ const rld::config::record& trec = tsec.get_record ("trace");
+ const rld::config::record& wrec = tsec.get_record ("wrapper");
- const rld::config::section& fssec = config.get_section ("function-signatures");
+ if (!nrec.single ())
+ throw rld::error ("duplicate", "trace names");
+ name = nrec.items[0].text;
+
+ if (!brec.single ())
+ throw rld::error ("duplicate", "trace bsp");
+ bsp = brec.items[0].text;
- for (rld::config::records::const_iterator ri = fssec.recs.begin ();
- ri != fssec.recs.end ();
- ++ri)
- {
/*
- * There can only be one function signature in the configuration.
+ * Include any files.
*/
- if ((*ri).items.size () > 1)
- throw rld::error ("duplicate", "function signature: " + (*ri).name);
+ config.includes (tsec);
- function_sig sig;
- sig.name = (*ri).name;
+ /*
+ * Load the wrappers.
+ */
+ rld::strings wi;
+ rld::config::parse_items (wrec, wi);
+ for (rld::strings::const_iterator wsi = wi.begin ();
+ wsi != wi.end ();
+ ++wsi)
+ {
+ wrappers.push_back (wrapper (*wsi, config));
+ }
/*
- * Function signatures are defined as the return value then the arguments
- * delimited by a comma and white space. No checking is made of the
- * return value or arguments.
+ * Load the trace functions.
*/
- rld::config::items::const_iterator ii = (*ri).items.begin ();
- std::stringstream ts((*ii).text);
- std::string arg;
- while (std::getline (ts, arg, ','))
+ rld::strings ti;
+ rld::config::parse_items (trec, ti);
+ for (rld::strings::const_iterator tsi = ti.begin ();
+ tsi != ti.end ();
+ ++tsi)
{
- rld::trim (arg);
- if (!arg.empty ())
- {
- if (sig.ret.empty ())
- sig.ret = arg;
- else
- sig.args.push_back(arg);
- }
+ rld::config::parse_items (config, *tsi, "trace", trace, true);
}
- if (sig.ret.empty ())
- throw rld::error ("no return value", "function signature: " + (*ri).name);
+ }
- if (sig.args.empty ())
- throw rld::error ("no arguments", "function signature: " + (*ri).name);
+ void
+ tracer::dump (std::ostream& out) const
+ {
+ out << " Tracer: " << name << std::endl
+ << " BSP: " << bsp << std::endl;
+ for (wrappers::const_iterator wi = wrappers.begin ();
+ wi != wrappers.end ();
+ ++wi)
+ {
+ (*wi).dump (out);
+ }
+ }
- sigs[sig.name] = sig;
+ linker::linker ()
+ {
}
- }
- void
- linker::dump (std::ostream& out)
- {
- const rld::config::paths& cpaths = config.get_paths ();
- out << "Configuration Files: " << cpaths.size () << std::endl;
- for (rld::config::paths::const_iterator pi = cpaths.begin ();
- pi != cpaths.end ();
- ++pi)
+ void
+ linker::load_config (const std::string& path,
+ const std::string& trace)
{
- out << " " << (*pi) << std::endl;
+ config.clear ();
+ config.load (path);
+ tracer.load (config, trace);
}
- out << std::endl
- << "Function Signatures: " << sigs.size () << std::endl;
- for (function_sigs::const_iterator si = sigs.begin ();
- si != sigs.end ();
- ++si)
+ void
+ linker::dump (std::ostream& out) const
{
- const function_sig& sig = (*si).second;
- out << " " << sig.name << ": " << sig.ret << ' ' << sig.name << '(';
- for (function_args::const_iterator fai = sig.args.begin ();
- fai != sig.args.end ();
- ++fai)
+ const rld::config::paths& cpaths = config.get_paths ();
+ out << "RTEMS Trace Linker" << std::endl
+ << " Configuration Files: " << cpaths.size () << std::endl;
+ for (rld::config::paths::const_iterator pi = cpaths.begin ();
+ pi != cpaths.end ();
+ ++pi)
{
- if (fai != sig.args.begin ())
- out << ", ";
- out << (*fai);
+ out << " " << (*pi) << std::endl;
}
- out << ");" << std::endl;
+
+ tracer.dump (out);
}
}
}
@@ -353,12 +503,13 @@ main (int argc, char* argv[])
try
{
- trace::linker linker;
- std::string ld_cmd;
- std::string configuration;
- bool exec_prefix_set = false;
+ rld::trace::linker linker;
+ std::string ld_cmd;
+ std::string configuration;
+ std::string trace = "tracer";
+ bool exec_prefix_set = false;
#if HAVE_WARNINGS
- bool warnings = false;
+ bool warnings = false;
#endif
while (true)
@@ -439,7 +590,7 @@ main (int argc, char* argv[])
*/
try
{
- linker.load_config (configuration);
+ linker.load_config (configuration, trace);
linker.dump (std::cout);
}
catch (...)