diff options
Diffstat (limited to 'linkers')
-rw-r--r-- | linkers/rtems-tld.cpp | 411 | ||||
-rw-r--r-- | linkers/test-trace.ini | 15 |
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] |