diff options
author | Chris Johns <chrisj@rtems.org> | 2014-08-04 09:19:55 +1000 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2014-08-04 09:19:55 +1000 |
commit | b6d7f5ff2ea1db4d60e190f22a1c13a80b8819a0 (patch) | |
tree | 642bae7409295a9967b8ecd99862b5bc90f9c293 /linkers/rtems-tld.cpp | |
parent | ea299027e85c686b8f36b2564ada99803708b373 (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.cpp | 485 |
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 <rim (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 (...) |