From 13ee8dc9506807fd3fb253b52583611754cb719e Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 4 Aug 2014 15:09:39 +1000 Subject: rtems-tld: Add generator loading support. --- rld-config.cpp | 33 +++++++++++++++++++---- rld-config.h | 11 ++++++++ rld.h | 46 ++++++++++++++++++++++++-------- rtems-tld.cpp | 83 +++++++++++++++++++++++++++++++++++++++++++++++++--------- rtld-base.ini | 36 +++++++++++++++++++++++++ test-trace.ini | 3 ++- 6 files changed, 183 insertions(+), 29 deletions(-) create mode 100644 rtld-base.ini diff --git a/rld-config.cpp b/rld-config.cpp index b197e5d..af85f94 100644 --- a/rld-config.cpp +++ b/rld-config.cpp @@ -56,6 +56,28 @@ namespace rld throw error ("not found", "config record: " + this->name + '/' + name); } + std::string + section::get_record_item (const std::string& rec_name) const + { + const record& rec = get_record (rec_name); + if (rec.items.size () != 1) + throw rld::error ("duplicate", "record item: " + name + '/' + rec_name); + return rec.items[0].text; + } + + void + section::get_record_items (const std::string& rec_name, rld::strings& items) const + { + const record& rec = get_record (rec_name); + items.clear (); + for (rld::config::items::const_iterator ii = rec.items.begin (); + ii != rec.items.end (); + ++ii) + { + items.push_back ((*ii).text); + } + } + config::config() { } @@ -134,7 +156,8 @@ namespace rld try { - const rld::config::record& rec = sec.get_record ("include"); + rld::strings is; + parse_items (sec, "include", is); have_includes = true; @@ -147,11 +170,11 @@ namespace rld * APIs. */ - for (rld::config::items::const_iterator ri = rec.items.begin (); - ri != rec.items.end (); - ++ri) + for (rld::strings::const_iterator isi = is.begin (); + isi != is.end (); + ++isi) { - load ((*ri).text); + load (*isi); } } catch (rld::error re) diff --git a/rld-config.h b/rld-config.h index eb6d614..adf3a9e 100644 --- a/rld-config.h +++ b/rld-config.h @@ -90,6 +90,17 @@ namespace rld * Find a record and throw an error if not found. */ const record& get_record (const std::string& name) const; + + /** + * Return the single item in a record. If the record is duplicated an + * error is thrown. + */ + std::string get_record_item (const std::string& name) const; + + /** + * Return the list of items in a record in a strings container. + */ + void get_record_items (const std::string& name, rld::strings& items) const; }; /** diff --git a/rld.h b/rld.h index 70a6913..726a8e1 100644 --- a/rld.h +++ b/rld.h @@ -149,6 +149,37 @@ namespace rld return ltrim (rtrim (s)); } + /** + * Dequote a string. + */ + inline std::string dequote (const std::string& s) + { + if ((s.front () == '"') || (s.front () == '\'')) + { + if (s.front () != s.back ()) + throw rld::error ("invalid quoting", "string: " + s); + return s.substr (1, s.length () - (1 + 1)); + } + return s; + } + + /** + * Find and replace. + */ + inline std::string find_replace(const std::string& sin, + const std::string& out, + const std::string& in) + { + std::string s = sin; + size_t pos = 0; + while ((pos = s.find (out, pos)) != std::string::npos) + { + s.replace (pos, out.length (), in); + pos += in.length (); + } + return s; + } + /** * Split the string in a contain of strings based on the the * delimiter. Optionally trim any white space or include empty string. @@ -170,14 +201,7 @@ namespace rld if (strip_whitespace) trim (e); if (strip_quotes) - { - if ((e.front () == '"') || (e.front () == '\'')) - { - if (e.front () != e.back ()) - throw rld::error ("invalid quoting", "string: " + s); - e = e.substr (1, e.length () - (1 + 1)); - } - } + e = dequote (e); if (empty || !e.empty ()) { se.push_back (e); @@ -189,10 +213,10 @@ namespace rld /** * Join the strings together with the separator. */ - inline std::string& join (const strings& ss, - const std::string& separator, - std::string& s) + inline std::string join (const strings& ss, + const std::string& separator) { + std::string s; for (strings::const_iterator ssi = ss.begin (); ssi != ss.end (); ++ssi) diff --git a/rtems-tld.cpp b/rtems-tld.cpp index ede5d10..8765dca 100644 --- a/rtems-tld.cpp +++ b/rtems-tld.cpp @@ -109,10 +109,14 @@ namespace rld */ 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. */ + std::string name; /**< The name of this wrapper. */ + rld::strings headers; /**< Include statements. */ + rld::strings defines; /**< Define statements. */ + std::string map_sym_prefix; /**< Mapping symbol prefix. */ + std::string arg_trace; /**< Code template to trace an argument. */ + std::string ret_trace; /**< Code template to trace the return value. */ + std::string code; /**< Code block inserted before the trace code. */ + function_sigs sigs; /**< The functions this wrapper wraps. */ /** * Load the wrapper. @@ -120,6 +124,12 @@ namespace rld wrapper (const std::string& name, rld::config::config& config); + /** + * Parse the generator. + */ + void parse_generator (rld::config::config& config, + const rld::config::section& section); + /** * Recursive parser for strings. */ @@ -162,10 +172,10 @@ namespace rld private: - 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. */ + 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. */ }; /** @@ -262,9 +272,13 @@ namespace rld /* * 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. + * # trace A list of functions to trace. + * # generator The name of the generator section. Defaults if not present. + * # 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. + * # signatures A list of section names of function signatures. * * @note The quoting and list spliting is a little weak because a delimiter * in a quote should not be seen as a delimiter. @@ -274,6 +288,8 @@ namespace rld parse (config, section, "headers", "header", headers); parse (config, section, "defines", "define", defines); + parse_generator (config, section); + rld::strings sig_list; rld::config::parse_items (section, "signatures", sig_list); @@ -293,6 +309,44 @@ namespace rld } } + void + wrapper::parse_generator (rld::config::config& config, + const rld::config::section& section) + { + const rld::config::record* rec = 0; + try + { + const rld::config::record& record = section.get_record ("generator"); + rec = &record; + } + catch (rld::error re) + { + /* + * No error, continue. + */ + } + + std::string gen_section; + + if (rec) + { + if (!rec->single ()) + throw rld::error ("duplicate", "generator: " + section.name + "/generator"); + gen_section = rec->items[0].text; + } + else + { + gen_section = config.get_section ("default-generator").get_record_item ("generator"); + } + + const rld::config::section& sec = config.get_section (gen_section); + + map_sym_prefix = sec.get_record_item ("map-sym-prefix"); + arg_trace = rld::dequote (sec.get_record_item ("arg-trace")); + ret_trace = rld::dequote (sec.get_record_item ("ret-trace")); + code = rld::dequote (sec.get_record_item ("code")); + } + void wrapper::parse (rld::config::config& config, const rld::config::section& section, @@ -337,7 +391,12 @@ namespace rld { out << " " << (*di) << std::endl; } - out << " Function Signatures: " << sigs.size () << std::endl; + out << " Mapping Symbol Prefix: " << map_sym_prefix << std::endl + << " Arg Trace Code: " << arg_trace << std::endl + << " Return Trace Code: " << ret_trace << std::endl + << " Code: | " + << rld::find_replace (code, "\n", "\n | ") << std::endl + << " Function Signatures: " << sigs.size () << std::endl; for (function_sigs::const_iterator si = sigs.begin (); si != sigs.end (); ++si) diff --git a/rtld-base.ini b/rtld-base.ini new file mode 100644 index 0000000..1ffc17e --- /dev/null +++ b/rtld-base.ini @@ -0,0 +1,36 @@ +; +; RTEMS Trace Linker Base configuration. +; +; Copyright 2014 Chris Johns +; + +; +; The default generartor is used if a wrapper does provide a generator record. +; +[default-generator] +generator = printf-generator + +; +; A printf generator prints to stdout the trace functions. +; +[printf-generator] +map-sym-prefix = rtld_pg__ +headers = printf-generator-headers +arg-trace = "rtld_pg_print_arg(@ARG_NUM@, @ARG_TYPE@, @ARG_SIZE@, &@ARG_LABEL@);" +ret-trace = "rtld_pg_print_ret(@RET_TYPE@, @RETG_SIZE@, &@RET_LABEL@);" +code = <<