source: rtems-tools/linkers/rtems-tld.cpp @ 29ad92c

4.104.11
Last change on this file since 29ad92c was 29ad92c, checked in by Chris Johns <chrisj@…>, on Mar 23, 2015 at 6:19:01 AM

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.

  • Property mode set to 100644
File size: 43.4 KB
Line 
1/*
2 * Copyright (c) 2014-2015, Chris Johns <chrisj@rtems.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16/**
17 * @file
18 *
19 * @ingroup rtems_rld
20 *
21 * @brief RTEMS Trace Linker manages creating a tracable RTEMS executable.
22 *
23 */
24
25#if HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <algorithm>
30#include <cctype>
31#include <functional>
32#include <iostream>
33#include <iomanip>
34#include <locale>
35#include <sstream>
36
37#include <cxxabi.h>
38#include <signal.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
43#include <getopt.h>
44
45#include <rld.h>
46#include <rld-cc.h>
47#include <rld-config.h>
48#include <rld-process.h>
49#include <rld-rtems.h>
50
51#ifndef HAVE_KILL
52#define kill(p,s) raise(s)
53#endif
54
55namespace rld
56{
57  /**
58   * RTEMS Trace Linker.
59   */
60  namespace trace
61  {
62    /**
63     * Dump on error user option.
64     */
65    bool dump_on_error;
66
67    /**
68     * A container of arguments.
69     */
70    typedef std::vector < std::string > function_args;
71
72    /**
73     * The return value.
74     */
75    typedef std::string function_return;
76
77    /**
78     * An option is a name and value pair. We consider options as global.
79     */
80    struct option
81    {
82      std::string name;      /**< The name of this option. */
83      std::string value;     /**< The option's value.. */
84
85      /**
86       * Load the option.
87       */
88      option (const std::string& name, const std::string& value)
89        : name (name),
90          value (value) {
91      }
92    };
93
94    /**
95     * A container of options.
96     */
97    typedef std::vector < option > options;
98
99    /**
100     * A function's signature.
101     */
102    struct signature
103    {
104      std::string     name; /**< The function's name. */
105      function_args   args; /**< The function's list of arguments. */
106      function_return ret;  /**< The fuctions return value. */
107
108      /**
109       * The default constructor.
110       */
111      signature ();
112
113      /**
114       * Construct the signature loading it from the configuration.
115       */
116      signature (const rld::config::record& record);
117
118      /**
119       * Has the signature got a return value ?
120       */
121      bool has_ret () const;
122
123      /**
124       * Has the signature got any arguments ?
125       */
126      bool has_args () const;
127
128      /**
129       * Return the function's declaration.
130       */
131      const std::string decl (const std::string& prefix = "") const;
132    };
133
134    /**
135     * A container of signatures.
136     */
137    typedef std::map < std::string, signature > signatures;
138
139    /**
140     * A function is list of function signatures headers and defines that allow
141     * a function to be wrapped.
142     */
143    struct function
144    {
145      std::string  name;        /**< The name of this wrapper. */
146      rld::strings headers;     /**< Include statements. */
147      rld::strings defines;     /**< Define statements. */
148      signatures   signatures_; /**< Signatures in this function. */
149
150      /**
151       * Load the function.
152       */
153      function (rld::config::config& config,
154                const std::string&   name);
155
156      /**
157       * Dump the function.
158       */
159      void dump (std::ostream& out) const;
160    };
161
162    /**
163     * A container of functions.
164     */
165    typedef std::vector < function > functions;
166
167    /**
168     * A generator and that contains the functions used to trace arguments and
169     * return values. It also provides the implementation of those functions.
170     */
171    struct generator
172    {
173      std::string  name;            /**< The name of this wrapper. */
174      rld::strings headers;         /**< Include statements. */
175      rld::strings defines;         /**< Define statements. */
176      std::string  entry_trace;     /**< Code template to trace the function entry. */
177      std::string  arg_trace;       /**< Code template to trace an argument. */
178      std::string  exit_trace;      /**< Code template to trace the function exit. */
179      std::string  ret_trace;       /**< Code template to trace the return value. */
180      rld::strings code;            /**< Code block inserted before the trace code. */
181
182      /**
183       * Default constructor.
184       */
185      generator ();
186
187      /**
188       * Load the generator.
189       */
190      generator (rld::config::config& config,
191                 const std::string&   name);
192
193      /**
194       * Dump the generator.
195       */
196      void dump (std::ostream& out) const;
197    };
198
199    /**
200     * Tracer.
201     */
202    class tracer
203    {
204    public:
205      tracer ();
206
207      /**
208       * Load the user's configuration.
209       */
210      void load (rld::config::config& config,
211                 const std::string&   section);
212
213      /**
214       * Process any script based options.
215       */
216      void load_options (rld::config::config&        config,
217                         const rld::config::section& section);
218
219      /**
220       * The defines for the trace.
221       */
222      void load_defines (rld::config::config&        config,
223                         const rld::config::section& section);
224
225      /**
226       * The functions for the trace.
227       */
228      void load_functions (rld::config::config&        config,
229                           const rld::config::section& section);
230
231      /**
232       * The enables for the tracer.
233       */
234      void load_enables (rld::config::config&        config,
235                         const rld::config::section& section);
236
237      /**
238       * The triggers for the tracer.
239       */
240      void load_triggers (rld::config::config&        config,
241                          const rld::config::section& section);
242
243      /**
244       * The traces for the tracer.
245       */
246      void load_traces (rld::config::config&        config,
247                        const rld::config::section& section);
248
249      /**
250       * Get option from the options section.
251       */
252      const std::string get_option (const std::string& name) const;
253
254      /**
255       * Generate the wrapper object file.
256       */
257      void generate (rld::process::tempfile& c);
258
259      /**
260       * Generate the trace names as a string table.
261       */
262      void generate_names (rld::process::tempfile& c);
263
264      /**
265       * Generate the enabled trace bitmap.
266       */
267      void generate_enables (rld::process::tempfile& c);
268
269      /**
270       * Generate the triggered trace bitmap.
271       */
272      void generate_triggers (rld::process::tempfile& c);
273
274      /**
275       * Generate the trace functions.
276       */
277      void generate_traces (rld::process::tempfile& c);
278
279      /**
280       * Generate a bitmap.
281       */
282      void generate_bitmap (rld::process::tempfile& c,
283                            const rld::strings&     names,
284                            const std::string&      label,
285                            const bool              global_set);
286
287      /**
288       * Get the traces.
289       */
290      const rld::strings& get_traces () const;
291
292      /**
293       * Dump the wrapper.
294       */
295      void dump (std::ostream& out) const;
296
297    private:
298
299      std::string  name;          /**< The name of the trace. */
300      rld::strings defines;       /**< Define statements. */
301      rld::strings enables;       /**< The default enabled functions. */
302      rld::strings triggers;      /**< The default trigger functions. */
303      rld::strings traces;        /**< The functions to trace. */
304      options      options_;      /**< The options. */
305      functions    functions_;    /**< The functions that can be traced. */
306      generator    generator_;    /**< The tracer's generator. */
307    };
308
309    /**
310     * Trace Linker.
311     */
312    class linker
313    {
314    public:
315      linker ();
316
317      /**
318       * Load the user's configuration.
319       */
320      void load_config (const std::string& name,
321                        const std::string& trace,
322                        const std::string& path);
323
324      /**
325       * Generate the C file.
326       */
327      void generate_wrapper (rld::process::tempfile& c);
328
329      /**
330       * Compile the C file.
331       */
332      void compile_wrapper (rld::process::tempfile& c,
333                            rld::process::tempfile& o);
334
335      /**
336       * Link the application.
337       */
338      void link (rld::process::tempfile& o,
339                 const std::string&      ld_cmds);
340
341      /**
342       * Dump the linker.
343       */
344      void dump (std::ostream& out) const;
345
346    private:
347
348      rld::config::config    config;     /**< User configuration. */
349      tracer                 tracer_;    /**< The tracer */
350      rld::process::tempfile c; /**< The C wrapper file */
351      rld::process::tempfile o; /**< The wrapper object file */
352    };
353
354    /**
355     * Recursive parser for strings.
356     */
357    void
358    parse (rld::config::config&        config,
359           const rld::config::section& section,
360           const std::string&          sec_name,
361           const std::string&          rec_name,
362           rld::strings&               items,
363           bool                        split = true,
364           int                         depth = 0)
365    {
366      if (depth > 32)
367        throw rld::error ("too deep", "parsing: " + sec_name + '/' + rec_name);
368
369      rld::config::parse_items (section, rec_name, items, false, false, split);
370
371      rld::strings sl;
372
373      rld::config::parse_items (section, sec_name, sl);
374
375      for (rld::strings::iterator sli = sl.begin ();
376           sli != sl.end ();
377           ++sli)
378      {
379        const rld::config::section& sec = config.get_section (*sli);
380        parse (config, sec, sec_name, rec_name, items, split, depth + 1);
381      }
382
383      /*
384       * Make the items unique.
385       */
386      rld::strings::iterator ii;
387      ii = std::unique (items.begin (), items.end ());
388      items.resize (std::distance (items.begin (), ii));
389    }
390
391    signature::signature ()
392    {
393    }
394
395    signature::signature (const rld::config::record& record)
396    {
397      /*
398       * There can only be one function signature in the configuration.
399       */
400      if (!record.single ())
401        throw rld::error ("duplicate", "signature: " + record.name);
402
403      name = record.name;
404
405      /*
406       * Signatures are defined as the return value then the arguments
407       * delimited by a comma and white space. No checking is made of the
408       * return value or arguments.
409       */
410      rld::strings si;
411      rld::config::parse_items (record, si);
412
413      if (si.size () == 0)
414        throw rld::error ("no return value", "signature: " + name);
415      if (si.size () == 1)
416          throw rld::error ("no arguments", "signature: " + name);
417
418      ret = si[0];
419      args.resize (si.size () - 1);
420      std::copy (si.begin ()  + 1, si.end (), args.begin ());
421    }
422
423    bool
424    signature::has_ret () const
425    {
426      /*
427       * @todo Need to define as part of the function signature if ret
428       *       processing is required.
429       */
430      return ret != "void";
431    }
432
433    bool
434    signature::has_args () const
435    {
436      if (args.empty ())
437          return false;
438      return ((args.size() == 1) && (args[0] == "void")) ? false : true;
439    }
440
441    const std::string
442    signature::decl (const std::string& prefix) const
443    {
444      std::string ds = ret + ' ' + prefix + name + '(';
445      if (has_args ())
446      {
447        int arg = 0;
448        for (function_args::const_iterator ai = args.begin ();
449             ai != args.end ();
450             ++ai)
451        {
452          if (ai != args.begin ())
453            ds += ", ";
454          ds += (*ai) + " a" + rld::to_string (++arg);
455        }
456      }
457      else
458      {
459        ds += "void";
460      }
461      ds += ')';
462      return ds;
463    }
464
465    function::function (rld::config::config& config,
466                        const std::string&   name)
467      : name (name)
468    {
469      /*
470       * A function section optionally contain one or more records of:
471       *
472       * # headers     A list of sections containing headers or header records.
473       * # header      A list of include string that are single or double quoted.
474       * # defines     A list of sections containing defines or define record.
475       * # defines     A list of define string that are single or double quoted.
476       * # signatures  A list of section names of signatures.
477       * # includes    A list of files to include.
478       *
479       * @note The quoting and list spliting is a little weak because a delimiter
480       *       in a quote should not be seen as a delimiter.
481       */
482      const rld::config::section& section = config.get_section (name);
483
484      config.includes (section);
485
486      parse (config, section, "headers", "header", headers);
487      parse (config, section, "defines", "define", defines);
488
489      rld::strings sig_list;
490      section.get_record_items ("signatures", sig_list);
491
492      for (rld::strings::const_iterator sli = sig_list.begin ();
493           sli != sig_list.end ();
494           ++sli)
495      {
496        rld::strings sigs;
497        rld::split(sigs, *sli, ',');
498
499        for (rld::strings::const_iterator ssi = sigs.begin ();
500             ssi != sigs.end ();
501             ++ssi)
502        {
503          const rld::config::section& sig_sec = config.get_section (*ssi);
504          for (rld::config::records::const_iterator si = sig_sec.recs.begin ();
505               si != sig_sec.recs.end ();
506               ++si)
507          {
508            signature sig (*si);
509            signatures_[sig.name] = sig;
510          }
511        }
512      }
513    }
514
515    void
516    function::dump (std::ostream& out) const
517    {
518      out << "   Function: " << name << std::endl
519          << "    Headers: " << headers.size () << std::endl;
520      for (rld::strings::const_iterator hi = headers.begin ();
521           hi != headers.end ();
522           ++hi)
523      {
524        out << "     " << (*hi) << std::endl;
525      }
526      out << "   Defines: " << defines.size () << std::endl;
527      for (rld::strings::const_iterator di = defines.begin ();
528           di != defines.end ();
529           ++di)
530      {
531        out << "     " << (*di) << std::endl;
532      }
533      out << "   Signatures: " << signatures_.size () << std::endl;
534      for (signatures::const_iterator si = signatures_.begin ();
535           si != signatures_.end ();
536           ++si)
537      {
538        const signature& sig = (*si).second;
539        out << "     " << sig.name << ": " << sig.decl () << ';' << std::endl;
540      }
541    }
542
543    generator::generator ()
544    {
545    }
546
547    generator::generator (rld::config::config& config,
548                          const std::string&   name)
549      : name (name)
550    {
551      /*
552       * A generator section optionally contain one or more records of:
553       *
554       * # headers     A list of sections containing headers or header records.
555       * # header      A list of include string that are single or double quoted.
556       * # defines     A list of sections containing defines or define record.
557       * # define      A list of define string that are single or double quoted.
558       * # code-blocks A list of section names of code blocks.
559       * # includes    A list of files to include.
560       *
561       * @note The quoting and list spliting is a little weak because a delimiter
562       *       in a quote should not be seen as a delimiter.
563       */
564      const rld::config::section& section = config.get_section (name);
565
566      config.includes (section);
567
568      parse (config, section, "headers",     "header", headers);
569      parse (config, section, "defines",     "define", defines);
570      parse (config, section, "code-blocks", "code",   code, false);
571
572      if (section.has_record ("entry-trace"))
573        entry_trace = rld::dequote (section.get_record_item ("entry-trace"));
574      if (section.has_record ("arg-trace"))
575        arg_trace = rld::dequote (section.get_record_item ("arg-trace"));
576      if (section.has_record ("exit-trace"))
577        exit_trace = rld::dequote (section.get_record_item ("exit-trace"));
578      if (section.has_record ("ret-trace"))
579        ret_trace = rld::dequote (section.get_record_item ("ret-trace"));
580    }
581
582    void
583    generator::dump (std::ostream& out) const
584    {
585      out << "  Generator: " << name << std::endl
586          << "   Headers: " << headers.size () << std::endl;
587      for (rld::strings::const_iterator hi = headers.begin ();
588           hi != headers.end ();
589           ++hi)
590      {
591        out << "    " << (*hi) << std::endl;
592      }
593      out << "   Defines: " << defines.size () << std::endl;
594      for (rld::strings::const_iterator di = defines.begin ();
595           di != defines.end ();
596           ++di)
597      {
598        out << "    " << (*di) << std::endl;
599      }
600      out << "   Arg Trace Code: " << arg_trace << std::endl
601          << "   Return Trace Code: " << ret_trace << std::endl
602          << "   Code blocks: " << std::endl;
603      for (rld::strings::const_iterator ci = code.begin ();
604           ci != code.end ();
605           ++ci)
606      {
607        out << "      > "
608            << rld::find_replace (*ci, "\n", "\n      | ") << std::endl;
609      }
610    }
611
612    tracer::tracer ()
613    {
614    }
615
616    void
617    tracer::load (rld::config::config& config,
618                  const std::string&   tname)
619    {
620      /*
621       * The configuration must contain a "section" section. This is the top level
622       * configuration and may contain:
623       *
624       *  # name      The name of trace being linked.
625       *  # options   A list of option sections.
626       *  # defines   A list of sections containing defines or define record.
627       *  # define    A list of define string that are single or double quoted.
628       *  # enables   The list of sections containing enabled functions to trace.
629       *  # triggers  The list of sections containing enabled functions to trigger trace on.
630       *  # traces    The list of sections containing function lists to trace.
631       *  # functions The list of sections containing function details.
632       *  # include   The list of files to include.
633       *
634       * The following records are required:
635       *
636       *  # name
637       *  # traces
638       *  # functions
639       */
640      const rld::config::section& section = config.get_section (tname);
641
642      name = section.get_record_item ("name");
643      load_options (config, section);
644      config.includes (section);
645      load_defines (config, section);
646      load_functions (config, section);
647      load_enables (config, section);
648      load_triggers (config, section);
649      load_traces (config, section);
650    }
651
652    void
653    tracer::load_options (rld::config::config&        config,
654                          const rld::config::section& section)
655    {
656      rld::strings opts;
657      rld::config::parse_items (section, "options", opts, false, true, true);
658
659      if (rld::verbose ())
660        std::cout << "options: " << section.name << ": " << opts.size () << std::endl;
661
662      options_.clear ();
663
664      for (rld::strings::const_iterator osi = opts.begin ();
665           osi != opts.end ();
666           ++osi)
667      {
668        const rld::config::section& osec = config.get_section (*osi);
669
670        if (rld::verbose ())
671          std::cout << " options: " << osec.name
672                    << ": recs:" << osec.recs.size () << std::endl;
673
674        for (rld::config::records::const_iterator ori = osec.recs.begin ();
675             ori != osec.recs.end ();
676             ++ori)
677        {
678          const rld::config::record& opt = *ori;
679
680          if (!opt.single ())
681              throw rld::error ("mode than one option specified", "option: " + opt.name);
682
683          options_.push_back (option (opt.name, opt[0]));
684
685          if (opt.name == "dump-on-error")
686          {
687            dump_on_error = true;
688          }
689          else if (opt.name == "verbose")
690          {
691            int level = ::strtoul(opt[0].c_str (), 0, 0);
692            if (level == 0)
693              level = 1;
694            for (int l = 0; l < level; ++l)
695              rld::verbose_inc ();
696          }
697          else if (opt.name == "prefix")
698          {
699            rld::cc::set_exec_prefix (opt[0]);
700          }
701          else if (opt.name == "cc")
702          {
703            rld::cc::set_cc (opt[0]);
704          }
705          else if (opt.name == "ld")
706          {
707            rld::cc::set_ld (opt[0]);
708          }
709          else if (opt.name == "cflags")
710          {
711            rld::cc::append_flags (opt[0], rld::cc::ft_cflags);
712          }
713          else if (opt.name == "rtems-path")
714          {
715            rld::rtems::set_path(opt[0]);
716          }
717          else if (opt.name == "rtems-bsp")
718          {
719            rld::rtems::set_arch_bsp(opt[0]);
720          }
721        }
722      }
723    }
724
725    void
726    tracer::load_defines (rld::config::config&        config,
727                          const rld::config::section& section)
728    {
729      parse (config, section, "defines", "define", defines);
730    }
731
732    void
733    tracer::load_functions (rld::config::config&        config,
734                            const rld::config::section& section)
735    {
736      rld::strings fl;
737      rld::config::parse_items (section, "functions", fl, true);
738      for (rld::strings::const_iterator fli = fl.begin ();
739           fli != fl.end ();
740           ++fli)
741      {
742        functions_.push_back (function (config, *fli));
743      }
744    }
745
746    void
747    tracer::load_enables (rld::config::config&        config,
748                          const rld::config::section& section)
749    {
750      parse (config, section, "enables", "enable", enables);
751    }
752
753    void
754    tracer::load_triggers (rld::config::config&        config,
755                           const rld::config::section& section)
756    {
757      parse (config, section, "triggers", "trigger", triggers);
758    }
759
760    void
761    tracer::load_traces (rld::config::config&        config,
762                         const rld::config::section& section)
763    {
764      parse (config, section, "traces", "trace", traces);
765
766      rld::strings gens;
767      std::string  gen;
768
769      parse (config, section, "traces", "generator", gens);
770
771      if (gens.size () > 1)
772      {
773        if (dump_on_error)
774          dump (std::cout);
775        throw rld::error ("duplicate generators", "tracer: " + section.name);
776      }
777
778      if (gens.size () == 0)
779      {
780        const rld::config::section& dg_section = config.get_section ("default-generator");
781        gen = dg_section.get_record_item ("generator");
782        config.includes (dg_section);
783      }
784      else
785      {
786        gen = gens[0];
787      }
788
789      sort (traces.begin (), traces.end ());
790
791      generator_ = generator (config, gen);
792    }
793
794    const std::string
795    tracer::get_option (const std::string& name) const
796    {
797      std::string value;
798      for (options::const_iterator oi = options_.begin ();
799           oi != options_.end ();
800           ++oi)
801      {
802        const option& opt = *oi;
803        if (opt.name == name)
804        {
805          value = opt.value;
806          break;
807        }
808      }
809      return value;
810    }
811
812    void
813    tracer::generate (rld::process::tempfile& c)
814    {
815      c.open (true);
816
817      if (rld::verbose ())
818        std::cout << "wrapper C file: " << c.name () << std::endl;
819
820      try
821      {
822        c.write_line ("/*");
823        c.write_line (" * RTEMS Trace Linker Wrapper");
824        c.write_line (" *  Automatically generated.");
825        c.write_line (" */");
826
827        c.write_line ("");
828        c.write_line ("/*");
829        c.write_line (" * Tracer: " + name);
830        c.write_line (" */");
831        c.write_lines (defines);
832
833        c.write_line ("");
834        c.write_line ("/*");
835        c.write_line (" * Generator: " + generator_.name);
836        c.write_line (" */");
837        c.write_lines (generator_.defines);
838        c.write_lines (generator_.headers);
839        c.write_line ("");
840        generate_names (c);
841        generate_enables (c);
842        generate_triggers (c);
843        c.write_line ("");
844        c.write_lines (generator_.code);
845
846        generate_traces (c);
847      }
848      catch (...)
849      {
850        c.close ();
851        if (dump_on_error)
852          dump (std::cout);
853        throw;
854      }
855
856      c.close ();
857
858      if (rld::verbose (RLD_VERBOSE_DETAILS))
859      {
860        std::cout << "Generated C file:" << std::endl;
861        c.output (" ", std::cout, true);
862      }
863    }
864
865    void
866    tracer::generate_names (rld::process::tempfile& c)
867    {
868      const std::string opt = get_option ("gen-names");
869
870      if (opt == "disable")
871        return;
872
873      c.write_line ("");
874      c.write_line ("/*");
875      c.write_line (" * Names.");
876      c.write_line (" */");
877
878      std::stringstream sss;
879      sss << "const char const* __rld_trace_names[" << traces.size() << "] = " << std::endl
880          << "{";
881      c.write_line (sss.str ());
882
883      int count = 0;
884
885      for (rld::strings::const_iterator ti = traces.begin ();
886           ti != traces.end ();
887           ++ti)
888      {
889        const std::string& trace = *ti;
890        sss.str (std::string ());
891        sss << "  /* " << std::setw (3) << count << " */ \"" << trace << "\",";
892        c.write_line (sss.str ());
893        ++count;
894      }
895
896      c.write_line ("};");
897    }
898
899    void
900    tracer::generate_enables (rld::process::tempfile& c)
901    {
902      const std::string opt = get_option ("gen-enables");
903      bool              global_state = false;
904
905      if (opt == "disable")
906        return;
907
908      if (opt == "global-on")
909        global_state = true;
910
911      c.write_line ("");
912      c.write_line ("/*");
913      c.write_line (" * Enables.");
914      c.write_line (" */");
915
916      generate_bitmap (c, enables, "enables", global_state);
917    }
918
919    void
920    tracer::generate_triggers (rld::process::tempfile& c)
921    {
922      const std::string opt = get_option ("gen-triggers");
923      bool              global_state = false;
924
925      if (opt == "disable")
926        return;
927
928      if (opt == "global-on")
929        global_state = true;
930
931      c.write_line ("");
932      c.write_line ("/*");
933      c.write_line (" * Triggers.");
934      c.write_line (" */");
935
936      generate_bitmap (c, triggers, "triggers", global_state);
937
938      c.write_line ("");
939    }
940
941    void
942    tracer::generate_traces (rld::process::tempfile& c)
943    {
944      for (functions::const_iterator fi = functions_.begin ();
945           fi != functions_.end ();
946           ++fi)
947      {
948        const function& funcs = *fi;
949
950        for (rld::strings::const_iterator ti = traces.begin ();
951             ti != traces.end ();
952             ++ti)
953        {
954          const std::string&         trace = *ti;
955          signatures::const_iterator si = funcs.signatures_.find (trace);
956
957          if (si != funcs.signatures_.end ())
958          {
959            c.write_line ("");
960            c.write_line ("/*");
961            c.write_line (" * Function: " + funcs.name);
962            c.write_line (" */");
963            c.write_lines (funcs.defines);
964            c.write_lines (funcs.headers);
965            break;
966          }
967        }
968      }
969
970      c.write_line ("");
971      c.write_line ("/*");
972      c.write_line (" * Wrappers.");
973      c.write_line (" */");
974
975      size_t count = 0;
976
977      for (rld::strings::const_iterator ti = traces.begin ();
978           ti != traces.end ();
979           ++ti)
980      {
981        const std::string& trace = *ti;
982        bool               found = false;
983
984        for (functions::const_iterator fi = functions_.begin ();
985             fi != functions_.end ();
986             ++fi)
987        {
988          const function&            funcs = *fi;
989          signatures::const_iterator si = funcs.signatures_.find (trace);
990
991          if (si != funcs.signatures_.end ())
992          {
993            found = true;
994
995            const signature& sig = (*si).second;
996
997            c.write_line("");
998            c.write_line(sig.decl () + ";");
999            c.write_line(sig.decl ("__real_") + ";");
1000            c.write_line(sig.decl ("__wrap_"));
1001            c.write_line("{");
1002
1003            if (sig.has_ret ())
1004              c.write_line(" " + sig.ret + " ret;");
1005
1006            std::stringstream lss;
1007            lss << count;
1008
1009            std::string l;
1010
1011            if (!generator_.entry_trace.empty ())
1012            {
1013              std::string       l = ' ' + generator_.entry_trace;
1014              l = rld::find_replace (l, "@FUNC_NAME@", '"' + sig.name + '"');
1015              l = rld::find_replace (l, "@FUNC_INDEX@", lss.str ());
1016              l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
1017              c.write_line(l);
1018            }
1019
1020            if (sig.has_args ())
1021            {
1022              for (size_t a = 0; a < sig.args.size (); ++a)
1023              {
1024                std::string l = ' ' + generator_.arg_trace;
1025                std::string n = rld::to_string ((int) (a + 1));
1026                l = rld::find_replace (l, "@ARG_NUM@", n);
1027                l = rld::find_replace (l, "@ARG_TYPE@", '"' + sig.args[a] + '"');
1028                l = rld::find_replace (l, "@ARG_SIZE@", "sizeof(" + sig.args[a] + ')');
1029                l = rld::find_replace (l, "@ARG_LABEL@", "a" + n);
1030                c.write_line(l);
1031              }
1032            }
1033
1034            l.clear ();
1035
1036            if (sig.has_ret ())
1037              l = " ret =";
1038
1039            l += " __real_" + sig.name + '(';
1040            if (sig.has_args ())
1041            {
1042              for (size_t a = 0; a < sig.args.size (); ++a)
1043              {
1044                if (a)
1045                  l += ", ";
1046                l += "a" + rld::to_string ((int) (a + 1));
1047              }
1048            }
1049            l += ");";
1050            c.write_line(l);
1051
1052            if (!generator_.exit_trace.empty ())
1053            {
1054              std::string l = ' ' + generator_.exit_trace;
1055              l = rld::find_replace (l, "@FUNC_NAME@", '"' + sig.name + '"');
1056              l = rld::find_replace (l, "@FUNC_INDEX@", lss.str ());
1057              l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
1058              c.write_line(l);
1059            }
1060
1061            if (sig.has_ret () && !generator_.ret_trace.empty ())
1062            {
1063              std::string l = ' ' + generator_.ret_trace;
1064              l = rld::find_replace (l, "@RET_TYPE@", '"' + sig.ret + '"');
1065              l = rld::find_replace (l, "@RET_SIZE@", "sizeof(" + sig.ret + ')');
1066              l = rld::find_replace (l, "@RET_LABEL@", "ret");
1067              c.write_line(l);
1068              c.write_line(" return ret;");
1069            }
1070
1071            c.write_line("}");
1072          }
1073        }
1074
1075        if (!found)
1076          throw rld::error ("not found", "trace function: " + trace);
1077
1078        ++count;
1079      }
1080    }
1081
1082    void
1083    tracer::generate_bitmap (rld::process::tempfile& c,
1084                             const rld::strings&     names,
1085                             const std::string&      label,
1086                             const bool              global_set)
1087    {
1088      uint32_t bitmap_size = ((traces.size () - 1) / (4 * 8)) + 1;
1089
1090      std::stringstream ss;
1091
1092      ss << "const uint32_t __rtld_trace_" << label << "[" << bitmap_size << "] = " << std::endl
1093         << "{" << std::endl;
1094
1095      size_t   count = 0;
1096      size_t   bit = 0;
1097      uint32_t bitmask = 0;
1098
1099      for (rld::strings::const_iterator ti = traces.begin ();
1100           ti != traces.end ();
1101           ++ti)
1102      {
1103        const std::string& trace = *ti;
1104        bool               set = global_set;
1105        if (!global_set)
1106        {
1107          for (rld::strings::const_iterator ni = names.begin ();
1108               ni != names.end ();
1109               ++ni)
1110          {
1111            const std::string& name = *ni;
1112            if (trace == name)
1113              set = true;
1114          }
1115        }
1116        if (set)
1117          bitmask |= 1 << bit;
1118        ++bit;
1119        ++count;
1120        if ((bit >= 32) || (count >= traces.size ()))
1121        {
1122          ss << " 0x" << std::hex << std::setfill ('0') << std::setw (8) << bitmask << ',';
1123          if ((count % 4) == 0)
1124            ss << std::endl;
1125          bit = 0;
1126          bitmask = 0;
1127        }
1128      }
1129
1130      c.write_line (ss.str ());
1131
1132      c.write_line ("};");
1133    }
1134
1135    const rld::strings&
1136    tracer::get_traces () const
1137    {
1138      return traces;
1139    }
1140
1141    void
1142    tracer::dump (std::ostream& out) const
1143    {
1144      out << " Tracer: " << name << std::endl
1145          << "  Traces: " << traces.size () << std::endl;
1146      for (rld::strings::const_iterator ti = traces.begin ();
1147           ti != traces.end ();
1148           ++ti)
1149      {
1150        out << "   " << (*ti) << std::endl;
1151      }
1152      out << "  Functions: " << functions_.size () << std::endl;
1153      for (functions::const_iterator fi = functions_.begin ();
1154           fi != functions_.end ();
1155           ++fi)
1156      {
1157        (*fi).dump (out);
1158      }
1159      out << "  Generator: " << std::endl;
1160      generator_.dump (out);
1161    }
1162
1163    linker::linker ()
1164    {
1165    }
1166
1167    void
1168    linker::load_config (const std::string& name,
1169                         const std::string& trace,
1170                         const std::string& path)
1171    {
1172      std::string sp = get_prefix ();
1173
1174      rld::path::path_join (sp, "share", sp);
1175      rld::path::path_join (sp, "rtems", sp);
1176      rld::path::path_join (sp, "trace-linker", sp);
1177
1178      if (!path.empty ())
1179        sp = path + ':' + sp;
1180
1181      if (rld::verbose ())
1182        std::cout << "search path: " << sp << std::endl;
1183
1184      config.set_search_path (sp);
1185      config.clear ();
1186      config.load (name);
1187      tracer_.load (config, trace);
1188    }
1189
1190    void
1191    linker::generate_wrapper (rld::process::tempfile& c)
1192    {
1193      tracer_.generate (c);
1194    }
1195
1196    void
1197    linker::compile_wrapper (rld::process::tempfile& c,
1198                             rld::process::tempfile& o)
1199    {
1200     rld::process::arg_container args;
1201
1202      if (rld::verbose ())
1203        std::cout << "wrapper O file: " << o.name () << std::endl;
1204
1205      rld::cc::make_cc_command (args);
1206      rld::cc::append_flags (rld::cc::ft_cflags, args);
1207
1208      args.push_back ("-O2");
1209      args.push_back ("-g");
1210      args.push_back ("-c");
1211      args.push_back ("-o");
1212      args.push_back (o.name ());
1213      args.push_back (c.name ());
1214
1215      rld::process::tempfile out;
1216      rld::process::tempfile err;
1217      rld::process::status   status;
1218
1219      status = rld::process::execute (rld::cc::get_cc (),
1220                                      args,
1221                                      out.name (),
1222                                      err.name ());
1223
1224      if ((status.type != rld::process::status::normal) ||
1225          (status.code != 0))
1226      {
1227        err.output (rld::cc::get_cc (), std::cout);
1228        if (dump_on_error)
1229          dump (std::cout);
1230        throw rld::error ("Compiler error", "compiling wrapper");
1231      }
1232    }
1233
1234    void
1235    linker::link (rld::process::tempfile& o,
1236                  const std::string&      ld_cmd)
1237    {
1238     rld::process::arg_container args;
1239
1240      if (rld::verbose ())
1241        std::cout << "linking: " << o.name () << std::endl;
1242
1243      std::string wrap = " -Wl,--wrap=";
1244
1245      rld::cc::make_ld_command (args);
1246
1247      rld::process::args_append (args,
1248                                 wrap + rld::join (tracer_.get_traces (), wrap));
1249      args.push_back (o.name ());
1250      rld::process::args_append (args, ld_cmd);
1251
1252      rld::process::tempfile out;
1253      rld::process::tempfile err;
1254      rld::process::status   status;
1255
1256      status = rld::process::execute (rld::cc::get_ld (),
1257                                      args,
1258                                      out.name (),
1259                                      err.name ());
1260
1261      if ((status.type != rld::process::status::normal) ||
1262          (status.code != 0))
1263      {
1264        err.output (rld::cc::get_ld (), std::cout);
1265        throw rld::error ("Linker error", "linking");
1266      }
1267      err.output (rld::cc::get_ld (), std::cout);
1268    }
1269
1270    void
1271    linker::dump (std::ostream& out) const
1272    {
1273      const rld::config::paths& cpaths = config.get_paths ();
1274      out << " Configuration Files: " << cpaths.size () << std::endl;
1275      for (rld::config::paths::const_iterator pi = cpaths.begin ();
1276           pi != cpaths.end ();
1277           ++pi)
1278      {
1279        out << "  " << (*pi) << std::endl;
1280      }
1281
1282      tracer_.dump (out);
1283    }
1284  }
1285}
1286
1287/**
1288 * RTEMS Trace Linker options. This needs to be rewritten to be like cc where
1289 * only a single '-' and long options is present. Anything after '--' is passed
1290 * to RTEMS's real linker.
1291 */
1292static struct option rld_opts[] = {
1293  { "help",        no_argument,            NULL,           'h' },
1294  { "version",     no_argument,            NULL,           'V' },
1295  { "verbose",     no_argument,            NULL,           'v' },
1296  { "warn",        no_argument,            NULL,           'w' },
1297  { "keep",        no_argument,            NULL,           'k' },
1298  { "compiler",    required_argument,      NULL,           'c' },
1299  { "linker",      required_argument,      NULL,           'l' },
1300  { "exec-prefix", required_argument,      NULL,           'E' },
1301  { "cflags",      required_argument,      NULL,           'f' },
1302  { "rtems",       required_argument,      NULL,           'r' },
1303  { "rtems-bsp",   required_argument,      NULL,           'B' },
1304  { "config",      required_argument,      NULL,           'C' },
1305  { "path",        required_argument,      NULL,           'P' },
1306  { "wrapper",     required_argument,      NULL,           'W' },
1307  { NULL,          0,                      NULL,            0 }
1308};
1309
1310void
1311usage (int exit_code)
1312{
1313  std::cout << "rtems-trace-ld [options] objects" << std::endl
1314            << "Options and arguments:" << std::endl
1315            << " -h          : help (also --help)" << std::endl
1316            << " -V          : print linker version number and exit (also --version)" << std::endl
1317            << " -v          : verbose (trace import parts), can supply multiple times" << std::endl
1318            << "               to increase verbosity (also --verbose)" << std::endl
1319            << " -w          : generate warnings (also --warn)" << std::endl
1320            << " -k          : keep temporary files (also --keep)" << std::endl
1321            << " -c compiler : target compiler is not standard (also --compiler)" << std::endl
1322            << " -l linker   : target linker is not standard (also --linker)" << std::endl
1323            << " -E prefix   : the RTEMS tool prefix (also --exec-prefix)" << std::endl
1324            << " -f cflags   : C compiler flags (also --cflags)" << std::endl
1325            << " -r path     : RTEMS path (also --rtems)" << std::endl
1326            << " -B bsp      : RTEMS arch/bsp (also --rtems-bsp)" << std::endl
1327            << " -W wrapper  : wrapper file name without ext (also --wrapper)" << std::endl
1328            << " -C ini      : user configuration INI file (also --config)" << std::endl
1329            << " -P path     : user configuration file search path (also --path)" << std::endl;
1330  ::exit (exit_code);
1331}
1332
1333static void
1334fatal_signal (int signum)
1335{
1336  signal (signum, SIG_DFL);
1337
1338  rld::process::temporaries_clean_up ();
1339
1340  /*
1341   * Get the same signal again, this time not handled, so its normal effect
1342   * occurs.
1343   */
1344  kill (getpid (), signum);
1345}
1346
1347static void
1348setup_signals (void)
1349{
1350  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
1351    signal (SIGINT, fatal_signal);
1352#ifdef SIGHUP
1353  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
1354    signal (SIGHUP, fatal_signal);
1355#endif
1356  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
1357    signal (SIGTERM, fatal_signal);
1358#ifdef SIGPIPE
1359  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
1360    signal (SIGPIPE, fatal_signal);
1361#endif
1362#ifdef SIGCHLD
1363  signal (SIGCHLD, SIG_DFL);
1364#endif
1365}
1366
1367int
1368main (int argc, char* argv[])
1369{
1370  int ec = 0;
1371
1372  setup_signals ();
1373
1374  try
1375  {
1376    rld::trace::linker linker;
1377    std::string        cc;
1378    std::string        ld;
1379    std::string        ld_cmd;
1380    std::string        configuration;
1381    std::string        path;
1382    std::string        trace = "tracer";
1383    std::string        wrapper;
1384    std::string        rtems_path;
1385    std::string        rtems_arch_bsp;
1386
1387    rld::set_cmdline (argc, argv);
1388
1389    while (true)
1390    {
1391      int opt = ::getopt_long (argc, argv, "hvwkVc:l:E:f:C:P:r:B:W:", rld_opts, NULL);
1392      if (opt < 0)
1393        break;
1394
1395      switch (opt)
1396      {
1397        case 'V':
1398          std::cout << "rtems-trace-ld (RTEMS Trace Linker) " << rld::version ()
1399                    << std::endl;
1400          ::exit (0);
1401          break;
1402
1403        case 'v':
1404          rld::verbose_inc ();
1405          break;
1406
1407        case 'w':
1408#if HAVE_WARNINGS
1409          warnings = true;
1410#endif
1411          break;
1412
1413        case 'k':
1414          rld::process::set_keep_temporary_files ();
1415          break;
1416
1417        case 'c':
1418          cc = optarg;
1419          break;
1420
1421        case 'l':
1422          ld = optarg;
1423          break;
1424
1425        case 'E':
1426          rld::cc::set_exec_prefix (optarg);
1427          break;
1428
1429        case 'f':
1430          rld::cc::append_flags (optarg, rld::cc::ft_cflags);
1431          break;
1432
1433        case 'r':
1434          rtems_path = optarg;
1435          break;
1436
1437        case 'B':
1438          rtems_arch_bsp = optarg;
1439          break;
1440
1441        case 'C':
1442          configuration = optarg;
1443          break;
1444
1445        case 'P':
1446          if (!path.empty ())
1447            path += ":";
1448          path += optarg;
1449          break;
1450
1451        case 'W':
1452          wrapper = optarg;
1453          break;
1454
1455        case '?':
1456          usage (3);
1457          break;
1458
1459        case 'h':
1460          usage (0);
1461          break;
1462      }
1463    }
1464
1465    /*
1466     * Set the program name.
1467     */
1468    rld::set_progname (argv[0]);
1469
1470    argc -= optind;
1471    argv += optind;
1472
1473    if (rld::verbose ())
1474    {
1475      std::cout << "RTEMS Trace Linker " << rld::version () << std::endl;
1476      std::cout << " " << rld::get_cmdline () << std::endl;
1477    }
1478
1479    /*
1480     * Load the arch/bsp value if provided.
1481     */
1482    if (!rtems_arch_bsp.empty ())
1483    {
1484      const std::string& prefix = rld::get_prefix ();
1485      if (rtems_path.empty () && prefix.empty ())
1486        throw rld::error ("No RTEMS path provided with arch/bsp", "options");
1487      if (!rtems_path.empty ())
1488        rld::rtems::set_path (rtems_path);
1489      else
1490        rld::rtems::set_path (prefix);
1491      rld::rtems::set_arch_bsp (rtems_arch_bsp);
1492    }
1493
1494    /**
1495     * Set the compiler and/or linker if provided.
1496     */
1497    if (!cc.empty ())
1498      rld::cc::set_cc (cc);
1499    if (!ld.empty ())
1500      rld::cc::set_ld (ld);
1501
1502    /*
1503     * Load the remaining command line arguments into the linker command line.
1504     */
1505    while (argc--)
1506    {
1507      /*
1508       * Create this value because 'ld_cmd += ' ' + *argv++' fails on clang.
1509       */
1510      std::string av = *argv++;
1511      ld_cmd += ' ' + av;
1512    }
1513    ld_cmd = rld::trim (ld_cmd);
1514
1515    /*
1516     * If there are no object files there is nothing to link.
1517     */
1518    if (ld_cmd.empty ())
1519      throw rld::error ("no trace linker options", "options");
1520
1521    /*
1522     * Perform a trace link.
1523     */
1524    try
1525    {
1526      linker.load_config (configuration, trace, path);
1527
1528      rld::process::tempfile c (".c");
1529      rld::process::tempfile o (".o");
1530
1531      if (!wrapper.empty ())
1532      {
1533        c.override (wrapper);
1534        c.keep ();
1535        o.override (wrapper);
1536        o.keep ();
1537      }
1538
1539      linker.generate_wrapper (c);
1540      linker.compile_wrapper (c, o);
1541      linker.link (o, ld_cmd);
1542
1543      if (rld::verbose ())
1544        linker.dump (std::cout);
1545    }
1546    catch (...)
1547    {
1548      throw;
1549    }
1550
1551  }
1552  catch (rld::error re)
1553  {
1554    std::cerr << "error: "
1555              << re.where << ": " << re.what
1556              << std::endl;
1557    ec = 10;
1558  }
1559  catch (std::exception e)
1560  {
1561    int   status;
1562    char* realname;
1563    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
1564    std::cerr << "error: exception: " << realname << " [";
1565    ::free (realname);
1566    const std::type_info &ti = typeid (e);
1567    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
1568    std::cerr << realname << "] " << e.what () << std::endl;
1569    ::free (realname);
1570    ec = 11;
1571  }
1572  catch (...)
1573  {
1574    /*
1575     * Helps to know if this happens.
1576     */
1577    std::cout << "error: unhandled exception" << std::endl;
1578    ec = 12;
1579  }
1580
1581  return ec;
1582}
Note: See TracBrowser for help on using the repository browser.